ReverseContainer.php 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Psr\Container\ContainerInterface;
  12. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  13. /**
  14. * Turns public and "container.reversible" services back to their ids.
  15. *
  16. * @author Nicolas Grekas <p@tchwork.com>
  17. */
  18. final class ReverseContainer
  19. {
  20. private $serviceContainer;
  21. private $reversibleLocator;
  22. private $tagName;
  23. private $getServiceId;
  24. public function __construct(Container $serviceContainer, ContainerInterface $reversibleLocator, string $tagName = 'container.reversible')
  25. {
  26. $this->serviceContainer = $serviceContainer;
  27. $this->reversibleLocator = $reversibleLocator;
  28. $this->tagName = $tagName;
  29. $this->getServiceId = \Closure::bind(function (object $service): ?string {
  30. return array_search($service, $this->services, true) ?: array_search($service, $this->privates, true) ?: null;
  31. }, $serviceContainer, Container::class);
  32. }
  33. /**
  34. * Returns the id of the passed object when it exists as a service.
  35. *
  36. * To be reversible, services need to be either public or be tagged with "container.reversible".
  37. */
  38. public function getId(object $service): ?string
  39. {
  40. if ($this->serviceContainer === $service) {
  41. return 'service_container';
  42. }
  43. if (null === $id = ($this->getServiceId)($service)) {
  44. return null;
  45. }
  46. if ($this->serviceContainer->has($id) || $this->reversibleLocator->has($id)) {
  47. return $id;
  48. }
  49. return null;
  50. }
  51. /**
  52. * @throws ServiceNotFoundException When the service is not reversible
  53. */
  54. public function getService(string $id): object
  55. {
  56. if ($this->serviceContainer->has($id)) {
  57. return $this->serviceContainer->get($id);
  58. }
  59. if ($this->reversibleLocator->has($id)) {
  60. return $this->reversibleLocator->get($id);
  61. }
  62. if (isset($this->serviceContainer->getRemovedIds()[$id])) {
  63. throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service is private and cannot be accessed by reference. You should either make it public, or tag it as "%s".', $id, $this->tagName));
  64. }
  65. // will throw a ServiceNotFoundException
  66. $this->serviceContainer->get($id);
  67. }
  68. }