74dfa4362e467f9b919ec803a54bdcc0d57150f6
[friendica-addons.git/.git] / advancedcontentfilter / vendor / symfony / service-contracts / ServiceLocatorTrait.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Contracts\Service;
13
14 use Psr\Container\ContainerExceptionInterface;
15 use Psr\Container\NotFoundExceptionInterface;
16
17 // Help opcache.preload discover always-needed symbols
18 class_exists(ContainerExceptionInterface::class);
19 class_exists(NotFoundExceptionInterface::class);
20
21 /**
22  * A trait to help implement ServiceProviderInterface.
23  *
24  * @author Robin Chalas <robin.chalas@gmail.com>
25  * @author Nicolas Grekas <p@tchwork.com>
26  */
27 trait ServiceLocatorTrait
28 {
29     private $factories;
30     private $loading = [];
31     private $providedTypes;
32
33     /**
34      * @param callable[] $factories
35      */
36     public function __construct(array $factories)
37     {
38         $this->factories = $factories;
39     }
40
41     /**
42      * {@inheritdoc}
43      *
44      * @return bool
45      */
46     public function has(string $id)
47     {
48         return isset($this->factories[$id]);
49     }
50
51     /**
52      * {@inheritdoc}
53      *
54      * @return mixed
55      */
56     public function get(string $id)
57     {
58         if (!isset($this->factories[$id])) {
59             throw $this->createNotFoundException($id);
60         }
61
62         if (isset($this->loading[$id])) {
63             $ids = array_values($this->loading);
64             $ids = \array_slice($this->loading, array_search($id, $ids));
65             $ids[] = $id;
66
67             throw $this->createCircularReferenceException($id, $ids);
68         }
69
70         $this->loading[$id] = $id;
71         try {
72             return $this->factories[$id]($this);
73         } finally {
74             unset($this->loading[$id]);
75         }
76     }
77
78     /**
79      * {@inheritdoc}
80      */
81     public function getProvidedServices(): array
82     {
83         if (null === $this->providedTypes) {
84             $this->providedTypes = [];
85
86             foreach ($this->factories as $name => $factory) {
87                 if (!\is_callable($factory)) {
88                     $this->providedTypes[$name] = '?';
89                 } else {
90                     $type = (new \ReflectionFunction($factory))->getReturnType();
91
92                     $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
93                 }
94             }
95         }
96
97         return $this->providedTypes;
98     }
99
100     private function createNotFoundException(string $id): NotFoundExceptionInterface
101     {
102         if (!$alternatives = array_keys($this->factories)) {
103             $message = 'is empty...';
104         } else {
105             $last = array_pop($alternatives);
106             if ($alternatives) {
107                 $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
108             } else {
109                 $message = sprintf('only knows about the "%s" service.', $last);
110             }
111         }
112
113         if ($this->loading) {
114             $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
115         } else {
116             $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message);
117         }
118
119         return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
120         };
121     }
122
123     private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
124     {
125         return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
126         };
127     }
128 }