Browse Source

Pass the $config array to the component constructor.

This avoids having to call setConfig() and ensures initialize() is called
with the initial config.
ADmad 1 year ago
parent
commit
ab02fb6c6d

+ 35 - 1
src/Controller/ComponentRegistry.php

@@ -19,9 +19,13 @@ namespace Cake\Controller;
 use Cake\Controller\Exception\MissingComponentException;
 use Cake\Core\App;
 use Cake\Core\ContainerInterface;
+use Cake\Core\Exception\CakeException;
 use Cake\Core\ObjectRegistry;
 use Cake\Event\EventDispatcherInterface;
 use Cake\Event\EventDispatcherTrait;
+use League\Container\Argument\ArgumentResolverTrait;
+use League\Container\Exception\NotFoundException;
+use ReflectionClass;
 use RuntimeException;
 
 /**
@@ -40,6 +44,8 @@ class ComponentRegistry extends ObjectRegistry implements EventDispatcherInterfa
      */
     use EventDispatcherTrait;
 
+    use ArgumentResolverTrait;
+
     /**
      * The controller that this collection is associated with.
      *
@@ -144,9 +150,22 @@ class ComponentRegistry extends ObjectRegistry implements EventDispatcherInterfa
             return $class;
         }
         if ($this->container?->has($class)) {
+            $constructor = (new ReflectionClass($class))->getConstructor();
+
+            if ($constructor !== null) {
+                $args = $this->reflectArguments($constructor, ['config' => $config]);
+
+                try {
+                    $this->container->extend($class)
+                        ->addArguments($args);
+                } catch (NotFoundException) {
+                    $this->container->add($class)
+                        ->addArguments($args);
+                }
+            }
+
             /** @var \Cake\Controller\Component $instance */
             $instance = $this->container->get($class);
-            $instance->setConfig($config);
         } else {
             $instance = new $class($this, $config);
         }
@@ -157,4 +176,19 @@ class ComponentRegistry extends ObjectRegistry implements EventDispatcherInterfa
 
         return $instance;
     }
+
+    /**
+     * Get container instance.
+     *
+     * @return \Cake\Core\ContainerInterface
+     * @psalm-suppress OverriddenMethodAccess
+     */
+    protected function getContainer(): ContainerInterface
+    {
+        if ($this->container === null) {
+            throw new CakeException('Container not set.');
+        }
+
+        return $this->container;
+    }
 }

+ 17 - 0
tests/TestCase/Controller/ComponentRegistryTest.php

@@ -27,6 +27,8 @@ use Cake\Http\ServerRequest;
 use Cake\TestSuite\TestCase;
 use Countable;
 use Exception;
+use League\Container\ReflectionContainer;
+use TestApp\Controller\Component\ConfiguredComponent;
 use TestApp\Controller\Component\FlashAliasComponent;
 use TestPlugin\Controller\Component\OtherComponent;
 use Traversable;
@@ -104,6 +106,21 @@ class ComponentRegistryTest extends TestCase
         $this->assertSame('customFlash', $flash->getConfig('key'));
     }
 
+    public function testLoadWithContainerAutoWiring(): void
+    {
+        $controller = new Controller(new ServerRequest());
+        $container = new Container();
+        $container->delegate(new ReflectionContainer());
+        $components = new ComponentRegistry($controller, $container);
+
+        $container->add(ComponentRegistry::class, $components);
+
+        $component = $components->load(ConfiguredComponent::class, ['key' => 'customFlash']);
+
+        $this->assertInstanceOf(ConfiguredComponent::class, $component);
+        $this->assertSame(['key' => 'customFlash'], $component->configCopy);
+    }
+
     /**
      * Tests loading as an alias
      */