From 2cf879ec4e5c92868dcab19408b9c9839a4870fe Mon Sep 17 00:00:00 2001 From: Moshe Weitzman Date: Sat, 9 Mar 2024 16:54:07 -0500 Subject: [PATCH] Use Autowire in commandfiles (#5889) --- composer.json | 2 +- composer.lock | 20 ++++- docs/bootstrap.md | 3 +- docs/commands.md | 4 +- docs/dependency-injection.md | 41 +++++----- docs/generators.md | 4 +- docs/hooks.md | 2 +- docs/install.md | 2 +- docs/site-alias-manager.md | 8 +- examples/Commands/SiteAliasAlterCommands.php | 17 ++-- src/Application.php | 2 +- src/Attributes/Bootstrap.php | 2 +- src/Commands/AutowireTrait.php | 48 +++++++++++ src/Commands/DrushCommands.php | 1 - src/Commands/config/ConfigCommands.php | 53 ++++--------- src/Commands/config/ConfigExportCommands.php | 4 +- src/Commands/config/ConfigImportCommands.php | 14 ++-- src/Commands/config/ConfigPullCommands.php | 18 ++--- src/Commands/core/ArchiveRestoreCommands.php | 19 ++--- src/Commands/core/BrowseCommands.php | 16 ++-- src/Commands/core/CacheCommands.php | 52 ++++++------ src/Commands/core/CacheRebuildCommands.php | 24 +++--- src/Commands/core/CliCommands.php | 15 +--- src/Commands/core/DeployCommands.php | 17 ++-- src/Commands/core/DeployHookCommands.php | 17 ++-- src/Commands/core/DrupalCommands.php | 24 +++--- src/Commands/core/DrupalDirectoryCommands.php | 17 ++-- src/Commands/core/EditCommands.php | 5 +- src/Commands/core/EntityCommands.php | 15 +--- src/Commands/core/EntityCreateCommands.php | 15 +--- src/Commands/core/LanguageCommands.php | 21 ++--- src/Commands/core/LinkHooks.php | 14 +--- src/Commands/core/LocaleCommands.php | 25 +++--- src/Commands/core/LoginCommands.php | 17 ++-- src/Commands/core/MaintCommands.php | 13 +-- src/Commands/core/MessengerCommands.php | 13 +-- src/Commands/core/MigrateRunnerCommands.php | 25 +++--- src/Commands/core/MkCommands.php | 22 +----- src/Commands/core/PhpCommands.php | 1 + src/Commands/core/QueueCommands.php | 25 ++---- src/Commands/core/RoleCommands.php | 21 ++--- src/Commands/core/RsyncCommands.php | 17 ++-- src/Commands/core/SiteCommands.php | 17 ++-- src/Commands/core/SiteInstallCommands.php | 30 +++---- src/Commands/core/SshCommands.php | 18 ++--- src/Commands/core/StateCommands.php | 12 +-- src/Commands/core/StatusCommands.php | 4 + src/Commands/core/TwigCommands.php | 30 +++---- src/Commands/core/UpdateDBCommands.php | 17 ++-- src/Commands/core/UserCommands.php | 17 ++-- src/Commands/core/ViewsCommands.php | 18 +---- src/Commands/core/WatchdogCommands.php | 19 ++--- src/Commands/field/FieldBaseInfoCommands.php | 15 +--- .../field/FieldBaseOverrideCreateCommands.php | 16 +--- src/Commands/field/FieldCreateCommands.php | 6 +- .../field/FieldDefinitionCommands.php | 20 ++--- src/Commands/field/FieldDeleteCommands.php | 18 +---- .../field/FieldEntityReferenceHooks.php | 12 +-- src/Commands/field/FieldInfoCommands.php | 13 +-- src/Commands/field/FieldTextHooks.php | 13 +-- src/Commands/generate/ApplicationFactory.php | 2 +- src/Commands/generate/GenerateCommands.php | 6 +- .../Drush/drush-command-file.php.twig | 13 +-- src/Commands/pm/PmCommands.php | 18 +---- src/Commands/pm/ThemeCommands.php | 20 ++--- src/Commands/sql/SqlCommands.php | 6 +- src/Commands/sql/SqlSyncCommands.php | 18 ++--- src/Drush.php | 17 ++-- src/Runtime/DependencyInjection.php | 57 ++++++------- src/Runtime/ServiceManager.php | 79 +++++++++++++------ .../unish/woot/src/Commands/WootCommands.php | 3 - .../WootCommandInfoAlterer.php | 15 +--- .../Commands/WootStaticFactoryCommands.php | 6 +- .../src/Drush/Generators/ExampleGenerator.php | 17 +--- .../DrushExtensionsCommands.php | 3 + .../Commands/StaticFactoryDrushCommands.php | 19 ++--- .../Commands/TestFixtureCommands.php | 18 ++--- tests/unish/UnishTestCase.php | 3 +- 78 files changed, 537 insertions(+), 773 deletions(-) create mode 100644 src/Commands/AutowireTrait.php diff --git a/composer.json b/composer.json index 851d35ff20..e3b32fa024 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,7 @@ "squizlabs/php_codesniffer": "^3.7" }, "conflict": { - "drupal/core": "< 10.0", + "drupal/core": "< 10.1", "drupal/migrate_run": "*", "drupal/migrate_tools": "<= 5" }, diff --git a/composer.lock b/composer.lock index a974133348..17362a8ff1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c05faf9a8e6790be876aad44fe047bc0", + "content-hash": "6126537e4b679cb1fca823a38fe154f0", "packages": [ { "name": "chi-teck/drupal-code-generator", @@ -6780,12 +6780,12 @@ "version": "3.7.2", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, @@ -6830,6 +6830,20 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], "time": "2023-02-22T23:07:41+00:00" }, { diff --git a/docs/bootstrap.md b/docs/bootstrap.md index 4cdaff1d3f..ad31d0fa9e 100644 --- a/docs/bootstrap.md +++ b/docs/bootstrap.md @@ -43,7 +43,7 @@ Bootstrapping is done from a Symfony Console command hook. The different bootstr none ----------------------- -Only run Drush _preflight_, without considering Drupal at all. Any code that operates on the Drush installation, and not specifically any Drupal directory, should bootstrap to this phase. +Only run Drush _preflight_, without considering Drupal at all. Any code that operates on the Drush installation, and not specifically any Drupal directory, should bootstrap to this phase. This Attribute and value may also be used on a command _class_ when it wants to load before Drupal bootstrap is started. Commands that ship inside Drupal modules always bootstrap to full, regardless of _none_ value. root ------------------------------ @@ -68,4 +68,3 @@ Fully initialize Drupal. This is analogous to the DRUPAL\_BOOTSTRAP\_FULL bootst max --------------------- This is not an actual bootstrap phase. Commands that use the "max" bootstrap level will cause Drush to bootstrap as far as possible, and then run the command regardless of the bootstrap phase that was reached. This is useful for Drush commands that work without a bootstrapped site, but that provide additional information or capabilities in the presence of a bootstrapped site. For example, [`drush status`](commands/core_status.md) will show progressively more information the farther the site bootstraps. - diff --git a/docs/commands.md b/docs/commands.md index 46a8b5b8e1..6376b47bd5 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -2,7 +2,7 @@ !!! tip - 1. Drush 12 expects commandfiles to use a [create() method](dependency-injection.md#create-method) to inject Drupal and Drush dependencies. Prior versions used a [drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files) which is now deprecated and will be removed in Drush 13. + 1. Drush 13 expects commandfiles to use [Autowire](https://github.com/drush-ops/drush/blob/13.x/src/Commands/AutowireTrait.php) to inject Drupal and Drush dependencies. Prior versions used a [drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files) which is now deprecated and will be removed in Drush 13. 1. Drush 12 expects all commandfiles in the `/src/Drush/` directory. The `Drush` subdirectory is a new requirement. Creating a new Drush command is easy. Follow the steps below. @@ -11,7 +11,7 @@ Creating a new Drush command is easy. Follow the steps below. 2. Drush will prompt for the machine name of the module that should _own_ the file. The module selected must already exist and be enabled. Use `drush generate module` to create a new module. 3. Drush will then report that it created a commandfile. Edit as needed. 4. Use the classes for the core Drush commands at [/src/Commands](https://github.com/drush-ops/drush/tree/12.x/src/Commands) as inspiration and documentation. -5. See the [dependency injection docs](dependency-injection.md) for interfaces you can implement to gain access to Drush config, Drush site aliases, etc. Also note the [create() method](dependency-injection.md#create-method) for injecting Drupal or Drush dependencies. +5. You may [inject dependencies](dependency-injection.md) into a command instance. 6. Write PHPUnit tests based on [Drush Test Traits](https://github.com/drush-ops/drush/blob/12.x/docs/contribute/unish.md#drush-test-traits). ## Attributes or Annotations diff --git a/docs/dependency-injection.md b/docs/dependency-injection.md index 3f22573d19..cc713841ac 100644 --- a/docs/dependency-injection.md +++ b/docs/dependency-injection.md @@ -3,15 +3,22 @@ Dependency Injection Drush command files obtain references to the resources they need through a technique called _dependency injection_. When using this programing paradigm, a class by convention will never use the `new` operator to instantiate dependencies. Instead, it will store the other objects it needs in class variables, and provide a way for other code to assign an object to that variable. -create() method +!!! tip + + Drush 11 and prior required [dependency injection via a drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files). This approach is deprecated in Drush 12+ and removed in Drush 13. + +Autowire ------------------ -:octicons-tag-24: 11.6+ +:octicons-tag-24: 13 +Command files may inject Drush and Drupal services by adding the [AutowireTrait](https://github.com/drush-ops/drush/blob/13.x/src/Commands/AutowireTrait.php) to the class (example: [PmCommands](https://github.com/drush-ops/drush/blob/13.x/src/Commands/pm/PmCommands.php)). This enables your [Constructor parameter type hints determine the the injected service](https://www.drupal.org/node/3396179). When a type hint is insufficient, an [#[Autowire] Attribute](https://www.drupal.org/node/3396179) on the constructor property (with _service:_ named argument) directs AutoWireTrait to the right service (example: [LoginCommands](https://github.com/drush-ops/drush/blob/13.x/src/Commands/core/LoginCommands.php)). This Attribute is currently _required_ when injecting Drush services (not required for Drupal services). -!!! tip +If your command is not found by Drush, add the `-vvv` option for debug info about any service instantiation errors. If Autowire is still insufficient, a commandfile may implement its own `create()` method (see below). - Drush 11 and prior required [dependency injection via a drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files). This approach is deprecated in Drush 12+ and will be removed in Drush 13. +create() method +------------------ +:octicons-tag-24: 11.6+ -Drush command files can inject services by adding a create() method to the commandfile. See [creating commands](commands.md) for instructions on how to use the Drupal Code Generator to create a simple command file starter. A create() method and a constructor will look something like this: +Command files not using Autowire may inject services by adding a create() method to the commandfile. A create() method and a constructor will look something like this: ```php class WootStaticFactoryCommands extends DrushCommands { @@ -22,33 +29,27 @@ class WootStaticFactoryCommands extends DrushCommands $this->configFactory = $configFactory; } - public static function create(ContainerInterface $container, DrushContainer $drush): self + public static function create(ContainerInterface $container): self { return new static($container->get('config.factory')); } ``` -See the [Drupal Documentation](https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/services-and-dependency-injection-in-drupal-8#s-injecting-dependencies-into-controllers-forms-and-blocks) for details on how to inject Drupal services into your command file. Drush's approach mimics Drupal's blocks, forms, and controllers. - -Note that if you do not need to pull any services from the Drush container, then you may -omit the second parameter to the `create()` method. +See the [Drupal Documentation](https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/services-and-dependency-injection-in-drupal-8#s-injecting-dependencies-into-controllers-forms-and-blocks) for details on how to inject Drupal services into your command file. This approach mimics Drupal's blocks, forms, and controllers. createEarly() method ------------------ :octicons-tag-24: 12.0+ -Drush commands that need to be instantiated prior to bootstrap may do so by -utilizing the `createEarly()` static factory. This method looks and functions -exacty like the `create()` static factory, except it is only passed the Drush -container. The Drupal container is not available to command handlers that use -`createEarly()`. +!!! tip + + Drush 12 supported a createEarly() method. This is deprecated and instead put a `#[CLI\Bootstrap(DrupalBootLevels::NONE)]` Attribute on the command class and inject dependencies via the usual `__construct` with [AutowireTrait](https://github.com/drush-ops/drush/blob/13.x/src/Commands/AutowireTrait.php). Note also that Drush commands packaged with Drupal modules are not discovered + until after Drupal bootstraps, and therefore cannot use `createEarly()`. This + mechanism is only usable by PSR-4 discovered commands packaged with Composer + projects that are *not* Drupal modules. -Note also that Drush commands packaged with Drupal modules are not discovered -until after Drupal bootstraps, and therefore cannot use `createEarly()`. This -mechanism is only usable by PSR-4 discovered commands packaged with Composer -projects that are *not* Drupal modules. Inflection ----------------- A command class may implement the following interfaces. When doing so, implement the corresponding trait to satisfy the interface. - [CustomEventAwareInterface](https://github.com/consolidation/annotated-command/blob/4.x/src/Events/CustomEventAwareInterface.php): Allows command files to [define and fire custom events](hooks.md) that other command files can hook. Example: [CacheCommands](https://github.com/drush-ops/drush/blob/13.x/src/Commands/core/CacheCommands.php) -- [StdinAwareInterface](https://github.com/consolidation/annotated-command/blob/4.x/src/Input/StdinAwareInterface.php): Read from standard input. This class contains facilities to redirect stdin to instead read from a file, e.g. in response to an option or argument value. Example: [CacheCommands](https://github.com/drush-ops/drush/blob/13.x/src/Commands/core/CacheCommands.php) \ No newline at end of file +- [StdinAwareInterface](https://github.com/consolidation/annotated-command/blob/4.x/src/Input/StdinAwareInterface.php): Read from standard input. This class contains facilities to redirect stdin to instead read from a file, e.g. in response to an option or argument value. Example: [CacheCommands](https://github.com/drush-ops/drush/blob/13.x/src/Commands/core/CacheCommands.php) diff --git a/docs/generators.md b/docs/generators.md index 696c74039d..fb66c1b157 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -2,7 +2,7 @@ !!! tip - Drush 11 and prior required generators to define a [drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files). This is no longer used with Drush 12+ generators. See [create() method](dependency-injection.md#create-method) for injecting dependencies. + Drush 11 and prior required generators to define a [drush.services.yml file](https://www.drush.org/11.x/dependency-injection/#services-files). This is no longer used with Drush 12+ generators. See [docs](dependency-injection.md) for injecting dependencies. Generators jump start your coding by building all the boring boilerplate code for you. After running the [generate command](commands/generate.md), you have a guide for where to insert your custom logic. @@ -17,7 +17,7 @@ Creating a new Drush generator is easy. Follow the steps below. 2. Drush will prompt for the machine name of the module that should _own_ the files. The module selected must already exist and be enabled. Use `drush generate module` to create a new module. 3. Drush will then report that it created a generator (PHP class and twig file). Edit as needed. 4. Similar to [ExampleGenerator](https://github.com/drush-ops/drush/tree/12.x/sut/modules/unish/woot/src/Drush/Generators), implement your custom logic in the generate() method. -5. See the [dependency injection docs](dependency-injection.md) for interfaces you can implement to gain access to Drush config, Drush site aliases, etc. Also note the [create() method](dependency-injection.md#create-method) for injecting Drupal or Drush dependencies. +5. You may [inject dependencies](dependency-injection.md) from Drupal or Drush. ## Auto-discovered Generators (PSR4) diff --git a/docs/hooks.md b/docs/hooks.md index 2695b8569c..c503549b73 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -9,7 +9,7 @@ All commandfiles may implement methods that are called by Drush at various times Drush commands can define custom events that other command files can hook. You can find examples in [CacheCommands](https://github.com/drush-ops/drush/blob/12.x/src/Commands/core/CacheCommands.php) and [SanitizeCommands](https://github.com/drush-ops/drush/blob/12.x/src/Drupal/Commands/sql/SanitizeCommands.php) -First, the command must implement CustomEventAwareInterface and use CustomEventAwareTrait, as described in the [dependency injection](dependency-injection.md) documentation. +First, the command must implement CustomEventAwareInterface and use CustomEventAwareTrait, as described in the [dependency injection](dependency-injection.md#inflection) documentation. Then, the command may ask the provided hook manager to return a list of handlers with a certain attribute. In the example below, the `my-event` label is used: ```php diff --git a/docs/install.md b/docs/install.md index 6f6e97e1e8..04daddeb15 100644 --- a/docs/install.md +++ b/docs/install.md @@ -31,7 +31,7 @@ Drupal Compatibility Drush 13 8.3+ TBD - + ✓ 10.2+ Drush 12 diff --git a/docs/site-alias-manager.md b/docs/site-alias-manager.md index dea904955f..2f25a43a78 100644 --- a/docs/site-alias-manager.md +++ b/docs/site-alias-manager.md @@ -4,8 +4,12 @@ Site Alias Manager The [Site Alias Manager (SAM)](https://github.com/consolidation/site-alias/blob/4.0.1/src/SiteAliasManager.php) service is used to retrieve information about one or all of the site aliases for the current installation. - An informative example is the [browse command](https://github.com/drush-ops/drush/blob/12.x/src/Commands/core/BrowseCommands.php) -- A commandfile gets access to the SAM by implementing the SiteAliasManagerAwareInterface and *use*ing the SiteAliasManagerAwareTrait trait. Then you gain access via `$this->siteAliasManager()`. -- If an alias was used for the current request, it is available via `$this->siteAliasManager()->getself()`. +- A commandfile gets access to the SAM as follows: +```php +#[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] +private readonly SiteAliasManagerInterface $siteAliasManager +``` +- If an alias was used for the current request, it is available via `$this->siteAliasManager->getself()`. - The SAM generally deals in [SiteAlias](https://github.com/consolidation/site-alias/blob/main/src/SiteAlias.php) objects. That is how any given site alias is represented. See its methods for determining things like whether the alias points to a local host or remote host. - [Site alias docs](site-aliases.md). - [Dynamically alter site aliases](https://raw.githubusercontent.com/drush-ops/drush/11.x/examples/Commands/SiteAliasAlterCommands.php). diff --git a/examples/Commands/SiteAliasAlterCommands.php b/examples/Commands/SiteAliasAlterCommands.php index d8d73ba734..e9a7715628 100644 --- a/examples/Commands/SiteAliasAlterCommands.php +++ b/examples/Commands/SiteAliasAlterCommands.php @@ -6,29 +6,26 @@ use Consolidation\AnnotatedCommand\Hooks\HookManager; use Consolidation\SiteAlias\SiteAliasManagerInterface; use Drush\Attributes as CLI; -use League\Container\Container as DrushContainer; +use Drush\Boot\DrupalBootLevels; +use Drush\Runtime\DependencyInjection; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; /** * Load this example by using the --include option - e.g. `drush --include=/path/to/drush/examples` */ +#[CLI\Bootstrap(DrupalBootLevels::NONE)] class SiteAliasAlterCommands extends DrushCommands { + use AutowireTrait; + public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * A few example alterations to site aliases. */ diff --git a/src/Application.php b/src/Application.php index e492bedc22..ef4759d531 100644 --- a/src/Application.php +++ b/src/Application.php @@ -12,8 +12,8 @@ use Drush\Command\RemoteCommandProxy; use Drush\Config\ConfigAwareTrait; use Drush\Runtime\RedispatchHook; -use Drush\Runtime\TildeExpansionHook; use Drush\Runtime\ServiceManager; +use Drush\Runtime\TildeExpansionHook; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use Robo\Contract\ConfigAwareInterface; diff --git a/src/Attributes/Bootstrap.php b/src/Attributes/Bootstrap.php index 43e5543705..7f558c9253 100644 --- a/src/Attributes/Bootstrap.php +++ b/src/Attributes/Bootstrap.php @@ -9,7 +9,7 @@ use Drush\Boot\DrupalBootLevels; use JetBrains\PhpStorm\ExpectedValues; -#[Attribute(Attribute::TARGET_METHOD)] +#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)] class Bootstrap { /** diff --git a/src/Commands/AutowireTrait.php b/src/Commands/AutowireTrait.php new file mode 100644 index 0000000000..0e9a15df4e --- /dev/null +++ b/src/Commands/AutowireTrait.php @@ -0,0 +1,48 @@ +getParameters() as $parameter) { + $service = ltrim((string) $parameter->getType(), '?'); + foreach ($parameter->getAttributes(Autowire::class) as $attribute) { + $service = (string) $attribute->newInstance()->value; + } + + if (!$container->has($service)) { + throw new AutowiringFailedException($service, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s::_construct()", you should configure its value explicitly.', $service, $parameter->getName(), static::class)); + } + + $args[] = $container->get($service); + } + } + + return new static(...$args); + } +} diff --git a/src/Commands/DrushCommands.php b/src/Commands/DrushCommands.php index e4db22154e..348ccd1d17 100644 --- a/src/Commands/DrushCommands.php +++ b/src/Commands/DrushCommands.php @@ -24,7 +24,6 @@ use Robo\Contract\ConfigAwareInterface; use Robo\Contract\IOAwareInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Filesystem\Path; abstract class DrushCommands implements IOAwareInterface, LoggerAwareInterface, ConfigAwareInterface, ProcessManagerAwareInterface diff --git a/src/Commands/config/ConfigCommands.php b/src/Commands/config/ConfigCommands.php index 8ee9dc4550..47f0c80592 100644 --- a/src/Commands/config/ConfigCommands.php +++ b/src/Commands/config/ConfigCommands.php @@ -16,27 +16,31 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\FileStorage; use Drupal\Core\Config\ImportStorageTransformer; +use Drupal\Core\Config\StorageCacheInterface; use Drupal\Core\Config\StorageComparer; use Drupal\Core\Config\StorageInterface; +use Drupal\Core\Config\StorageManagerInterface; use Drupal\Core\Site\Settings; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exec\ExecTrait; +use Drush\Runtime\DependencyInjection; use Drush\Utils\FsUtils; use Drush\Utils\StringUtils; use JetBrains\PhpStorm\Deprecated; -use League\Container\Container; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Path; use Symfony\Component\Yaml\Parser; final class ConfigCommands extends DrushCommands implements StdinAwareInterface { + use AutowireTrait; use StdinAwareTrait; use ExecTrait; @@ -48,46 +52,22 @@ final class ConfigCommands extends DrushCommands implements StdinAwareInterface const DELETE = 'config:delete'; const STATUS = 'config:status'; - protected ?StorageInterface $configStorageExport; - - protected ?ImportStorageTransformer $importStorageTransformer; - public function getConfigFactory(): ConfigFactoryInterface { return $this->configFactory; } - protected function __construct(protected ConfigFactoryInterface $configFactory, protected StorageInterface $configStorage, protected SiteAliasManagerInterface $siteAliasManager) - { + public function __construct( + protected ConfigFactoryInterface $configFactory, + protected StorageCacheInterface $configStorage, + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] + protected SiteAliasManagerInterface $siteAliasManager, + protected StorageManagerInterface $configStorageExport, + protected ImportStorageTransformer $importStorageTransformer, + ) { parent::__construct(); } - public static function create(ContainerInterface $container, Container $drush_container): self - { - $commandHandler = new static( - $container->get('config.factory'), - $container->get('config.storage'), - $drush_container->get('site.alias.manager') - ); - - if ($container->has('config.storage.export')) { - $commandHandler->setExportStorage($container->get('config.storage.export')); - } - if ($container->has('config.import_transformer')) { - $commandHandler->setImportTransformer($container->get('config.import_transformer')); - } - - return $commandHandler; - } - - /** - * @param StorageInterface $exportStorage - */ - public function setExportStorage(StorageInterface $exportStorage): void - { - $this->configStorageExport = $exportStorage; - } - /** * @return StorageInterface */ @@ -99,11 +79,6 @@ public function getConfigStorageExport() return $this->configStorage; } - public function setImportTransformer(ImportStorageTransformer $importStorageTransformer): void - { - $this->importStorageTransformer = $importStorageTransformer; - } - public function hasImportTransformer(): bool { return isset($this->importStorageTransformer); diff --git a/src/Commands/config/ConfigExportCommands.php b/src/Commands/config/ConfigExportCommands.php index 50b2684310..07ddd3e937 100644 --- a/src/Commands/config/ConfigExportCommands.php +++ b/src/Commands/config/ConfigExportCommands.php @@ -6,16 +6,16 @@ use Consolidation\AnnotatedCommand\Hooks\HookManager; use Drupal\Core\Config\ConfigManagerInterface; -use Drupal\Core\Config\StorageComparer; use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\StorageComparer; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Site\Settings; use Drush\Attributes as CLI; use Drush\Commands\DrushCommands; use Drush\Exceptions\UserAbortException; +use Psr\Container\ContainerInterface; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Filesystem\Path; -use Symfony\Component\DependencyInjection\ContainerInterface; final class ConfigExportCommands extends DrushCommands { diff --git a/src/Commands/config/ConfigImportCommands.php b/src/Commands/config/ConfigImportCommands.php index 2d729e238d..b66f6b6485 100644 --- a/src/Commands/config/ConfigImportCommands.php +++ b/src/Commands/config/ConfigImportCommands.php @@ -4,20 +4,16 @@ namespace Drush\Commands\config; -use Consolidation\AnnotatedCommand\Hooks\HookManager; -use Drush\Boot\DrupalBootLevels; -use Drush\Commands\core\DocsCommands; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -use Drush\Attributes as CLI; -use Drupal\Core\Config\ImportStorageTransformer; use Consolidation\AnnotatedCommand\CommandData; use Consolidation\AnnotatedCommand\CommandError; +use Consolidation\AnnotatedCommand\Hooks\HookManager; use Drupal\config\StorageReplaceDataWrapper; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigException; use Drupal\Core\Config\ConfigImporter; use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\ImportStorageTransformer; use Drupal\Core\Config\StorageComparer; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\TypedConfigManagerInterface; @@ -28,10 +24,14 @@ use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Site\Settings; use Drupal\Core\StringTranslation\TranslationInterface; +use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\core\DocsCommands; use Drush\Commands\DrushCommands; use Drush\Exceptions\UserAbortException; +use Psr\Container\ContainerInterface; use Symfony\Component\Filesystem\Path; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class ConfigImportCommands extends DrushCommands { diff --git a/src/Commands/config/ConfigPullCommands.php b/src/Commands/config/ConfigPullCommands.php index afb4037545..1a536c500b 100644 --- a/src/Commands/config/ConfigPullCommands.php +++ b/src/Commands/config/ConfigPullCommands.php @@ -10,31 +10,29 @@ use Consolidation\SiteAlias\HostPath; use Consolidation\SiteAlias\SiteAliasManagerInterface; use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\core\DocsCommands; use Drush\Commands\core\RsyncCommands; use Drush\Commands\DrushCommands; use Drush\Drush; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class ConfigPullCommands extends DrushCommands { + use AutowireTrait; + const PULL = 'config:pull'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Export and transfer config from one environment to another. */ diff --git a/src/Commands/core/ArchiveRestoreCommands.php b/src/Commands/core/ArchiveRestoreCommands.php index 0482134e94..9755ba9cf2 100644 --- a/src/Commands/core/ArchiveRestoreCommands.php +++ b/src/Commands/core/ArchiveRestoreCommands.php @@ -15,19 +15,24 @@ use Drush\Backend\BackendPathEvaluator; use Drush\Boot\BootstrapManager; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Exceptions\UserAbortException; +use Drush\Runtime\DependencyInjection; use Drush\Sql\SqlBase; use Drush\Utils\FsUtils; use Exception; -use League\Container\Container as DrushContainer; use PharData; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Path; use Throwable; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class ArchiveRestoreCommands extends DrushCommands { + use AutowireTrait; + const RESTORE = 'archive:restore'; private Filesystem $filesystem; private ?string $destinationPath = null; @@ -43,22 +48,14 @@ final class ArchiveRestoreCommands extends DrushCommands private const TEMP_DIR_NAME = 'uncompressed'; public function __construct( + #[Autowire(service: DependencyInjection::BOOTSTRAP_MANAGER)] private readonly BootstrapManager $bootstrapManager, + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('bootstrap.manager'), - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Restore (import) your code, files, and database. */ diff --git a/src/Commands/core/BrowseCommands.php b/src/Commands/core/BrowseCommands.php index aee66ec372..5f06e52e0a 100644 --- a/src/Commands/core/BrowseCommands.php +++ b/src/Commands/core/BrowseCommands.php @@ -8,33 +8,27 @@ use Drupal\Core\Url; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exec\ExecTrait; -use League\Container\Container as DrushContainer; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class BrowseCommands extends DrushCommands { + use AutowireTrait; use ExecTrait; const BROWSE = 'browse'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Display a link to a given path or open link in a browser. */ diff --git a/src/Commands/core/CacheCommands.php b/src/Commands/core/CacheCommands.php index c7b950ad4d..359f7cecd7 100644 --- a/src/Commands/core/CacheCommands.php +++ b/src/Commands/core/CacheCommands.php @@ -4,29 +4,36 @@ namespace Drush\Commands\core; -use Consolidation\AnnotatedCommand\Hooks\HookManager; -use Drupal\Core\Cache\CacheTagsInvalidatorInterface; +use Composer\Autoload\ClassLoader; use Consolidation\AnnotatedCommand\CommandData; use Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface; use Consolidation\AnnotatedCommand\Events\CustomEventAwareTrait; +use Consolidation\AnnotatedCommand\Hooks\HookManager; +use Consolidation\AnnotatedCommand\Input\StdinAwareInterface; +use Consolidation\AnnotatedCommand\Input\StdinAwareTrait; use Consolidation\OutputFormatters\StructuredData\PropertyList; +use Drupal\Core\Asset\JsCollectionOptimizerLazy; +use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheTagsInvalidatorInterface; +use Drupal\Core\Plugin\CachedDiscoveryClearerInterface; +use Drupal\Core\Routing\RouteBuilderInterface; +use Drupal\Core\Theme\Registry; use Drush\Attributes as CLI; use Drush\Boot\BootstrapManager; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\Core\Cache\Cache; +use Drush\Runtime\DependencyInjection; use Drush\Utils\StringUtils; -use Consolidation\AnnotatedCommand\Input\StdinAwareInterface; -use Consolidation\AnnotatedCommand\Input\StdinAwareTrait; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Exception\IOException; -use Composer\Autoload\ClassLoader; /* * Interact with Drupal's Cache API. */ final class CacheCommands extends DrushCommands implements CustomEventAwareInterface, StdinAwareInterface { + use AutowireTrait; use CustomEventAwareTrait; use StdinAwareTrait; @@ -34,39 +41,26 @@ final class CacheCommands extends DrushCommands implements CustomEventAwareInter const TAGS = 'cache:tags'; const CLEAR = 'cache:clear'; const SET = 'cache:set'; - // @deprecated. Use CacheRebuildCommands::REBUILD - const REBUILD = 'cache:rebuild'; const EVENT_CLEAR = 'cache-clear'; public function __construct( private CacheTagsInvalidatorInterface $invalidator, - private $themeRegistry, - private $routerBuilder, - private $jsOptimizer, + private Registry $themeRegistry, + private RouteBuilderInterface $routerBuilder, + // @todo Type hints not sufficient for unknown reason. + #[Autowire(service: 'asset.js.collection_optimizer')] + private JsCollectionOptimizerLazy $jsOptimizer, + #[Autowire(service: 'asset.css.collection_optimizer')] private $cssOptimizer, - private $pluginCacheClearer, + private CachedDiscoveryClearerInterface $pluginCacheClearer, + #[Autowire(service: DependencyInjection::BOOTSTRAP_MANAGER)] private BootstrapManager $bootstrapManager, + #[Autowire(service: DependencyInjection::LOADER)] private ClassLoader $autoloader ) { parent::__construct(); } - public static function create(ContainerInterface $container, $drush_container): self - { - $commandHandler = new static( - $container->get('cache_tags.invalidator'), - $container->get('theme.registry'), - $container->get('router.builder'), - $container->get('asset.js.collection_optimizer'), - $container->get('asset.css.collection_optimizer'), - $container->get('plugin.cache_clearer'), - $drush_container->get('bootstrap.manager'), - $drush_container->get('loader') - ); - - return $commandHandler; - } - /** * Fetch a cached object and display it. */ diff --git a/src/Commands/core/CacheRebuildCommands.php b/src/Commands/core/CacheRebuildCommands.php index d1f21b5bd9..19a3b24704 100644 --- a/src/Commands/core/CacheRebuildCommands.php +++ b/src/Commands/core/CacheRebuildCommands.php @@ -5,38 +5,32 @@ namespace Drush\Commands\core; use Composer\Autoload\ClassLoader; -use Consolidation\SiteAlias\SiteAliasManager; +use Drupal\Core\DrupalKernel; +use Drupal\Core\Site\Settings; use Drush\Attributes as CLI; use Drush\Boot\BootstrapManager; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\Core\DrupalKernel; -use Drupal\Core\Site\Settings; use Drush\Drupal\DrushLoggerServiceProvider; -use Drush\Drush; -use Psr\Container\ContainerInterface as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class CacheRebuildCommands extends DrushCommands { + use AutowireTrait; + const REBUILD = 'cache:rebuild'; public function __construct( + #[Autowire(service: DependencyInjection::BOOTSTRAP_MANAGER)] private BootstrapManager $bootstrapManager, + #[Autowire(service: DependencyInjection::LOADER)] private ClassLoader $autoloader ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('bootstrap.manager'), - $drush_container->get('loader') - ); - - return $commandHandler; - } - /** * Rebuild all caches. * diff --git a/src/Commands/core/CliCommands.php b/src/Commands/core/CliCommands.php index 8e81b5ffb9..ba1ae65a47 100644 --- a/src/Commands/core/CliCommands.php +++ b/src/Commands/core/CliCommands.php @@ -6,6 +6,8 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Psysh\DrushCommand; @@ -15,11 +17,11 @@ use Drush\Utils\FsUtils; use Psy\Configuration; use Psy\VersionUpdater\Checker; -use Drush\Boot\DrupalBootLevels; -use Symfony\Component\DependencyInjection\ContainerInterface; final class CliCommands extends DrushCommands { + use AutowireTrait; + const DOCS_REPL = 'docs:repl'; const PHP = 'php:cli'; @@ -29,15 +31,6 @@ public function __construct( parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager') - ); - - return $commandHandler; - } - /** * Drush's PHP Shell. */ diff --git a/src/Commands/core/DeployCommands.php b/src/Commands/core/DeployCommands.php index 5e1b269ffc..e000cb2b14 100644 --- a/src/Commands/core/DeployCommands.php +++ b/src/Commands/core/DeployCommands.php @@ -7,33 +7,28 @@ use Consolidation\SiteAlias\SiteAlias; use Consolidation\SiteAlias\SiteAliasManagerInterface; use Consolidation\SiteProcess\ProcessManager; -use Drupal\Component\DependencyInjection\ContainerInterface; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\config\ConfigImportCommands; use Drush\Commands\DrushCommands; use Drush\Drush; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class DeployCommands extends DrushCommands { + use AutowireTrait; + const DEPLOY = 'deploy'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Run several commands after performing a code deployment. */ diff --git a/src/Commands/core/DeployHookCommands.php b/src/Commands/core/DeployHookCommands.php index ce96518cb6..28f71dcb98 100644 --- a/src/Commands/core/DeployHookCommands.php +++ b/src/Commands/core/DeployHookCommands.php @@ -7,42 +7,37 @@ use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Consolidation\OutputFormatters\StructuredData\UnstructuredListData; use Consolidation\SiteAlias\SiteAliasManagerInterface; -use Drupal\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; use Drupal\Core\Update\UpdateRegistry; use Drupal\Core\Utility\Error; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exceptions\UserAbortException; use Drush\Log\SuccessInterface; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; use Psr\Log\LogLevel; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class DeployHookCommands extends DrushCommands { + use AutowireTrait; + const HOOK_STATUS = 'deploy:hook-status'; const HOOK = 'deploy:hook'; const BATCH_PROCESS = 'deploy:batch-process'; const MARK_COMPLETE = 'deploy:mark-complete'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Get the deploy hook update registry. */ diff --git a/src/Commands/core/DrupalCommands.php b/src/Commands/core/DrupalCommands.php index e200f0bfe9..a59d63c7fe 100644 --- a/src/Commands/core/DrupalCommands.php +++ b/src/Commands/core/DrupalCommands.php @@ -10,14 +10,15 @@ use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Url; use Drush\Attributes as CLI; -use Drush\Commands\core\DocsCommands; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drupal\DrupalUtil; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class DrupalCommands extends DrushCommands { + use AutowireTrait; + const CRON = 'core:cron'; const REQUIREMENTS = 'core:requirements'; const ROUTE = 'core:route'; @@ -37,19 +38,12 @@ public function getRouteProvider(): RouteProviderInterface return $this->routeProvider; } - public function __construct(protected CronInterface $cron, protected ModuleHandlerInterface $moduleHandler, protected RouteProviderInterface $routeProvider) - { - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('cron'), - $container->get('module_handler'), - $container->get('router.route_provider') - ); - - return $commandHandler; + public function __construct( + protected CronInterface $cron, + protected ModuleHandlerInterface $moduleHandler, + protected RouteProviderInterface $routeProvider + ) { + parent::__construct(); } /** diff --git a/src/Commands/core/DrupalDirectoryCommands.php b/src/Commands/core/DrupalDirectoryCommands.php index 220d9ea5b1..e8421fa8d7 100644 --- a/src/Commands/core/DrupalDirectoryCommands.php +++ b/src/Commands/core/DrupalDirectoryCommands.php @@ -6,34 +6,29 @@ use Consolidation\SiteAlias\HostPath; use Consolidation\SiteAlias\SiteAliasManagerInterface; -use Drupal\Component\DependencyInjection\ContainerInterface; use Drush\Attributes as CLI; use Drush\Backend\BackendPathEvaluator; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class DrupalDirectoryCommands extends DrushCommands { + use AutowireTrait; + const DIRECTORY = 'drupal:directory'; protected BackendPathEvaluator $pathEvaluator; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); $this->pathEvaluator = new BackendPathEvaluator(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Return the filesystem path for modules/themes and other key folders. */ diff --git a/src/Commands/core/EditCommands.php b/src/Commands/core/EditCommands.php index baa1ddcd0c..c4121aae9d 100644 --- a/src/Commands/core/EditCommands.php +++ b/src/Commands/core/EditCommands.php @@ -6,13 +6,13 @@ use Consolidation\SiteAlias\SiteAliasManagerInterface; use Consolidation\SiteProcess\Util\Escape; -use Drupal\Component\DependencyInjection\ContainerInterface; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exec\ExecTrait; use League\Container\Container as DrushContainer; +use Symfony\Component\DependencyInjection\ContainerInterface; final class EditCommands extends DrushCommands { @@ -26,6 +26,9 @@ public function __construct( parent::__construct(); } + /** + * Not using Autowire in order to implicitly test backward compat. + */ public static function create(ContainerInterface $container, DrushContainer $drush_container): self { $commandHandler = new static( diff --git a/src/Commands/core/EntityCommands.php b/src/Commands/core/EntityCommands.php index a28001353c..3a35d8f107 100644 --- a/src/Commands/core/EntityCommands.php +++ b/src/Commands/core/EntityCommands.php @@ -7,15 +7,17 @@ use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Entity\EntityStorageException; -use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\Query\QueryInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class EntityCommands extends DrushCommands { + use AutowireTrait; + const DELETE = 'entity:delete'; const SAVE = 'entity:save'; @@ -24,15 +26,6 @@ public function __construct(protected EntityTypeManagerInterface $entityTypeMana parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - ); - - return $commandHandler; - } - /** * Delete content entities. * diff --git a/src/Commands/core/EntityCreateCommands.php b/src/Commands/core/EntityCreateCommands.php index 71effcbdfb..4cf29d8c6d 100644 --- a/src/Commands/core/EntityCreateCommands.php +++ b/src/Commands/core/EntityCreateCommands.php @@ -15,13 +15,15 @@ use Drupal\Core\Session\AccountSwitcherInterface; use Drupal\field\Entity\FieldStorageConfig; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Yaml\Yaml; final class EntityCreateCommands extends DrushCommands { + use AutowireTrait; + const CREATE = 'entity:create'; public function __construct( @@ -32,17 +34,6 @@ public function __construct( parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - $container->get('entity_field.manager'), - $container->get('account_switcher') - ); - - return $commandHandler; - } - /** * Create a content entity after prompting for field values. * diff --git a/src/Commands/core/LanguageCommands.php b/src/Commands/core/LanguageCommands.php index a6668fed88..ec044d1cb2 100644 --- a/src/Commands/core/LanguageCommands.php +++ b/src/Commands/core/LanguageCommands.php @@ -9,12 +9,14 @@ use Drupal\Core\Language\LanguageManagerInterface; use Drupal\language\Entity\ConfigurableLanguage; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class LanguageCommands extends DrushCommands { + use AutowireTrait; + const ADD = 'language:add'; const INFO = 'language:info'; @@ -28,18 +30,11 @@ public function getModuleHandler(): ModuleHandlerInterface return $this->moduleHandler; } - public function __construct(protected LanguageManagerInterface $languageManager, protected ModuleHandlerInterface $moduleHandler) - { - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('language_manager'), - $container->get('module_handler') - ); - - return $commandHandler; + public function __construct( + protected LanguageManagerInterface $languageManager, + protected ModuleHandlerInterface $moduleHandler + ) { + parent::__construct(); } #[CLI\Command(name: self::ADD, aliases: ['language-add'])] diff --git a/src/Commands/core/LinkHooks.php b/src/Commands/core/LinkHooks.php index 33abe1f406..318ba6dc59 100644 --- a/src/Commands/core/LinkHooks.php +++ b/src/Commands/core/LinkHooks.php @@ -9,27 +9,21 @@ use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\link\LinkItemInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Commands\field\FieldCreateCommands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\DependencyInjection\ContainerInterface; final class LinkHooks extends DrushCommands { + use AutowireTrait; + public function __construct( protected ModuleHandlerInterface $moduleHandler ) { - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('module_handler') - ); - - return $commandHandler; + parent::__construct(); } #[CLI\Hook(type: HookManager::OPTION_HOOK, target: FieldCreateCommands::CREATE)] diff --git a/src/Commands/core/LocaleCommands.php b/src/Commands/core/LocaleCommands.php index fea828a6ef..b107ddc6c6 100644 --- a/src/Commands/core/LocaleCommands.php +++ b/src/Commands/core/LocaleCommands.php @@ -15,13 +15,15 @@ use Drupal\language\Entity\ConfigurableLanguage; use Drupal\locale\PoDatabaseReader; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Exceptions\CommandFailedException; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class LocaleCommands extends DrushCommands { + use AutowireTrait; + const CHECK = 'locale:check'; const CLEAR = 'locale:clear-status'; const UPDATE = 'locale:update'; @@ -49,20 +51,13 @@ public function getState(): StateInterface return $this->state; } - public function __construct(protected LanguageManagerInterface $languageManager, protected ConfigFactoryInterface $configFactory, protected ModuleHandlerInterface $moduleHandler, protected StateInterface $state) - { - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('language_manager'), - $container->get('config.factory'), - $container->get('module_handler'), - $container->get('state') - ); - - return $commandHandler; + public function __construct( + protected LanguageManagerInterface $languageManager, + protected ConfigFactoryInterface $configFactory, + protected ModuleHandlerInterface $moduleHandler, + protected StateInterface $state + ) { + parent::__construct(); } /** diff --git a/src/Commands/core/LoginCommands.php b/src/Commands/core/LoginCommands.php index f27a8f0a9f..8a7dd31270 100644 --- a/src/Commands/core/LoginCommands.php +++ b/src/Commands/core/LoginCommands.php @@ -10,33 +10,30 @@ use Drush\Attributes as CLI; use Drush\Boot\BootstrapManager; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exec\ExecTrait; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class LoginCommands extends DrushCommands { + use AutowireTrait; use ExecTrait; const LOGIN = 'user:login'; public function __construct( + #[Autowire(service: DependencyInjection::BOOTSTRAP_MANAGER)] private readonly BootstrapManager $bootstrapManager, + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly($drush_container): self - { - $commandHandler = new static( - $drush_container->get('bootstrap.manager'), - $drush_container->get('site.alias.manager') - ); - - return $commandHandler; - } - /** * Display a one time login link for user ID 1, or another user. */ diff --git a/src/Commands/core/MaintCommands.php b/src/Commands/core/MaintCommands.php index 19282cfdb1..bc66a61534 100644 --- a/src/Commands/core/MaintCommands.php +++ b/src/Commands/core/MaintCommands.php @@ -6,11 +6,13 @@ use Drupal\Core\State\StateInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Symfony\Component\DependencyInjection\ContainerInterface; final class MaintCommands extends DrushCommands { + use AutowireTrait; + const KEY = 'system.maintenance_mode'; const GET = 'maint:get'; const SET = 'maint:set'; @@ -20,15 +22,6 @@ public function __construct(protected StateInterface $state) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('state') - ); - - return $commandHandler; - } - public function getState(): StateInterface { return $this->state; diff --git a/src/Commands/core/MessengerCommands.php b/src/Commands/core/MessengerCommands.php index e742932aa5..15479bfc4e 100644 --- a/src/Commands/core/MessengerCommands.php +++ b/src/Commands/core/MessengerCommands.php @@ -7,23 +7,16 @@ use Consolidation\AnnotatedCommand\Hooks\HookManager; use Drupal\Core\Messenger\MessengerInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drupal\DrupalUtil; -use Symfony\Component\DependencyInjection\ContainerInterface; final class MessengerCommands extends DrushCommands { - public function __construct(protected MessengerInterface $messenger) - { - } + use AutowireTrait; - public static function create(ContainerInterface $container): self + public function __construct(protected MessengerInterface $messenger) { - $commandHandler = new static( - $container->get('messenger') - ); - - return $commandHandler; } #[CLI\Hook(type: HookManager::PRE_COMMAND_HOOK, target: '*')] diff --git a/src/Commands/core/MigrateRunnerCommands.php b/src/Commands/core/MigrateRunnerCommands.php index d353962e0f..2117b5fa0b 100644 --- a/src/Commands/core/MigrateRunnerCommands.php +++ b/src/Commands/core/MigrateRunnerCommands.php @@ -11,7 +11,6 @@ use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; -use Drupal\Core\KeyValueStore\KeyValueStoreInterface; use Drupal\migrate\Exception\RequirementsException; use Drupal\migrate\MigrateMessageInterface; use Drupal\migrate\Plugin\MigrateIdMapInterface; @@ -19,40 +18,36 @@ use Drupal\migrate\Plugin\MigrationPluginManagerInterface; use Drupal\migrate\Plugin\RequirementsInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drupal\Migrate; use Drush\Drupal\Migrate\MigrateExecutable; use Drush\Drupal\Migrate\MigrateMessage; use Drush\Drupal\Migrate\MigrateUtils; +use Drush\Drush; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Path; class MigrateRunnerCommands extends DrushCommands { - protected KeyValueStoreInterface $keyValue; + use AutowireTrait; + protected ?MigrationPluginManagerInterface $migrationPluginManager = null; public function __construct( protected DateFormatterInterface $dateFormatter, - KeyValueFactoryInterface $keyValueFactory + // @todo Can we avoid the autowire attribute here? + #[Autowire(service: 'keyvalue')] + protected KeyValueFactoryInterface $keyValueFactory ) { parent::__construct(); $this->keyValue = $keyValueFactory->get('migrate_last_imported'); - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('date.formatter'), - $container->get('keyvalue') - ); + $container = Drush::getContainer(); if ($container->has('plugin.manager.migration')) { - $commandHandler->setMigrationPluginManager($container->get('plugin.manager.migration')); + $this->setMigrationPluginManager($container->get('plugin.manager.migration')); } - - return $commandHandler; } /** diff --git a/src/Commands/core/MkCommands.php b/src/Commands/core/MkCommands.php index dd8f130402..545b3fd7bd 100644 --- a/src/Commands/core/MkCommands.php +++ b/src/Commands/core/MkCommands.php @@ -13,35 +13,16 @@ use Drush\Commands\help\HelpCLIFormatter; use Drush\Commands\help\ListCommands; use Drush\Drush; -use Psr\Container\ContainerInterface as DrushContainer; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Path; use Symfony\Component\Yaml\Yaml; final class MkCommands extends DrushCommands { - protected function __construct( - private readonly ContainerInterface $container, - private readonly DrushContainer $drush_container, - ) { - parent::__construct(); - } - - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $container, - $drush_container, - ); - - return $commandHandler; - } - /** * Build a Markdown document for each Drush command/generator that is available on a site. * @@ -66,7 +47,8 @@ public function docs(): void $destination = 'generators'; $destination_path = Path::join($dir_root, 'docs', $destination); $this->prepare($destination_path); - $application_generate = (new ApplicationFactory($this->container, $this->drush_container, $this->logger()))->create(); + $container = Drush::getContainer(); + $application_generate = (new ApplicationFactory($container->get('service_container'), $container, $this->logger()))->create(); $all = $this->createAnnotatedCommands($application_generate, Drush::getApplication()); $namespaced = ListCommands::categorize($all); [$nav_generators, $pages_generators, $map_generators] = $this->writeContentFilesAndBuildNavAndBuildRedirectMap($namespaced, $destination, $dir_root, $destination_path); diff --git a/src/Commands/core/PhpCommands.php b/src/Commands/core/PhpCommands.php index 12db6346b7..40fab7b87e 100644 --- a/src/Commands/core/PhpCommands.php +++ b/src/Commands/core/PhpCommands.php @@ -11,6 +11,7 @@ use Drush\Commands\DrushCommands; use Symfony\Component\Finder\Finder; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class PhpCommands extends DrushCommands implements StdinAwareInterface { use StdinAwareTrait; diff --git a/src/Commands/core/QueueCommands.php b/src/Commands/core/QueueCommands.php index 6ade510742..303608e9c2 100644 --- a/src/Commands/core/QueueCommands.php +++ b/src/Commands/core/QueueCommands.php @@ -4,34 +4,29 @@ namespace Drush\Commands\core; -use Consolidation\AnnotatedCommand\Hooks\HookManager; -use Drupal\Core\Queue\QueueInterface; -use Consolidation\AnnotatedCommand\CommandData; -use Consolidation\AnnotatedCommand\CommandError; use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Drupal\Core\Queue\DelayableQueueInterface; use Drupal\Core\Queue\DelayedRequeueException; use Drupal\Core\Queue\QueueFactory; +use Drupal\Core\Queue\QueueGarbageCollectionInterface; +use Drupal\Core\Queue\QueueInterface; use Drupal\Core\Queue\QueueWorkerManagerInterface; use Drupal\Core\Queue\RequeueException; use Drupal\Core\Queue\SuspendQueueException; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\Core\Queue\QueueGarbageCollectionInterface; -use JetBrains\PhpStorm\Deprecated; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; -use Symfony\Component\DependencyInjection\ContainerInterface; final class QueueCommands extends DrushCommands { + use AutowireTrait; + const RUN = 'queue:run'; const LIST = 'queue:list'; const DELETE = 'queue:delete'; - /** - * @var QueueWorkerManagerInterface - */ protected QueueWorkerManagerInterface $workerManager; protected $queueService; @@ -42,16 +37,6 @@ public function __construct(QueueWorkerManagerInterface $workerManager, QueueFac $this->queueService = $queueService; } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('plugin.manager.queue_worker'), - $container->get('queue') - ); - - return $commandHandler; - } - public function getWorkerManager(): QueueWorkerManagerInterface { return $this->workerManager; diff --git a/src/Commands/core/RoleCommands.php b/src/Commands/core/RoleCommands.php index c9a9df2edd..99ec7ab188 100644 --- a/src/Commands/core/RoleCommands.php +++ b/src/Commands/core/RoleCommands.php @@ -6,19 +6,22 @@ use Consolidation\OutputFormatters\Options\FormatterOptions; use Consolidation\OutputFormatters\StructuredData\RowsOfFields; -use Consolidation\SiteAlias\SiteAliasManagerInterface; -use Drupal\Component\DependencyInjection\ContainerInterface; +use Consolidation\SiteAlias\SiteAliasManager; use Drupal\user\Entity\Role; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; +use Drush\Runtime\DependencyInjection; use Drush\Utils\StringUtils; -use League\Container\Container as DrushContainer; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class RoleCommands extends DrushCommands { + use AutowireTrait; + const CREATE = 'role:create'; const DELETE = 'role:delete'; const PERM_ADD = 'role:perm:add'; @@ -26,20 +29,12 @@ final class RoleCommands extends DrushCommands const LIST = 'role:list'; public function __construct( - private readonly SiteAliasManagerInterface $siteAliasManager + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] + private readonly SiteAliasManager $siteAliasManager ) { parent::__construct(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Create a new role. */ diff --git a/src/Commands/core/RsyncCommands.php b/src/Commands/core/RsyncCommands.php index 4839947bb2..327bf5686c 100644 --- a/src/Commands/core/RsyncCommands.php +++ b/src/Commands/core/RsyncCommands.php @@ -11,13 +11,20 @@ use Consolidation\SiteProcess\Util\Escape; use Drush\Attributes as CLI; use Drush\Backend\BackendPathEvaluator; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Config\ConfigLocator; use Drush\Exceptions\UserAbortException; +use Drush\Runtime\DependencyInjection; use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class RsyncCommands extends DrushCommands { + use AutowireTrait; + /** * These are arguments after the aliases and paths have been evaluated. * @see validate(). @@ -30,6 +37,7 @@ final class RsyncCommands extends DrushCommands protected BackendPathEvaluator $pathEvaluator; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); @@ -38,15 +46,6 @@ public function __construct( $this->pathEvaluator = new BackendPathEvaluator(); } - public static function createEarly($drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager') - ); - - return $commandHandler; - } - /** * Rsync Drupal code or files to/from another server using ssh. */ diff --git a/src/Commands/core/SiteCommands.php b/src/Commands/core/SiteCommands.php index 65abe2cfff..2ecdab5f7a 100644 --- a/src/Commands/core/SiteCommands.php +++ b/src/Commands/core/SiteCommands.php @@ -6,31 +6,26 @@ use Consolidation\OutputFormatters\StructuredData\UnstructuredListData; use Consolidation\SiteAlias\SiteAliasManagerInterface; -use Drupal\Component\DependencyInjection\ContainerInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class SiteCommands extends DrushCommands { + use AutowireTrait; + const SET = 'site:set'; const ALIAS = 'site:alias'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Set a site alias that will persist for the current session. * diff --git a/src/Commands/core/SiteInstallCommands.php b/src/Commands/core/SiteInstallCommands.php index a7b01cc9f6..c110e44b38 100644 --- a/src/Commands/core/SiteInstallCommands.php +++ b/src/Commands/core/SiteInstallCommands.php @@ -4,55 +4,49 @@ namespace Drush\Commands\core; +use Composer\Autoload\ClassLoader; use Consolidation\AnnotatedCommand\CommandData; use Consolidation\AnnotatedCommand\Hooks\HookManager; +use Consolidation\SiteAlias\SiteAliasManager; use Drupal\Component\FileCache\FileCacheFactory; +use Drupal\Core\Config\FileStorage; use Drupal\Core\Database\Database; use Drupal\Core\Installer\Exception\AlreadyInstalledException; use Drupal\Core\Site\Settings; use Drush\Attributes as CLI; +use Drush\Boot\BootstrapManager; use Drush\Boot\DrupalBootLevels; use Drush\Boot\Kernels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drush\Drush; use Drush\Exceptions\UserAbortException; -use Drupal\Core\Config\FileStorage; use Drush\Exec\ExecTrait; +use Drush\Runtime\DependencyInjection; use Drush\Sql\SqlBase; use Drush\Utils\StringUtils; -use Psr\Container\ContainerInterface as DrushContainer; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Path; -use Drush\Boot\BootstrapManager; -use Consolidation\SiteAlias\SiteAliasManager; -use Drush\Config\DrushConfig; -use Composer\Autoload\ClassLoader; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class SiteInstallCommands extends DrushCommands { + use AutowireTrait; use ExecTrait; const INSTALL = 'site:install'; public function __construct( + #[Autowire(service: DependencyInjection::BOOTSTRAP_MANAGER)] private BootstrapManager $bootstrapManager, + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private SiteAliasManager $siteAliasManager, + #[Autowire(service: DependencyInjection::LOADER)] private ClassLoader $autoloader ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('bootstrap.manager'), - $drush_container->get('site.alias.manager'), - $drush_container->get('loader') - ); - - return $commandHandler; - } - /** * Install Drupal along with modules/themes/configuration/profile. */ diff --git a/src/Commands/core/SshCommands.php b/src/Commands/core/SshCommands.php index 9e1388bd17..83663dc272 100644 --- a/src/Commands/core/SshCommands.php +++ b/src/Commands/core/SshCommands.php @@ -8,28 +8,26 @@ use Consolidation\SiteProcess\Util\Shell; use Consolidation\SiteProcess\Util\Tty; use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class SshCommands extends DrushCommands { + use AutowireTrait; + const SSH = 'site:ssh'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Connect to a webserver via SSH, and optionally run a shell command. */ diff --git a/src/Commands/core/StateCommands.php b/src/Commands/core/StateCommands.php index 12f4c5d0e0..011bbc5df5 100644 --- a/src/Commands/core/StateCommands.php +++ b/src/Commands/core/StateCommands.php @@ -9,12 +9,13 @@ use Consolidation\OutputFormatters\StructuredData\PropertyList; use Drupal\Core\State\StateInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Yaml\Yaml; -use Symfony\Component\DependencyInjection\ContainerInterface; final class StateCommands extends DrushCommands implements StdinAwareInterface { + use AutowireTrait; use StdinAwareTrait; const GET = 'state:get'; @@ -25,15 +26,6 @@ public function __construct(protected StateInterface $state) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('state') - ); - - return $commandHandler; - } - public function getState(): StateInterface { return $this->state; diff --git a/src/Commands/core/StatusCommands.php b/src/Commands/core/StatusCommands.php index 79ec4e36ef..8e2897f01f 100644 --- a/src/Commands/core/StatusCommands.php +++ b/src/Commands/core/StatusCommands.php @@ -23,6 +23,7 @@ use League\Container\Container as DrushContainer; use Symfony\Component\Filesystem\Path; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class StatusCommands extends DrushCommands { const STATUS = 'core:status'; @@ -33,6 +34,9 @@ public function __construct( parent::__construct(); } + /** + * Not using Autowire in order to implicitly test backward compat. + */ public static function createEarly(DrushContainer $drush_container): self { $commandHandler = new static( diff --git a/src/Commands/core/TwigCommands.php b/src/Commands/core/TwigCommands.php index bbb52e722e..3ded8cdab8 100644 --- a/src/Commands/core/TwigCommands.php +++ b/src/Commands/core/TwigCommands.php @@ -7,39 +7,35 @@ use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Drupal\Core\DrupalKernelInterface; use Drupal\Core\Extension\ExtensionList; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\PhpStorage\PhpStorageFactory; use Drupal\Core\State\StateInterface; use Drupal\Core\Template\TwigEnvironment; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\Core\Extension\ModuleHandlerInterface; use Drush\Drush; use Drush\Utils\StringUtils; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Path; use Symfony\Component\Finder\Finder; -use Symfony\Component\DependencyInjection\ContainerInterface; final class TwigCommands extends DrushCommands { + use AutowireTrait; + const UNUSED = 'twig:unused'; const COMPILE = 'twig:compile'; const DEBUG = 'twig:debug'; - public function __construct(protected TwigEnvironment $twig, protected ModuleHandlerInterface $moduleHandler, private ExtensionList $extensionList, private StateInterface $state, private DrupalKernelInterface $kernel) - { - } - - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('twig'), - $container->get('module_handler'), - $container->get('extension.list.module'), - $container->get('state'), - $container->get('kernel'), - ); - - return $commandHandler; + public function __construct( + protected TwigEnvironment $twig, + protected ModuleHandlerInterface $moduleHandler, + #[Autowire(service: 'extension.list.module')] + private ExtensionList $extensionList, + private StateInterface $state, + private DrupalKernelInterface $kernel + ) { } public function getTwig(): TwigEnvironment diff --git a/src/Commands/core/UpdateDBCommands.php b/src/Commands/core/UpdateDBCommands.php index 9cb8bbba54..f915e67f87 100644 --- a/src/Commands/core/UpdateDBCommands.php +++ b/src/Commands/core/UpdateDBCommands.php @@ -11,35 +11,32 @@ use Drupal\Core\Utility\Error; use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drupal\DrupalUtil; use Drush\Drush; use Drush\Exceptions\UserAbortException; use Drush\Log\SuccessInterface; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; use Psr\Log\LogLevel; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class UpdateDBCommands extends DrushCommands { + use AutowireTrait; + const UPDATEDB = 'updatedb'; const STATUS = 'updatedb:status'; const BATCH_PROCESS = 'updatedb:batch-process'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Note - can't inject @database since a method below is static. */ diff --git a/src/Commands/core/UserCommands.php b/src/Commands/core/UserCommands.php index 5a480d5df0..c6fdf45c21 100644 --- a/src/Commands/core/UserCommands.php +++ b/src/Commands/core/UserCommands.php @@ -4,23 +4,25 @@ namespace Drush\Commands\core; -use Consolidation\AnnotatedCommand\Hooks\HookManager; -use Drupal\Core\Datetime\DateFormatterInterface; use Consolidation\AnnotatedCommand\CommandData; use Consolidation\AnnotatedCommand\CommandError; +use Consolidation\AnnotatedCommand\Hooks\HookManager; use Consolidation\OutputFormatters\Options\FormatterOptions; use Consolidation\OutputFormatters\StructuredData\RowsOfFields; +use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\user\Entity\Role; use Drupal\user\Entity\User; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Utils\StringUtils; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; -use Symfony\Component\DependencyInjection\ContainerInterface; final class UserCommands extends DrushCommands { + use AutowireTrait; + const INFORMATION = 'user:information'; const BLOCK = 'user:block'; const UNBLOCK = 'user:unblock'; @@ -59,15 +61,6 @@ public function __construct(protected DateFormatterInterface $dateFormatter) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('date.formatter') - ); - - return $commandHandler; - } - /** * Print information about the specified user(s). */ diff --git a/src/Commands/core/ViewsCommands.php b/src/Commands/core/ViewsCommands.php index 7c618519b5..79b10b8a85 100644 --- a/src/Commands/core/ViewsCommands.php +++ b/src/Commands/core/ViewsCommands.php @@ -10,14 +10,16 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Render\RendererInterface; +use Drupal\views\Views; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\views\Views; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class ViewsCommands extends DrushCommands { + use AutowireTrait; + const DEV = 'views:dev'; const EXECUTE = 'views:execute'; const LIST = 'views:list'; @@ -33,18 +35,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('config.factory'), - $container->get('module_handler'), - $container->get('entity_type.manager'), - $container->get('renderer') - ); - - return $commandHandler; - } - public function getConfigFactory(): ConfigFactoryInterface { return $this->configFactory; diff --git a/src/Commands/core/WatchdogCommands.php b/src/Commands/core/WatchdogCommands.php index ee5bc59071..19300ac8f8 100644 --- a/src/Commands/core/WatchdogCommands.php +++ b/src/Commands/core/WatchdogCommands.php @@ -7,24 +7,26 @@ use Consolidation\AnnotatedCommand\Hooks\HookManager; use Consolidation\OutputFormatters\StructuredData\PropertyList; use Consolidation\OutputFormatters\StructuredData\RowsOfFields; +use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Database\Connection; use Drupal\Core\Logger\RfcLogLevel; use Drupal\Core\Session\AnonymousUserSession; use Drupal\user\Entity\User; use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\Html; use Drush\Drupal\DrupalUtil; use Drush\Exceptions\UserAbortException; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; -use Drush\Boot\DrupalBootLevels; -use Symfony\Component\DependencyInjection\ContainerInterface; final class WatchdogCommands extends DrushCommands { + use AutowireTrait; + const SHOW = 'watchdog:show'; const LIST = 'watchdog:list'; const TAIL = 'watchdog:tail'; @@ -35,15 +37,6 @@ public function __construct(protected Connection $connection) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('database') - ); - - return $commandHandler; - } - /** * Show watchdog messages. */ diff --git a/src/Commands/field/FieldBaseInfoCommands.php b/src/Commands/field/FieldBaseInfoCommands.php index 8b901f70dd..3cfe7f679e 100644 --- a/src/Commands/field/FieldBaseInfoCommands.php +++ b/src/Commands/field/FieldBaseInfoCommands.php @@ -9,13 +9,15 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; -use Symfony\Component\DependencyInjection\ContainerInterface; class FieldBaseInfoCommands extends DrushCommands { + use AutowireTrait; + use EntityTypeBundleAskTrait; use EntityTypeBundleValidationTrait; use FieldDefinitionRowsOfFieldsTrait; @@ -27,17 +29,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - $container->get('entity_type.bundle.info'), - $container->get('entity_field.manager') - ); - - return $commandHandler; - } - /** * List all base fields of an entity type */ diff --git a/src/Commands/field/FieldBaseOverrideCreateCommands.php b/src/Commands/field/FieldBaseOverrideCreateCommands.php index 38e6944c15..32148fd93f 100644 --- a/src/Commands/field/FieldBaseOverrideCreateCommands.php +++ b/src/Commands/field/FieldBaseOverrideCreateCommands.php @@ -10,18 +10,17 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\Entity\BaseFieldOverride; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Question\ConfirmationQuestion; -use Symfony\Component\DependencyInjection\ContainerInterface; use function dt; -use function t; class FieldBaseOverrideCreateCommands extends DrushCommands { + use AutowireTrait; use EntityTypeBundleAskTrait; use EntityTypeBundleValidationTrait; @@ -32,17 +31,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - $container->get('entity_type.bundle.info'), - $container->get('entity_field.manager') - ); - - return $commandHandler; - } - /** * Create a new base field override * diff --git a/src/Commands/field/FieldCreateCommands.php b/src/Commands/field/FieldCreateCommands.php index dacf4597a3..14a9436d33 100644 --- a/src/Commands/field/FieldCreateCommands.php +++ b/src/Commands/field/FieldCreateCommands.php @@ -15,7 +15,6 @@ use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\WidgetPluginManager; @@ -24,14 +23,12 @@ use Drupal\field\FieldStorageConfigInterface; use Drush\Attributes as CLI; use Drush\Commands\DrushCommands; +use Psr\Container\ContainerInterface; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\DependencyInjection\ContainerInterface; use function dt; -use function t; class FieldCreateCommands extends DrushCommands implements CustomEventAwareInterface { @@ -52,6 +49,7 @@ public function __construct( protected ModuleHandlerInterface $moduleHandler, protected EntityFieldManagerInterface $entityFieldManager ) { + parent::__construct(); } public static function create(ContainerInterface $container): self diff --git a/src/Commands/field/FieldDefinitionCommands.php b/src/Commands/field/FieldDefinitionCommands.php index 82ced56e1d..733bd2b652 100644 --- a/src/Commands/field/FieldDefinitionCommands.php +++ b/src/Commands/field/FieldDefinitionCommands.php @@ -4,43 +4,37 @@ namespace Drush\Commands\field; -use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Consolidation\OutputFormatters\StructuredData\UnstructuredListData; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\FormatterPluginManager; use Drupal\Core\Field\WidgetPluginManager; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class FieldDefinitionCommands extends DrushCommands { + use AutowireTrait; + const TYPES = 'field:types'; const WIDGETS = 'field:widgets'; const FORMATTERS = 'field:formatters'; public function __construct( private readonly FieldTypePluginManagerInterface $typePluginManager, + // @todo These attributes should not be needed but services aren't found otherwise. + #[Autowire(service: 'plugin.manager.field.widget')] private readonly WidgetPluginManager $widgetPluginManager, + #[Autowire(service: 'plugin.manager.field.formatter')] private readonly FormatterPluginManager $formatterPluginManager, ) { parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('plugin.manager.field.field_type'), - $container->get('plugin.manager.field.widget'), - $container->get('plugin.manager.field.formatter') - ); - - return $commandHandler; - } - #[CLI\Command(name: self::TYPES)] #[CLI\FieldLabels( labels: [ diff --git a/src/Commands/field/FieldDeleteCommands.php b/src/Commands/field/FieldDeleteCommands.php index b898e02c33..cbbc913d6a 100644 --- a/src/Commands/field/FieldDeleteCommands.php +++ b/src/Commands/field/FieldDeleteCommands.php @@ -4,43 +4,33 @@ namespace Drush\Commands\field; -use Drupal\Core\Entity\EntityTypeBundleInfo; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\FieldConfigInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\DependencyInjection\ContainerInterface; use function count; use function dt; use function field_purge_batch; -use function t; class FieldDeleteCommands extends DrushCommands { + use AutowireTrait; use EntityTypeBundleAskTrait; use EntityTypeBundleValidationTrait; public function __construct( protected EntityTypeManagerInterface $entityTypeManager, - protected EntityTypeBundleInfo $entityTypeBundleInfo + protected EntityTypeBundleInfoInterface $entityTypeBundleInfo ) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - $container->get('entity_type.bundle.info') - ); - - return $commandHandler; - } - /** * Delete a field * diff --git a/src/Commands/field/FieldEntityReferenceHooks.php b/src/Commands/field/FieldEntityReferenceHooks.php index 585a1072c2..f0d74bd2d5 100644 --- a/src/Commands/field/FieldEntityReferenceHooks.php +++ b/src/Commands/field/FieldEntityReferenceHooks.php @@ -6,13 +6,13 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\DependencyInjection\ContainerInterface; class FieldEntityReferenceHooks extends DrushCommands { + use AutowireTrait; use EntityTypeBundleValidationTrait; public function __construct( @@ -21,14 +21,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): static - { - return new static( - $container->get('entity_type.manager'), - $container->get('entity_type.bundle.info'), - ); - } - #[CLI\Hook(type: HookManager::ON_EVENT, target: 'field-create-field-storage')] public function hookFieldStorage(array $values, InputInterface $input): array { diff --git a/src/Commands/field/FieldInfoCommands.php b/src/Commands/field/FieldInfoCommands.php index e37ccdfee9..a014a61386 100644 --- a/src/Commands/field/FieldInfoCommands.php +++ b/src/Commands/field/FieldInfoCommands.php @@ -8,13 +8,14 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; -use Symfony\Component\DependencyInjection\ContainerInterface; class FieldInfoCommands extends DrushCommands { + use AutowireTrait; use EntityTypeBundleAskTrait; use EntityTypeBundleValidationTrait; use FieldDefinitionRowsOfFieldsTrait; @@ -25,16 +26,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('entity_type.manager'), - $container->get('entity_type.bundle.info') - ); - - return $commandHandler; - } - /** * List all configurable fields of an entity bundle */ diff --git a/src/Commands/field/FieldTextHooks.php b/src/Commands/field/FieldTextHooks.php index e4c5a7b90a..98a8456bc2 100644 --- a/src/Commands/field/FieldTextHooks.php +++ b/src/Commands/field/FieldTextHooks.php @@ -9,15 +9,15 @@ use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\text\Plugin\Field\FieldType\TextItemBase; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\DependencyInjection\ContainerInterface; class FieldTextHooks extends DrushCommands { + use AutowireTrait; use EntityTypeBundleValidationTrait; public function __construct( @@ -26,15 +26,6 @@ public function __construct( ) { } - public static function create(ContainerInterface $container): static - { - return new static( - $container->get('entity_type.manager'), - $container->get('plugin.manager.field.field_type'), - ); - } - - #[CLI\Hook(type: HookManager::OPTION_HOOK, target: FieldCreateCommands::CREATE)] public function hookOption(Command $command, AnnotationData $annotationData): void { diff --git a/src/Commands/generate/ApplicationFactory.php b/src/Commands/generate/ApplicationFactory.php index 8dafcea5e5..39fef6dc5b 100644 --- a/src/Commands/generate/ApplicationFactory.php +++ b/src/Commands/generate/ApplicationFactory.php @@ -10,9 +10,9 @@ use Drush\Commands\generate\Generators\Drush\DrushCommandFile; use Drush\Commands\generate\Generators\Drush\DrushGenerator; use Drush\Runtime\ServiceManager; +use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface as DrushContainer; use Psr\Log\LoggerInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; class ApplicationFactory { diff --git a/src/Commands/generate/GenerateCommands.php b/src/Commands/generate/GenerateCommands.php index f68298d4c9..bf087b329b 100644 --- a/src/Commands/generate/GenerateCommands.php +++ b/src/Commands/generate/GenerateCommands.php @@ -8,12 +8,12 @@ use Drush\Commands\core\DocsCommands; use Drush\Commands\DrushCommands; use Drush\Commands\help\ListCommands; +use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface as DrushContainer; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\ArgvInput; -use Symfony\Component\DependencyInjection\ContainerInterface; final class GenerateCommands extends DrushCommands { @@ -25,11 +25,11 @@ protected function __construct( ) { } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self + public static function create(ContainerInterface $container): self { $commandHandler = new static( + $container->get('service_container'), $container, - $drush_container, ); return $commandHandler; diff --git a/src/Commands/generate/Generators/Drush/drush-command-file.php.twig b/src/Commands/generate/Generators/Drush/drush-command-file.php.twig index 5cb44f35ea..a282e243eb 100644 --- a/src/Commands/generate/Generators/Drush/drush-command-file.php.twig +++ b/src/Commands/generate/Generators/Drush/drush-command-file.php.twig @@ -8,7 +8,7 @@ use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Drush\Attributes as CLI; use Drush\Commands\DrushCommands; {% if services %} -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drush\Commands\AutowireTrait; {{ di.use(services) }} {% endif %} {% endsort %} @@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; final class {{ class }} extends DrushCommands { {% if services %} + use AutowireTrait; + /** * Constructs {{ class|article }} object. */ @@ -27,15 +29,6 @@ final class {{ class }} extends DrushCommands { ) { parent::__construct(); } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( -{{ di.container(services) }} - ); - } {% endif %} /** diff --git a/src/Commands/pm/PmCommands.php b/src/Commands/pm/PmCommands.php index 3decc7065b..a97ba8446e 100644 --- a/src/Commands/pm/PmCommands.php +++ b/src/Commands/pm/PmCommands.php @@ -14,15 +14,16 @@ use Drupal\Core\Extension\ModuleInstallerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drush\Attributes as CLI; -use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exceptions\UserAbortException; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class PmCommands extends DrushCommands { + use AutowireTrait; + const INSTALL = 'pm:install'; const UNINSTALL = 'pm:uninstall'; const LIST = 'pm:list'; @@ -37,19 +38,6 @@ public function __construct( parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('config.factory'), - $container->get('module_installer'), - $container->get('module_handler'), - $container->get('theme_handler'), - $container->get('extension.list.module') - ); - - return $commandHandler; - } - public function getConfigFactory(): ConfigFactoryInterface { return $this->configFactory; diff --git a/src/Commands/pm/ThemeCommands.php b/src/Commands/pm/ThemeCommands.php index f9ef1111c5..4226987a04 100644 --- a/src/Commands/pm/ThemeCommands.php +++ b/src/Commands/pm/ThemeCommands.php @@ -5,30 +5,24 @@ namespace Drush\Commands\pm; use Drupal\Core\Extension\ThemeInstallerInterface; -use Drush\Commands\DrushCommands; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; +use Drush\Commands\DrushCommands; use Drush\Utils\StringUtils; -use Symfony\Component\DependencyInjection\ContainerInterface; final class ThemeCommands extends DrushCommands { + use AutowireTrait; + const INSTALL = 'theme:install'; const UNINSTALL = 'theme:uninstall'; - public function __construct(protected ThemeInstallerInterface $themeInstaller) - { + public function __construct( + protected ThemeInstallerInterface $themeInstaller + ) { parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('theme_installer') - ); - - return $commandHandler; - } - /** * @return mixed */ diff --git a/src/Commands/sql/SqlCommands.php b/src/Commands/sql/SqlCommands.php index 6ccefd96fd..f3d91f5356 100644 --- a/src/Commands/sql/SqlCommands.php +++ b/src/Commands/sql/SqlCommands.php @@ -8,9 +8,10 @@ use Consolidation\AnnotatedCommand\Hooks\HookManager; use Consolidation\AnnotatedCommand\Input\StdinAwareInterface; use Consolidation\AnnotatedCommand\Input\StdinAwareTrait; +use Consolidation\OutputFormatters\StructuredData\PropertyList; use Consolidation\SiteProcess\Util\Tty; -use Drush\Attributes as CLI; use Drupal\Core\Database\Database; +use Drush\Attributes as CLI; use Drush\Boot\DrupalBootLevels; use Drush\Commands\core\DocsCommands; use Drush\Commands\DrushCommands; @@ -18,7 +19,6 @@ use Drush\Exceptions\UserAbortException; use Drush\Exec\ExecTrait; use Drush\Sql\SqlBase; -use Consolidation\OutputFormatters\StructuredData\PropertyList; use Symfony\Component\Console\Input\InputInterface; final class SqlCommands extends DrushCommands implements StdinAwareInterface @@ -86,7 +86,7 @@ public function connect($options = ['extra' => self::REQ]): string #[CLI\Usage(name: 'drush sql:create --db-su=root --db-su-pw=rootpassword --db-url="mysql://drupal_db_user:drupal_db_password@127.0.0.1/drupal_db"', description: 'Create the database as specified in the db-url option.')] #[CLI\Bootstrap(level: DrupalBootLevels::MAX, max_level: DrupalBootLevels::CONFIGURATION)] #[CLI\OptionsetSql] - public function create($options = ['db-su' => self::REQ, 'db-su-pw' => self::REQ]): void + public function createDb($options = ['db-su' => self::REQ, 'db-su-pw' => self::REQ]): void { $sql = SqlBase::create($options); $db_spec = $sql->getDbSpec(); diff --git a/src/Commands/sql/SqlSyncCommands.php b/src/Commands/sql/SqlSyncCommands.php index e12a0b7faa..cc17dd39b0 100644 --- a/src/Commands/sql/SqlSyncCommands.php +++ b/src/Commands/sql/SqlSyncCommands.php @@ -9,34 +9,32 @@ use Consolidation\SiteAlias\SiteAlias; use Consolidation\SiteAlias\SiteAliasManagerInterface; use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; +use Drush\Commands\AutowireTrait; use Drush\Commands\core\DocsCommands; use Drush\Commands\core\RsyncCommands; use Drush\Commands\core\StatusCommands; use Drush\Commands\DrushCommands; use Drush\Drush; use Drush\Exceptions\UserAbortException; -use League\Container\Container as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Path; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] final class SqlSyncCommands extends DrushCommands { + use AutowireTrait; + const SYNC = 'sql:sync'; public function __construct( + #[Autowire(service: DependencyInjection::SITE_ALIAS_MANAGER)] private readonly SiteAliasManagerInterface $siteAliasManager ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('site.alias.manager'), - ); - - return $commandHandler; - } - /** * Copy DB data from a source site to a target site. Transfers data via rsync. */ diff --git a/src/Drush.php b/src/Drush.php index eb5159125d..a87721b260 100644 --- a/src/Drush.php +++ b/src/Drush.php @@ -5,28 +5,29 @@ namespace Drush; use Composer\InstalledVersions; -use Robo\Runner; -use Robo\Robo; -use Drush\Config\DrushConfig; -use Drush\Boot\BootstrapManager; -use Drush\Boot\Boot; use Consolidation\AnnotatedCommand\AnnotatedCommandFactory; use Consolidation\SiteAlias\SiteAliasInterface; use Consolidation\SiteAlias\SiteAliasManager; use Consolidation\SiteProcess\ProcessBase; use Consolidation\SiteProcess\SiteProcess; +use Drush\Boot\Boot; +use Drush\Boot\BootstrapManager; +use Drush\Config\DrushConfig; +use Drush\Preflight\PreflightArgs; +use Drush\Runtime\DependencyInjection; use Drush\SiteAlias\ProcessManager; use Psr\Log\LoggerInterface; +use Robo\Robo; +use Robo\Runner; use RuntimeException; use Symfony\Component\Console\Application; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; + // TODO: Not sure if we should have a reference to PreflightArgs here. // Maybe these constants should be in config, and PreflightArgs can // reference them from there as well. -use Drush\Preflight\PreflightArgs; -use Symfony\Component\Process\Process; /** * Static Service Container wrapper. @@ -231,7 +232,7 @@ public static function config(): DrushConfig */ public static function aliasManager(): SiteAliasManager { - return self::service('site.alias.manager'); + return self::service(DependencyInjection::SITE_ALIAS_MANAGER); } /** diff --git a/src/Runtime/DependencyInjection.php b/src/Runtime/DependencyInjection.php index 65cb9e5219..7ff4d20469 100644 --- a/src/Runtime/DependencyInjection.php +++ b/src/Runtime/DependencyInjection.php @@ -4,37 +4,40 @@ namespace Drush\Runtime; -use Drush\Formatters\EntityToArraySimplifier; -use Drush\Log\Logger; -use League\Container\Container; -use Symfony\Component\Console\Input\StringInput; -use Symfony\Component\Console\Output\ConsoleOutput; -use Robo\Robo; -use Drush\Formatters\DrushFormatterManager; +use Composer\Autoload\ClassLoader; +use Consolidation\Config\ConfigInterface; +use Consolidation\Config\Util\ConfigOverlay; +use Consolidation\SiteAlias\SiteAliasManager; use Consolidation\SiteAlias\SiteAliasManagerAwareInterface; use Consolidation\SiteProcess\ProcessManagerAwareInterface; +use Drush\Cache\CommandCache; +use Drush\Command\DrushCommandInfoAlterer; use Drush\Command\GlobalOptionsEventListener; +use Drush\Config\DrushConfig; +use Drush\DrupalFinder\DrushDrupalFinder; use Drush\Drush; +use Drush\Formatters\DrushFormatterManager; +use Drush\Formatters\EntityToArraySimplifier; +use Drush\Log\Logger; +use Drush\SiteAlias\ProcessManager; use Drush\Symfony\DrushStyleInjector; -use Drush\Cache\CommandCache; -use Drush\DrupalFinder\DrushDrupalFinder; +use League\Container\Container; +use League\Container\ContainerInterface; +use Robo\Robo; +use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Application; -use Consolidation\Config\ConfigInterface; -use Composer\Autoload\ClassLoader; -use League\Container\ContainerInterface; -use Consolidation\SiteAlias\SiteAliasManager; -use Drush\Command\DrushCommandInfoAlterer; -use Consolidation\Config\Util\ConfigOverlay; -use Drush\Config\DrushConfig; -use Drush\SiteAlias\ProcessManager; /** * Prepare our Dependency Injection Container */ class DependencyInjection { + const SITE_ALIAS_MANAGER = 'site.alias.manager'; + const BOOTSTRAP_MANAGER = 'bootstrap.manager'; + const LOADER = 'loader'; protected array $handlers = []; public function desiredHandlers($handlerList): void @@ -103,8 +106,8 @@ protected function addDrushServices($container, ClassLoader $loader, DrushDrupal ->addMethodCall('setLogOutputStyler', ['logStyler']) ->addMethodCall('add', ['drush', new Logger($output)]); - Robo::addShared($container, 'loader', $loader); - Robo::addShared($container, 'site.alias.manager', $aliasManager); + Robo::addShared($container, self::LOADER, $loader); + Robo::addShared($container, self::SITE_ALIAS_MANAGER, $aliasManager); // Fetch the runtime config, where -D et. al. are stored, and // add a reference to it to the container. @@ -119,17 +122,17 @@ protected function addDrushServices($container, ClassLoader $loader, DrushDrupal // Add some of our own objects to the container Robo::addShared($container, 'service.manager', 'Drush\Runtime\ServiceManager') - ->addArgument('loader') + ->addArgument(self::LOADER) ->addArgument('config') ->addArgument('logger'); Robo::addShared($container, 'bootstrap.drupal8', 'Drush\Boot\DrupalBoot8') ->addArgument('service.manager') - ->addArgument('loader'); - Robo::addShared($container, 'bootstrap.manager', 'Drush\Boot\BootstrapManager') + ->addArgument(self::LOADER); + Robo::addShared($container, self::BOOTSTRAP_MANAGER, 'Drush\Boot\BootstrapManager') ->addMethodCall('setDrupalFinder', [$drupalFinder]) ->addMethodCall('add', ['bootstrap.drupal8']); Robo::addShared($container, 'bootstrap.hook', 'Drush\Boot\BootstrapHook') - ->addArgument('bootstrap.manager'); + ->addArgument(self::BOOTSTRAP_MANAGER); Robo::addShared($container, 'tildeExpansion.hook', 'Drush\Runtime\TildeExpansionHook'); Robo::addShared($container, 'process.manager', ProcessManager::class) ->addMethodCall('setConfig', ['config']) @@ -152,7 +155,7 @@ protected function addDrushServices($container, ClassLoader $loader, DrushDrupal // Add inflectors. @see \Drush\Boot\BaseBoot::inflect $container->inflector(SiteAliasManagerAwareInterface::class) - ->invokeMethod('setSiteAliasManager', ['site.alias.manager']); + ->invokeMethod('setSiteAliasManager', [self::SITE_ALIAS_MANAGER]); $container->inflector(ProcessManagerAwareInterface::class) ->invokeMethod('setProcessManager', ['process.manager']); } @@ -183,8 +186,8 @@ protected function alterServicesForDrush($container, Application $application): protected function injectApplicationServices($container, Application $application): void { $application->setLogger($container->get('logger')); - $application->setBootstrapManager($container->get('bootstrap.manager')); - $application->setAliasManager($container->get('site.alias.manager')); + $application->setBootstrapManager($container->get(self::BOOTSTRAP_MANAGER)); + $application->setAliasManager($container->get(self::SITE_ALIAS_MANAGER)); $application->setRedispatchHook($container->get('redispatch.hook')); $application->setTildeExpansionHook($container->get('tildeExpansion.hook')); $application->setDispatcher($container->get('eventDispatcher')); diff --git a/src/Runtime/ServiceManager.php b/src/Runtime/ServiceManager.php index 1ad4c02f98..09c716c217 100644 --- a/src/Runtime/ServiceManager.php +++ b/src/Runtime/ServiceManager.php @@ -13,6 +13,8 @@ use Consolidation\SiteProcess\ProcessManagerAwareInterface; use Drupal\Component\DependencyInjection\ContainerInterface as DrupalContainer; use DrupalCodeGenerator\Command\BaseGenerator; +use Drush\Attributes\Bootstrap; +use Drush\Boot\DrupalBootLevels; use Drush\Commands\DrushCommands; use Drush\Config\DrushConfig; use Grasmash\YamlCli\Command\GetValueCommand; @@ -105,9 +107,9 @@ public function discover(array $commandfileSearchpath, string $baseNamespace): a [FilterHooks::class] )); - // If a command class has a static `create` method, then we will + // If a command class has a Bootstrap Attribute or static `create` method, we // postpone instantiating it until after we bootstrap Drupal. - $this->bootstrapCommandClasses = array_filter($commandClasses, [$this, 'hasStaticCreateFactory']); + $this->bootstrapCommandClasses = array_filter($commandClasses, [$this, 'requiresBootstrap']); // Remove the command classes that we put into the bootstrap command classes. $commandClasses = array_diff($commandClasses, $this->bootstrapCommandClasses); @@ -313,11 +315,19 @@ public function instantiateServices(array $bootstrapCommandClasses, DrushContain return !$reflection->isAbstract(); }); + // Prevent duplicate calls to delegate() by checking for state. + if ($container && !$drushContainer->has('state')) { + // Combine the two containers. + $drushContainer->delegate($container); + } foreach ($bootstrapCommandClasses as $class) { $commandHandler = null; try { - if ($container && $this->hasStaticCreateFactory($class)) { + if ($this->hasStaticCreateFactory($class) && $this->supportsCompoundContainer($class, $drushContainer)) { + // Hurray, this class is compatible with the container with delegate. + $commandHandler = $class::create($drushContainer); + } elseif ($container && $this->hasStaticCreateFactory($class)) { $commandHandler = $class::create($container, $drushContainer); } elseif (!$container && $this->hasStaticCreateEarlyFactory($class)) { $commandHandler = $class::createEarly($drushContainer); @@ -337,13 +347,18 @@ public function instantiateServices(array $bootstrapCommandClasses, DrushContain return $commandHandlers; } + /** + * Determine if the first parameter of the create method supports our container with delegate. + */ + protected function supportsCompoundContainer($class, $drush_container): bool + { + $reflection = new \ReflectionMethod($class, 'create'); + $hint = (string)$reflection->getParameters()[0]->getType(); + return is_a($drush_container, $hint); + } + /** * Check to see if the provided class has a static `create` method. - * - * @param string $class The name of the class to check - * - * @return bool - * True if class has a static `create` method. */ protected function hasStaticCreateFactory(string $class): bool { @@ -351,26 +366,31 @@ protected function hasStaticCreateFactory(string $class): bool } /** - * Check to see if the provided class has a static `createEarly` method. - * - * @param string $class The name of the class to check - * - * @return bool - * True if class has a static `createEarly` method. + * Does the provided class have a Bootstrap Attribute, indicating early loading. */ - protected function hasStaticCreateEarlyFactory(string $class): bool + protected function hasBootStrapAttributeNone(string $class): bool { - return static::hasStaticMethod($class, 'createEarly'); + try { + $reflection = new \ReflectionClass($class); + if ($attributes = $reflection->getAttributes(Bootstrap::class)) { + $bootstrap = $attributes[0]->newInstance(); + return $bootstrap->level === DrupalBootLevels::NONE; + } + } catch (\ReflectionException $e) { + } + return false; + } + + /** + * Check whether a command class requires Drupal bootstrap. + */ + protected function requiresBootstrap(string $class): bool + { + return $this->hasStaticCreateFactory($class) && !$this->hasBootStrapAttributeNone($class); } /** * Check to see if the provided class has the specified static method. - * - * @param string $class The name of the class to check - * @param string $methodName The name of the method the class should have - * - * @return bool - * True if class has a static method with the specified name. */ protected function hasStaticMethod(string $class, string $methodName): bool { @@ -382,6 +402,19 @@ protected function hasStaticMethod(string $class, string $methodName): bool return $reflectionMethod->isStatic(); } + /** + * Check to see if the provided class has a static `createEarly` method. + * + * @param string $class The name of the class to check + * + * @return bool + * True if class has a static `createEarly` method. + */ + protected function hasStaticCreateEarlyFactory(string $class): bool + { + return static::hasStaticMethod($class, 'createEarly'); + } + /** * Return generators that ship in modules. * @@ -432,7 +465,7 @@ public function inflect(DrushContainer $container, $object): void } // These may be removed in future versions of Drush if ($object instanceof SiteAliasManagerAwareInterface) { - $object->setSiteAliasManager($container->get('site.alias.manager')); + $object->setSiteAliasManager($container->get(DependencyInjection::SITE_ALIAS_MANAGER)); } if ($object instanceof StdinAwareInterface) { $object->setStdinHandler($container->get('stdinHandler')); diff --git a/sut/modules/unish/woot/src/Commands/WootCommands.php b/sut/modules/unish/woot/src/Commands/WootCommands.php index 87544515ef..e71144bf70 100644 --- a/sut/modules/unish/woot/src/Commands/WootCommands.php +++ b/sut/modules/unish/woot/src/Commands/WootCommands.php @@ -6,9 +6,6 @@ use Consolidation\OutputFormatters\StructuredData\RowsOfFields; -/** - * Commandfiles must be listed in a module's drush.services.yml file. - */ class WootCommands { public function __construct(protected string $appRoot) {} diff --git a/sut/modules/unish/woot/src/Drush/CommandInfoAlterers/WootCommandInfoAlterer.php b/sut/modules/unish/woot/src/Drush/CommandInfoAlterers/WootCommandInfoAlterer.php index 1014ac8214..e2cfc6a495 100644 --- a/sut/modules/unish/woot/src/Drush/CommandInfoAlterers/WootCommandInfoAlterer.php +++ b/sut/modules/unish/woot/src/Drush/CommandInfoAlterers/WootCommandInfoAlterer.php @@ -4,14 +4,16 @@ namespace Drupal\woot\Drush\CommandInfoAlterers; -use Drupal\Core\Logger\LoggerChannelInterface; use Consolidation\AnnotatedCommand\CommandInfoAltererInterface; use Consolidation\AnnotatedCommand\Parser\CommandInfo; use Drupal\Core\Logger\LoggerChannelFactoryInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Logger\LoggerChannelInterface; +use Drush\Commands\AutowireTrait; class WootCommandInfoAlterer implements CommandInfoAltererInterface { + use AutowireTrait; + protected LoggerChannelInterface $logger; public function __construct(LoggerChannelFactoryInterface $loggerFactory) @@ -19,15 +21,6 @@ public function __construct(LoggerChannelFactoryInterface $loggerFactory) $this->logger = $loggerFactory->get('drush'); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('logger.factory') - ); - - return $commandHandler; - } - public function alterCommandInfo(CommandInfo $commandInfo, $commandFileInstance) { if ($commandInfo->getName() === 'woot:altered') { diff --git a/sut/modules/unish/woot/src/Drush/Commands/WootStaticFactoryCommands.php b/sut/modules/unish/woot/src/Drush/Commands/WootStaticFactoryCommands.php index 0b2323542d..365316dfd9 100644 --- a/sut/modules/unish/woot/src/Drush/Commands/WootStaticFactoryCommands.php +++ b/sut/modules/unish/woot/src/Drush/Commands/WootStaticFactoryCommands.php @@ -4,10 +4,8 @@ namespace Drupal\woot\Drush\Commands; -use Consolidation\OutputFormatters\StructuredData\RowsOfFields; use Drush\Commands\DrushCommands; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Psr\Container\ContainerInterface as DrushContainer; +use Psr\Container\ContainerInterface; /** * Module commandfiles discovered by virtue of being located in the @@ -27,7 +25,7 @@ protected function __construct($configFactory) $this->configFactory = $configFactory; } - public static function create(ContainerInterface $container, DrushContainer $drush_container): self + public static function create(ContainerInterface $container): self { return new static($container->get('config.factory')); } diff --git a/sut/modules/unish/woot/src/Drush/Generators/ExampleGenerator.php b/sut/modules/unish/woot/src/Drush/Generators/ExampleGenerator.php index 9787c208e5..d41b14b06e 100644 --- a/sut/modules/unish/woot/src/Drush/Generators/ExampleGenerator.php +++ b/sut/modules/unish/woot/src/Drush/Generators/ExampleGenerator.php @@ -4,16 +4,12 @@ namespace Drupal\woot\Drush\Generators; -use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Extension\ModuleInstallerInterface; -use Drupal\Core\Extension\ThemeHandlerInterface; use DrupalCodeGenerator\Asset\AssetCollection as Assets; use DrupalCodeGenerator\Attribute\Generator; use DrupalCodeGenerator\Command\BaseGenerator; use DrupalCodeGenerator\GeneratorType; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drush\Commands\AutowireTrait; #[Generator( name: 'woot:example', @@ -24,6 +20,8 @@ )] class ExampleGenerator extends BaseGenerator { + use AutowireTrait; + /** * Illustrates how to inject a dependency into a Generator. */ @@ -33,15 +31,6 @@ public function __construct( parent::__construct(); } - public static function create(ContainerInterface $container): self - { - $commandHandler = new static( - $container->get('module_handler'), - ); - - return $commandHandler; - } - protected function generate(array &$vars, Assets $assets): void { $ir = $this->createInterviewer($vars); diff --git a/tests/fixtures/drush-extensions/DrushExtensionsCommands.php b/tests/fixtures/drush-extensions/DrushExtensionsCommands.php index e4a592e19e..533d7c501e 100644 --- a/tests/fixtures/drush-extensions/DrushExtensionsCommands.php +++ b/tests/fixtures/drush-extensions/DrushExtensionsCommands.php @@ -4,8 +4,11 @@ namespace Drush\Commands\drush_extensions; +use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; use Drush\Commands\DrushCommands; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] class DrushExtensionsCommands extends DrushCommands { /** diff --git a/tests/fixtures/lib/Drush/Commands/StaticFactoryDrushCommands.php b/tests/fixtures/lib/Drush/Commands/StaticFactoryDrushCommands.php index 00cd54ac8f..14b946adc0 100644 --- a/tests/fixtures/lib/Drush/Commands/StaticFactoryDrushCommands.php +++ b/tests/fixtures/lib/Drush/Commands/StaticFactoryDrushCommands.php @@ -2,32 +2,23 @@ namespace Custom\Library\Drush\Commands; +use Drupal\Core\DrupalKernelInterface; use Drush\Attributes as CLI; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\DrupalKernel; /** * Composer library commandfiles discovered by virtue of being located * in Drush/Commands directory + namespace, relative to some entry in * the library's `autoload` section in its composer.json file. - * - * The static 'create' function (the static factory) is used to - * initialize the command instance, similar to the pattern used - * by Drupal forms. */ class StaticFactoryDrushCommands extends DrushCommands { - protected DrupalKernel $kernel; + use AutowireTrait; - protected function __construct(DrupalKernel $kernel) + protected function __construct(protected DrupalKernelInterface $kernel) { - $this->kernel = $kernel; - } - - public static function create(ContainerInterface $container): self - { - return new static($container->get('kernel')); + parent::__construct(); } #[CLI\Command(name: 'site:path')] diff --git a/tests/functional/Commands/TestFixtureCommands.php b/tests/functional/Commands/TestFixtureCommands.php index 68f192fb1a..8d153e45cb 100644 --- a/tests/functional/Commands/TestFixtureCommands.php +++ b/tests/functional/Commands/TestFixtureCommands.php @@ -11,26 +11,24 @@ use Drupal\Core\DrupalKernel; use Drupal\Core\Site\Settings; +use Drush\Attributes as CLI; +use Drush\Boot\DrupalBootLevels; use Drush\Drush; -use Psr\Container\ContainerInterface as DrushContainer; +use Drush\Runtime\DependencyInjection; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +#[CLI\Bootstrap(DrupalBootLevels::NONE)] class TestFixtureCommands extends DrushCommands { + use AutowireTrait; + protected function __construct( + #[Autowire(service: DependencyInjection::LOADER)] private $autoloader ) { parent::__construct(); } - public static function createEarly(DrushContainer $drush_container): self - { - $commandHandler = new static( - $drush_container->get('loader') - ); - - return $commandHandler; - } - // Obsolete: // unit-invoke // missing-callback diff --git a/tests/unish/UnishTestCase.php b/tests/unish/UnishTestCase.php index cb419e1ae7..9c31b90b36 100644 --- a/tests/unish/UnishTestCase.php +++ b/tests/unish/UnishTestCase.php @@ -8,6 +8,7 @@ use Consolidation\SiteAlias\SiteAlias; use Consolidation\SiteProcess\ProcessManager; use Drupal\Core\Database\Database; +use Drush\Commands\core\SiteInstallCommands; use PHPUnit\Framework\TestCase; use Symfony\Component\Filesystem\Path; use Symfony\Component\Process\Process; @@ -683,7 +684,7 @@ protected function installSut($uri = self::INTEGRATION_TEST_ENV, $optionsFromTes if ($level = $this->logLevel()) { $options[$level] = true; } - $process = $this->processManager()->siteProcess($sutAlias, [self::getDrush(), 'site:install', 'testing', 'install_configure_form.enable_update_status_emails=NULL'], $options); + $process = $this->processManager()->siteProcess($sutAlias, [self::getDrush(), SiteInstallCommands::INSTALL, 'testing', 'install_configure_form.enable_update_status_emails=NULL'], $options); // Set long timeout because Xdebug slows everything. $process->setTimeout(0); $this->process = $process;