From ffb4d0c9b8954be7fa9d88844af328401b6205db Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sun, 15 Nov 2020 16:13:55 +0000 Subject: [PATCH 1/3] Add before resolving callbacks --- src/Illuminate/Container/Container.php | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 98d8f0ae7900..923cd0ab45ad 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -105,6 +105,13 @@ class Container implements ArrayAccess, ContainerContract */ protected $reboundCallbacks = []; + /** + * All of the global before resolving callbacks. + * + * @var \Closure[] + */ + protected $globalBeforeResolvingCallbacks = []; + /** * All of the global resolving callbacks. * @@ -119,6 +126,13 @@ class Container implements ArrayAccess, ContainerContract */ protected $globalAfterResolvingCallbacks = []; + /** + * All of the before resolving callbacks by class type. + * + * @var array[] + */ + protected $beforeResolvingCallbacks = []; + /** * All of the resolving callbacks by class type. * @@ -667,6 +681,10 @@ protected function resolve($abstract, $parameters = [], $raiseEvents = true) { $abstract = $this->getAlias($abstract); + if ($raiseEvents) { + $this->fireBeforeResolvingCallbacks($abstract, $parameters); + } + $concrete = $this->getContextualConcrete($abstract); $needsContextualBuild = ! empty($parameters) || ! is_null($concrete); @@ -1072,6 +1090,26 @@ public function afterResolving($abstract, Closure $callback = null) } } + /** + * Fire all of the before resolving callbacks. + * + * @param string $abstract + * @param array $parameters + * @return void + */ + protected function fireBeforeResolvingCallbacks($abstract, $parameters) + { + foreach ($this->globalBeforeResolvingCallbacks as $callback) { + $callback($abstract, $parameters, $this); + } + + foreach ($this->beforeResolvingCallbacks as $type => $callback) { + if ($type === $abstract || is_subclass_of($abstract, $type)) { + $callback($abstract, $parameters, $this); + } + } + } + /** * Fire all of the resolving callbacks. * From 61b4de9bc4693470d142395fdd475c5a0178aeb1 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sun, 15 Nov 2020 16:31:39 +0000 Subject: [PATCH 2/3] Add beforeResolving method --- src/Illuminate/Container/Container.php | 45 ++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 923cd0ab45ad..9b273f367c7b 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -1050,6 +1050,26 @@ protected function unresolvablePrimitive(ReflectionParameter $parameter) throw new BindingResolutionException($message); } + /** + * Register a new before resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + */ + public function beforeResolving($abstract, Closure $callback = null) + { + if (is_string($abstract)) { + $abstract = $this->getAlias($abstract); + } + + if ($abstract instanceof Closure && is_null($callback)) { + $this->globalBeforeResolvingCallbacks[] = $abstract; + } else { + $this->beforeResolvingCallbacks[$abstract][] = $callback; + } + } + /** * Register a new resolving callback. * @@ -1097,19 +1117,32 @@ public function afterResolving($abstract, Closure $callback = null) * @param array $parameters * @return void */ - protected function fireBeforeResolvingCallbacks($abstract, $parameters) + protected function fireBeforeResolvingCallbacks($abstract, $parameters = []) { - foreach ($this->globalBeforeResolvingCallbacks as $callback) { - $callback($abstract, $parameters, $this); - } + $this->fireBeforeCallbackArray($abstract, $parameters, $this->globalBeforeResolvingCallbacks); - foreach ($this->beforeResolvingCallbacks as $type => $callback) { + foreach ($this->beforeResolvingCallbacks as $type => $callbacks) { if ($type === $abstract || is_subclass_of($abstract, $type)) { - $callback($abstract, $parameters, $this); + $this->fireBeforeCallbackArray($abstract, $parameters, $callbacks); } } } + /** + * Fire an array of callbacks with an object. + * + * @param string $abstract + * @param array $parameters + * @param array $callbacks + * @return void + */ + protected function fireBeforeCallbackArray($abstract, $parameters, array $callbacks) + { + foreach ($callbacks as $callback) { + $callback($abstract, $parameters, $this); + } + } + /** * Fire all of the resolving callbacks. * From 6e9cd675369ee3d819734a80a19241548256d703 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sun, 15 Nov 2020 16:37:38 +0000 Subject: [PATCH 3/3] Add tests --- tests/Container/ResolvingCallbackTest.php | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/Container/ResolvingCallbackTest.php b/tests/Container/ResolvingCallbackTest.php index c38eec52fa76..e8aeecb73a68 100644 --- a/tests/Container/ResolvingCallbackTest.php +++ b/tests/Container/ResolvingCallbackTest.php @@ -441,6 +441,45 @@ public function testAfterResolvingCallbacksAreCalledOnceForImplementation() $container->make(ResolvingContractStub::class); $this->assertEquals(2, $callCounter); } + + public function testBeforeResolvingCallbacksAreCalled() + { + // Given a call counter initialized to zero. + $container = new Container; + $callCounter = 0; + + // And a contract/implementation stub binding. + $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); + + // When we add a before resolving callback that increment the counter by one. + $container->beforeResolving(ResolvingContractStub::class, function () use (&$callCounter) { + $callCounter++; + }); + + // Then resolving the implementation stub increases the counter by one. + $container->make(ResolvingImplementationStub::class); + $this->assertEquals(1, $callCounter); + + // And resolving the contract stub increases the counter by one. + $container->make(ResolvingContractStub::class); + $this->assertEquals(2, $callCounter); + } + + public function testGlobalBeforeResolvingCallbacksAreCalled() + { + // Given a call counter initialized to zero. + $container = new Container; + $callCounter = 0; + + // When we add a global before resolving callback that increment that counter by one. + $container->beforeResolving(function () use (&$callCounter) { + $callCounter++; + }); + + // Then resolving anything increases the counter by one. + $container->make(ResolvingImplementationStub::class); + $this->assertEquals(1, $callCounter); + } } interface ResolvingContractStub