From c97c206292808ca8921cb96d6fb46dbbec5f522a Mon Sep 17 00:00:00 2001 From: Jasper Smet Date: Sat, 24 Oct 2026 14:01:48 +0200 Subject: [PATCH 1/2] Update dependency injection docs for the built-in container Refs cakephp/cakephp#19559, cakephp/cakephp#19696, cakephp/cakephp#19716. --- docs/en/appendices/6-0-migration-guide.md | 15 +++ docs/en/development/dependency-injection.md | 123 ++++++++------------ docs/en/plugins.md | 4 +- 3 files changed, 63 insertions(+), 79 deletions(-) diff --git a/docs/en/appendices/6-0-migration-guide.md b/docs/en/appendices/6-0-migration-guide.md index 6832c801e6..e0a679ab3b 100644 --- a/docs/en/appendices/6-0-migration-guide.md +++ b/docs/en/appendices/6-0-migration-guide.md @@ -106,6 +106,21 @@ Some properties have also been renamed to better reflect their purpose. These ar argument will need to be updated to pass it as the 3rd argument instead or use named parameters. +### Dependency Injection + +- CakePHP now uses `Cake\Container\Container` by default and no longer requires + `league/container`. Remove the old `App.container = 'cake'` opt-in. To use a + custom container, set `App.container` to a class name implementing + `Cake\Container\ContainerInterface`. +- Replace `Cake\Core\Container`, `Cake\Core\ContainerInterface` and + `Cake\Core\ServiceProvider` with their `Cake\Container` equivalents. +- Auto-wiring and its resolution cache are enabled by default. Remove delegation + to `League\Container\ReflectionContainer`; use `disableAutoWiring()` and + `enableAutoWiring()` to configure the built-in resolver. See + [Auto-wiring](../development/dependency-injection#auto-wiring) for details. +- `Container::defaultToShared()`, `enableAutoWiring()` and `disableAutoWiring()` + return `static`. Update the return types of overrides accordingly. + ### Datasource - `Datasource/Paging/PaginatedInterface` now extends `IteratorAggregate` diff --git a/docs/en/development/dependency-injection.md b/docs/en/development/dependency-injection.md index eeb6bd464e..62ba15b663 100644 --- a/docs/en/development/dependency-injection.md +++ b/docs/en/development/dependency-injection.md @@ -597,9 +597,9 @@ public function services(ContainerInterface $container): void > [!NOTE] > CakePHP's dependency injection container uses [PSR-11](https://www.php-fig.org/psr/psr-11/) for compatibility with other frameworks and libraries. -In order to have services created by the container, you need to tell it which -classes it can create and how to build those classes. The -simplest definition is via a class name: +The container can auto-wire concrete classes. Define services explicitly to +configure their construction, map interfaces to implementations, or control +sharing. The simplest definition is via a class name: ```php // Add a class by its name. @@ -614,7 +614,7 @@ Your application and plugins define the services they have in the namespace App; use App\Service\BillingService; -use Cake\Core\ContainerInterface; +use Cake\Container\ContainerInterface; use Cake\Http\BaseApplication; class Application extends BaseApplication @@ -649,8 +649,9 @@ $container->add(AuditLogServiceInterface::class, function (...$args) { Factory functions will receive all the resolved dependencies for the class as arguments. -Once you've defined a class, you also need to define the dependencies it -requires. Those dependencies can be either objects or primitive values: +Class-typed constructor dependencies can be auto-wired. Define arguments +explicitly for primitive values or dependencies that cannot be resolved from +their type: ```php // Add a primitive value like a string, array or number. @@ -772,8 +773,8 @@ An example ServiceProvider would look like: ```php namespace App\ServiceProvider; -use Cake\Core\ContainerInterface; -use Cake\Core\ServiceProvider; +use Cake\Container\ContainerInterface; +use Cake\Container\ServiceProvider; // Other imports here. class BillingServiceProvider extends ServiceProvider @@ -817,7 +818,8 @@ example of a bootable service would be: ```php namespace App\ServiceProvider; -use Cake\Core\ServiceProvider; +use Cake\Container\ContainerInterface; +use Cake\Container\ServiceProvider; // Other imports here. class BillingServiceProvider extends ServiceProvider @@ -1327,70 +1329,15 @@ class ArticlesController extends AppController > - **Clarity**: Controller focuses on HTTP concerns, service handles business logic > - **Maintainability**: Complex workflows are organized into focused classes -## Auto-wiring with league/container + + -> [!WARNING] -> Auto-wiring is convenient but can impact performance. Enable caching in production environments. +## Auto-wiring -When using the default `league/container` implementation, auto-wiring is turned -off by default. To enable it: - -```php -// In src/Application.php -use League\Container\ReflectionContainer; - -public function services(ContainerInterface $container): void -{ - $container->delegate( - new ReflectionContainer(), - ); -} -``` - -While your dependencies will now be resolved automatically, this approach will -not cache resolutions which can be detrimental to performance. To enable -caching: - -```php -use League\Container\ReflectionContainer; - -$container->delegate( - // or consider using the value of Configure::read('debug') - new ReflectionContainer(true), -); -``` - -Read more about auto wiring in the [PHP League Container documentation](https://container.thephpleague.com/4.x/auto-wiring/). - -## Built-in Container - -::: info Added in version 5.4.0 -::: - -CakePHP includes its own PSR-11-compatible dependency injection container in -the `Cake\Container` namespace. The `league/container` implementation remains -the default so that existing applications continue to work unchanged. To use -the built-in container, set `App.container` to `cake` in `config/app.php`: - -```php -return [ - 'App' => [ - 'container' => 'cake', - ], -]; -``` - -CakePHP exposes the built-in container through a compatibility bridge. Continue -to type-hint `Cake\Core\ContainerInterface` in your application's `services()` -method; service definitions using `add()`, `addShared()`, `extend()`, tags, and -delegates work with either implementation. - -### Auto-wiring - -Unlike the default `league/container` implementation, the built-in container -enables auto-wiring and caches auto-wired resolutions by default. It can create -concrete classes and resolve their class-typed constructor dependencies without -an explicit service definition: +CakePHP uses its built-in PSR-11 container, `Cake\Container\Container`, by +default. Auto-wiring and caching of auto-wired resolutions are enabled. The +container can create concrete classes and resolve their class-typed constructor +dependencies without an explicit definition: ```php class OrderService @@ -1402,14 +1349,36 @@ class OrderService // Only the interface needs an explicit mapping. OrderService is auto-wired. $container->add(PaymentGateway::class, StripePaymentGateway::class); +$service = $container->get(OrderService::class); ``` Define services explicitly when a constructor needs an interface, a scalar or array value, or another value that cannot be determined from its type. Explicit -definitions also let you configure constructor arguments and control whether a -service is shared. +definitions also let you configure arguments and control whether a service is +shared. Auto-wiring caches resolved instances; this differs from explicit +definitions, which are not shared unless registered with `addShared()`. + +Use `hasDefinition()` to check for an explicit registration. `has()` also checks +delegates, including the auto-wiring resolver, so it can return true for an +unregistered concrete class. + +To disable auto-wiring, call `disableAutoWiring()` before adding any custom +delegates, as that method clears all delegates. To enable auto-wiring without +caching resolved instances: + +```php +$container->disableAutoWiring()->enableAutoWiring(false); +``` + +### Controller Actions and Commands + +Class-typed controller action arguments are resolved from explicit definitions +first, then matching passed arguments, then default parameter values. If none +applies, an instantiable concrete class can be auto-wired. Optional arguments +with a default of `null` keep that default unless a definition or passed value +is available. -When using the built-in container, do not add -`League\Container\ReflectionContainer`; auto-wiring is already enabled. The -following [auto-wiring instructions](#auto-wiring-with-leaguecontainer) apply -only when using the default `league/container` implementation. +Command constructor dependencies can also be auto-wired. Interfaces and scalar +arguments still need explicit definitions. Controller construction itself uses +explicit definitions; it does not automatically resolve arbitrary controllers +through auto-wiring. diff --git a/docs/en/plugins.md b/docs/en/plugins.md index 5b2f6df62f..bb072ba7b4 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -312,7 +312,7 @@ like: namespace ContactManager; use Cake\Core\BasePlugin; -use Cake\Core\ContainerInterface; +use Cake\Container\ContainerInterface; use Cake\Core\PluginApplicationInterface; use Cake\Console\CommandCollection; use Cake\Event\EventManagerInterface; @@ -366,7 +366,7 @@ class ContactManagerPlugin extends BasePlugin /** * Register application container services. * - * @param \Cake\Core\ContainerInterface $container The Container to update. + * @param \Cake\Container\ContainerInterface $container The Container to update. * @return void * @link https://book.cakephp.org/5/en/development/dependency-injection.html#dependency-injection */ From eb1c3063d9e9f9bdc73e3f1c9445d6664fb73ae8 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 25 Oct 2026 02:11:08 -0400 Subject: [PATCH 2/2] Update docs/en/appendices/6-0-migration-guide.md --- docs/en/appendices/6-0-migration-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/appendices/6-0-migration-guide.md b/docs/en/appendices/6-0-migration-guide.md index e0a679ab3b..c2ad47533d 100644 --- a/docs/en/appendices/6-0-migration-guide.md +++ b/docs/en/appendices/6-0-migration-guide.md @@ -109,7 +109,7 @@ Some properties have also been renamed to better reflect their purpose. These ar ### Dependency Injection - CakePHP now uses `Cake\Container\Container` by default and no longer requires - `league/container`. Remove the old `App.container = 'cake'` opt-in. To use a + `league/container`. Remove the old `App.container = 'cake'` config option. To use a custom container, set `App.container` to a class name implementing `Cake\Container\ContainerInterface`. - Replace `Cake\Core\Container`, `Cake\Core\ContainerInterface` and