From 7438522b6b09533636ff5d180e779464a79c0e69 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 28 May 2021 15:35:58 +0200 Subject: [PATCH 1/4] introduce scoped instances in the container --- src/Illuminate/Container/Container.php | 52 ++++++++++++++++++- src/Illuminate/Foundation/Http/Kernel.php | 2 + src/Illuminate/Queue/QueueServiceProvider.php | 7 ++- src/Illuminate/Queue/Worker.php | 16 +++++- tests/Container/ContainerTest.php | 39 ++++++++++++++ 5 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index f7049d84cd96..faec398bd49a 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -51,6 +51,13 @@ class Container implements ArrayAccess, ContainerContract */ protected $instances = []; + /** + * The container's scoped instances. + * + * @var array + */ + protected $scopedInstances = []; + /** * The registered type aliases. * @@ -393,6 +400,36 @@ public function singletonIf($abstract, $concrete = null) } } + /** + * Register a scoped binding in the container. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scoped($abstract, $concrete = null) + { + $this->scopedInstances[] = $abstract; + + $this->singleton($abstract, $concrete); + } + + /** + * Register a scoped binding if it hasn't already been registered. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scopedIf($abstract, $concrete = null) + { + if (! $this->bound($abstract)) { + $this->scopedInstances[] = $abstract; + + $this->singleton($abstract, $concrete); + } + } + /** * "Extend" an abstract type in the container. * @@ -426,7 +463,7 @@ public function extend($abstract, Closure $closure) * @param mixed $instance * @return mixed */ - public function instance($abstract, $instance) + public function instance($abstract, $instance) { $this->removeAbstractAlias($abstract); @@ -1307,6 +1344,18 @@ public function forgetInstances() $this->instances = []; } + /** + * Clear all of the scoped instances from the container. + * + * @return void + */ + public function resetScope() + { + foreach ($this->scopedInstances as $scoped) { + unset($this->instances[$scoped]); + } + } + /** * Flush the container of all bindings and resolved instances. * @@ -1319,6 +1368,7 @@ public function flush() $this->bindings = []; $this->instances = []; $this->abstractAliases = []; + $this->scopedInstances = []; } /** diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index adb11d008175..191922a1dff3 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -104,6 +104,8 @@ public function __construct(Application $app, Router $router) */ public function handle($request) { + $this->app->resetScope(); + try { $request->enableHttpMethodParameterOverride(); diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index b87e55379579..6cf37c1a9a32 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -166,11 +166,16 @@ protected function registerWorker() return $this->app->isDownForMaintenance(); }; + $scopeResetter = function () use ($app){ + return $app->resetScope(); + }; + return new Worker( $app['queue'], $app['events'], $app[ExceptionHandler::class], - $isDownForMaintenance + $isDownForMaintenance, + $scopeResetter ); }); } diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 0ed727eef373..37ba1b20ec31 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -65,6 +65,13 @@ class Worker */ protected $isDownForMaintenance; + /** + * The callback used to reset the application scope. + * + * @var callable + */ + protected $scopeResetter; + /** * Indicates if the worker should exit. * @@ -93,17 +100,20 @@ class Worker * @param \Illuminate\Contracts\Events\Dispatcher $events * @param \Illuminate\Contracts\Debug\ExceptionHandler $exceptions * @param callable $isDownForMaintenance + * @param callable|null $scopeResetter * @return void */ public function __construct(QueueManager $manager, Dispatcher $events, ExceptionHandler $exceptions, - callable $isDownForMaintenance) + callable $isDownForMaintenance, + callable $scopeResetter = null) { $this->events = $events; $this->manager = $manager; $this->exceptions = $exceptions; $this->isDownForMaintenance = $isDownForMaintenance; + $this->scopeResetter = $scopeResetter; } /** @@ -138,6 +148,10 @@ public function daemon($connectionName, $queue, WorkerOptions $options) continue; } + if (isset($this->scopeResetter)) { + ($this->scopeResetter)(); + } + // First, we will attempt to get the next job off of the queue. We will also // register the timeout handler and reset the alarm for this job so it is // not stuck in a frozen state forever. Then, we can fire off this job. diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 5cdb0204ddd9..7f37cb209b69 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -106,6 +106,31 @@ public function testSharedClosureResolution() $this->assertSame($firstInstantiation, $secondInstantiation); } + public function testScopedClosureResolution() + { + $container = new Container; + $container->scoped('class', function () { + return new stdClass; + }); + $firstInstantiation = $container->make('class'); + $secondInstantiation = $container->make('class'); + $this->assertSame($firstInstantiation, $secondInstantiation); + } + + public function testScopedClosureResets() + { + $container = new Container; + $container->scoped('class', function () { + return new stdClass; + }); + $firstInstantiation = $container->make('class'); + + $container->resetScope(); + + $secondInstantiation = $container->make('class'); + $this->assertNotSame($firstInstantiation, $secondInstantiation); + } + public function testAutoConcreteResolution() { $container = new Container; @@ -122,6 +147,20 @@ public function testSharedConcreteResolution() $this->assertSame($var1, $var2); } + public function testScopedConcreteResolutionResets() + { + $container = new Container; + $container->scoped(ContainerConcreteStub::class); + + $var1 = $container->make(ContainerConcreteStub::class); + + $container->resetScope(); + + $var2 = $container->make(ContainerConcreteStub::class); + + $this->assertNotSame($var1, $var2); + } + public function testBindFailsLoudlyWithInvalidArgument() { $this->expectException(TypeError::class); From 48f2cbf804f75e5ae5edd5506d6df4b8b3b391b2 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 28 May 2021 15:40:42 +0200 Subject: [PATCH 2/4] fix style --- src/Illuminate/Container/Container.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index faec398bd49a..9d5fa632aec4 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -463,7 +463,7 @@ public function extend($abstract, Closure $closure) * @param mixed $instance * @return mixed */ - public function instance($abstract, $instance) + public function instance($abstract, $instance) { $this->removeAbstractAlias($abstract); From b236cc4fc2a88bf630a02f05a196e031789a1b81 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 28 May 2021 15:42:57 +0200 Subject: [PATCH 3/4] remove from kernel --- src/Illuminate/Foundation/Http/Kernel.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 191922a1dff3..adb11d008175 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -104,8 +104,6 @@ public function __construct(Application $app, Router $router) */ public function handle($request) { - $this->app->resetScope(); - try { $request->enableHttpMethodParameterOverride(); From 79a0961dc2d550ca34e8e32470a496087a577d40 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Fri, 28 May 2021 15:46:25 +0200 Subject: [PATCH 4/4] fix style --- src/Illuminate/Queue/QueueServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index 6cf37c1a9a32..e1a9a6fe4574 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -166,7 +166,7 @@ protected function registerWorker() return $this->app->isDownForMaintenance(); }; - $scopeResetter = function () use ($app){ + $scopeResetter = function () use ($app) { return $app->resetScope(); };