33namespace Micro \Component \DependencyInjection ;
44
55
6+ use Micro \Component \DependencyInjection \Autowire \AutowireHelperFactory ;
7+ use Micro \Component \DependencyInjection \Autowire \AutowireHelperFactoryInterface ;
68use Micro \Component \DependencyInjection \Exception \ServiceNotRegisteredException ;
79use Micro \Component \DependencyInjection \Exception \ServiceRegistrationException ;
8- use Psr \Container \ContainerInterface ;
910use \Closure ;
11+ use Psr \Container \ContainerInterface ;
1012
11- class Container implements ContainerInterface, ContainerRegistryInterface
13+ class Container implements ContainerInterface, ContainerRegistryInterface, ContainerDecoratorInterface
1214{
1315 /**
1416 * @var array<string, object>
1517 */
1618 private array $ services ;
1719
1820 /**
19- * @var array<string, Closure>
21+ * @var array<string, Closure|string >
2022 */
2123 private array $ servicesRaw ;
2224
25+ /**
26+ * @var array<string, array<Closure, int>>
27+ */
28+ private array $ decorators = [];
29+
30+ /**
31+ * @var AutowireHelperFactoryInterface
32+ */
33+ private AutowireHelperFactoryInterface $ autowireHelperFactory ;
2334
24- public function __construct ()
35+ public function __construct (
36+ )
2537 {
38+ $ this ->autowireHelperFactory = new AutowireHelperFactory ($ this );
2639 $ this ->services = [];
2740 $ this ->servicesRaw = [];
2841 }
@@ -46,13 +59,30 @@ public function has(string $id): bool
4659 /**
4760 * {@inheritDoc}
4861 */
49- public function register (string $ id , \ Closure $ service ): void
62+ public function register (string $ id , Closure $ service ): void
5063 {
64+ if ($ this ->has ($ id )) {
65+ throw new ServiceRegistrationException (sprintf ('Service "%s" already registered ' , $ id ));
66+ }
67+
5168 $ this ->servicesRaw [$ id ] = $ service ;
5269 }
5370
71+ /**
72+ * {@inheritDoc}
73+ */
74+ public function decorate (string $ id , Closure $ service , int $ priority = 0 ): void
75+ {
76+ if (!array_key_exists ($ id , $ this ->decorators )) {
77+ $ this ->decorators [$ id ] = [];
78+ }
79+
80+ $ this ->decorators [$ id ][] = [$ service , $ priority ];
81+ }
82+
5483 /**
5584 * @param string $id
85+ *
5686 * @return object
5787 */
5888 private function lookup (string $ id ): object
@@ -61,23 +91,41 @@ private function lookup(string $id): object
6191 return $ this ->services [$ id ];
6292 }
6393
64- return $ this ->createServiceInstance ($ id );
94+ $ this ->initializeService ($ id );
95+
96+ return $ this ->services [$ id ];
6597 }
6698
6799 /**
68- * @param string $id
100+ * @param string $serviceId
69101 * @return object
70102 */
71- private function createServiceInstance (string $ id ): object
103+ protected function initializeService (string $ serviceId ): void
72104 {
73- if (empty ($ this ->servicesRaw [$ id ])) {
74- throw new ServiceNotRegisteredException ($ id );
105+ if (empty ($ this ->servicesRaw [$ serviceId ])) {
106+ throw new ServiceNotRegisteredException ($ serviceId );
75107 }
76108
77- $ raw = $ this ->servicesRaw [$ id ];
109+ $ raw = $ this ->servicesRaw [$ serviceId ];
110+
78111 $ service = $ raw ($ this );
79- $ this ->services [$ id ] = $ service ;
80112
81- return $ service ;
113+ $ this ->services [$ serviceId ] = $ service ;
114+
115+ if (!array_key_exists ($ serviceId , $ this ->decorators )) {
116+ return ;
117+ }
118+
119+ $ decorators = $ this ->decorators [$ serviceId ];
120+
121+ usort ($ decorators , function (array $ left , array $ right ): bool {
122+ return $ left [1 ] > $ right [1 ];
123+ });
124+
125+ $ helper = $ this ->autowireHelperFactory ->create ();
126+
127+ foreach ($ decorators as $ decorator ) {
128+ $ this ->services [$ serviceId ] = $ helper ->autowire ($ decorator [0 ])();
129+ }
82130 }
83131}
0 commit comments