Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate Annotated Commands in favor of native Symfony Console commands #6135

Open
wants to merge 49 commits into
base: 13.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2f63ffc
Deprecate AnnotatedCommands in favor of native Symfony Console commands
weitzman Oct 14, 2024
ec1f512
PHPCS and rename directory to just Listeners (was EventListener)
weitzman Oct 14, 2024
47bf610
PHPStan
weitzman Oct 14, 2024
a201b1e
Restore handle() methods on a few Formatter Attribute classes
weitzman Oct 14, 2024
756d384
A few fixes
weitzman Oct 14, 2024
000c215
Remove illegal operation
weitzman Oct 14, 2024
2eeb287
A bit ugly but test has to pass
weitzman Oct 14, 2024
ff65ece
Add --filter option automatically for Console commands. Implementatio…
weitzman Oct 14, 2024
f2f179d
Incorporate into the Trait
weitzman Oct 14, 2024
41a8aa6
Support --filter during execute() of formatter supporting commands
weitzman Oct 15, 2024
141fa70
Convert image:flush to a Console command. Add ValidateEntityLoad list…
weitzman Oct 15, 2024
2eea0de
Deprecate constants
weitzman Oct 15, 2024
68cad77
Inject a new io service when StyleInterface is the type hint
weitzman Oct 15, 2024
b3fbd3a
Add visibility and remove use of dt()
weitzman Oct 15, 2024
a194c59
Use io instead of logger for success messages
weitzman Oct 15, 2024
4a9f239
Deal with a PHPStan failure by aliasing SynfonyStyle to DrushStyle in…
weitzman Oct 15, 2024
e78b50a
in ImageFlushCommand, use choice() and remove the deprecation from it
weitzman Oct 15, 2024
2f42025
Convert sql:dump. Optionsets are provided via a Listener
weitzman Oct 15, 2024
ac5ad80
PHPCS
weitzman Oct 15, 2024
0239f0f
Experiment with static method to add OptionSets
weitzman Oct 16, 2024
8b16ff4
Demonstrate a static method approach for Validators
weitzman Oct 16, 2024
7d6e8ea
Experiment with FormatterOptions via code not Attributes
weitzman Oct 16, 2024
9847b61
Build io when needed - don't get it from the container
weitzman Oct 16, 2024
b9e11f3
Use DI
weitzman Oct 16, 2024
6216ad6
Less magic - commands that format have own execute() with a bit of bo…
weitzman Oct 18, 2024
8d7b2e4
FormatterOptions now has methods we need to deprecate formatting Attr…
weitzman Oct 18, 2024
1a795af
Revert Formatting Attributes and use new fluid syntax for setInput
weitzman Oct 18, 2024
680da18
Start restore of automatic mention of the formatting help topic
weitzman Oct 18, 2024
12e74f8
Pass formattterOptions during configure()
weitzman Oct 20, 2024
74becdc
Simplify ImageFlushCommands a bit
weitzman Oct 20, 2024
6c899f4
Start deprecating a few Attribute classes
weitzman Oct 21, 2024
74b697c
Minor improvements
weitzman Oct 24, 2024
5b55f98
Convert sql:sanitize command. Convert the UserTable sanitizer to a Li…
weitzman Oct 24, 2024
ebd367a
PHPStan fixes
weitzman Oct 24, 2024
34afdc7
Convert to UserTableFields listener. Needed for green
weitzman Oct 24, 2024
f923a80
Introduce writeFormattedOutput() - use in execute()
weitzman Oct 24, 2024
2e75912
Just put validators right into the Command
weitzman Oct 25, 2024
a2b44fd
Lets go with calling Optionset methods statically from configure()
weitzman Oct 25, 2024
b4ed0bf
Experiment with CommandTester - it works
weitzman Oct 25, 2024
58c2ddd
Move the install check to setUp()
weitzman Oct 26, 2024
c1056ed
A bit more experimentation with Applicationtester
weitzman Oct 30, 2024
8f4f573
Delay getting $application because that can make entitytypeManager stale
weitzman Oct 31, 2024
fdfaf0f
Dont store $application in local variable. it gets stale.
weitzman Oct 31, 2024
3712e5d
drush() method is good enough for now
weitzman Oct 31, 2024
f0ffbd9
Docs for Console commands
weitzman Nov 1, 2024
955511e
Merge branch '13.x' into use-command-directly
weitzman Nov 2, 2024
aa21ad9
Convert image:derive
weitzman Nov 2, 2024
8ef8994
Migrate config:set into a Console command
weitzman Nov 2, 2024
b9817b9
Config:get is now a Console command
weitzman Nov 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defaults: &defaults
PHP_EXTENSIONS_DISABLE: xdebug
PHP_XDEBUG_MODE: off

#No longer used
requires: &requires
requires:
- check_mergable
Expand Down Expand Up @@ -173,7 +174,8 @@ workflows:
# - test_80_drupal92_security:
# <<: *requires
- test:
<<: *requires
# Not used, for now.
# <<: *requires
<<: *poststeps
matrix:
parameters:
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"consolidation/annotated-command": "^4.9.2",
"consolidation/config": "^2.1.2 || ^3",
"consolidation/filter-via-dot-access-data": "^2.0.2",
"consolidation/output-formatters": "^4.3.2",
"consolidation/output-formatters": "dev-use-command-directly-of as 4.x-dev",
"consolidation/robo": "^4.0.6 || ^5",
"consolidation/site-alias": "^4",
"consolidation/site-process": "^5.2.0",
Expand Down Expand Up @@ -88,7 +88,8 @@
"config": {
"allow-plugins": {
"composer/installers": true,
"cweagans/composer-patches": true
"cweagans/composer-patches": true,
"symfony/runtime": true
},
"optimize-autoloader": true,
"preferred-install": "dist",
Expand Down
83 changes: 27 additions & 56 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

!!! tip

1. Drush 13 expects commandfiles to use the [AutowireTrait](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 14.
1. Drush 12 expects all commandfiles in the `<module-name>/src/Drush/<Commands|Generators>` directory. The `Drush` subdirectory is a new requirement.
1. Drush 13+ expects commandfiles to use the [AutowireTrait](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 14.
1. Drush 12+ expects all commandfiles in the `<module-name>/src/Drush/<Commands|Generators|Listeners>` directory. The `Drush` subdirectory is a new requirement.

Creating a new Drush command is easy. Follow the steps below.

Expand All @@ -14,67 +14,38 @@ Creating a new Drush command is easy. Follow the steps below.
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/13.x/docs/contribute/unish.md#drush-test-traits).

## Attributes or Annotations
The following are both valid ways to declare a command:

=== "PHP8 Attributes"

```php
use Drush\Attributes as CLI;

/**
* Retrieve and display xkcd cartoons (attribute variant).
*/
#[CLI\Command(name: 'xkcd:fetch-attributes', aliases: ['xkcd-attributes'])]
#[CLI\Argument(name: 'search', description: 'Optional argument to retrieve the cartoons matching an index, keyword, or "random".')]
#[CLI\Option(name: 'image-viewer', description: 'Command to use to view images (e.g. xv, firefox).', suggestedValues: ['open', 'xv', 'firefox'])]
#[CLI\Option(name: 'google-custom-search-api-key', description: 'Google Custom Search API Key')]
#[CLI\Usage(name: 'drush xkcd', description: 'Retrieve and display the latest cartoon')]
#[CLI\Usage(name: 'drush xkcd sandwich', description: 'Retrieve and display cartoons about sandwiches.')]
public function fetch($search = null, $options = ['image-viewer' => 'open', 'google-custom-search-api-key' => 'AIza']) {
$this->doFetch($search, $options);
}
```

=== "Annotations"

```php
/**
* @command xkcd:fetch
* @param $search Optional argument to retrieve the cartoons matching an index number, keyword, or "random".
* @option image-viewer Command to use to view images (e.g. xv, firefox).
* @option google-custom-search-api-key Google Custom Search API Key.
* @usage drush xkcd
* Retrieve and display the latest cartoon.
* @usage drush xkcd sandwich
* Retrieve and display cartoons about sandwiches.
* @aliases xkcd
*/
public function fetch($search = null, $options = ['image-viewer' => 'open', 'google-custom-search-api-key' => 'AIza']) {
$this->doFetch($search, $options);
}
```
## Symfony Console Commands

- A commandfile that will only be used on PHP8+ should [use PHP Attributes](https://github.com/drush-ops/drush/pull/4821) instead of Annotations.
- [See Attributes provided by Drush core](https://www.drush.org/api/Drush/Attributes.html). Custom code can supply additional Attribute classes, which may then be added to any command. For example see [InteractConfigName](https://github.com/drush-ops/drush/blob/13.x/src/Attributes/InteractConfigName.php) which is used by [ConfigCommands](https://github.com/drush-ops/drush/blob/8b77c9abe6639de42a198c7e69565f09dcf5f22d/src/Commands/config/ConfigCommands.php#L98).
Drush 14+ deprecates old-style Annotated Commands in favor of pure [Symfony Console commands](https://symfony.com/doc/current/console.html). This implies:

- Each command lives in its own class file
- The command class extends `Symfony\Component\Console\Command\Command` directly. The base class `DrushCommands` is deprecated.
- The command class should use Console's #[AsCommand] Attribute to declare its name, aliases, and hidden status. The old #[Command] Attribute is deprecated.
- Options and Arguments moved from Attributes to a configure() method on the command class
- The main logic of the command moved to an execute() method on the command class.
- User interaction now happens in an interact() method on the command class.
- Drush and Drupal services may still be autowired. This is how you access the logger. Build own $io as needed.
- Commands that wish to offer multiple _output formats_ (yes please!) should (Example: _TwigUnusedCommand_,
_SqlDumpCommand_):
- inject `FormatterManager` in __construct()
- `use FormatterTrait`
- call `$this->configureFormatter()` in `configure()` in order to automatically add the needed options.
- `execute()` is boilerplate. By convention, do your work in a `doExecute()` method instead.
- [See Optionsets provided by Drush core](https://github.com/drush-ops/drush/blob/13.x/src/Commands/OptionsSets.php). Custom code can supply additional Optionset methods, which any command may choose to use.

## Altering Command Info
Drush command info (annotations/attributes) can be altered from other modules. This is done by creating and registering _command info alterers_. Alterers are classes that are able to intercept and manipulate an existing command annotation.

In the module that wants to alter a command info, add a class that:
Drush command info can be altered from other modules. This is done by creating and registering a command definition listener. Listeners are dispatched once after non-bootstrap commands are instantiated and once again after bootstrap commands are instantiated.

1. The class namespace, relative to base namespace, should be `Drupal\<module-name>\Drush\CommandInfoAlterers` and the class file should be located under the `src/Drush/CommandInfoAlterers` directory.
1. The filename must have a name like FooCommandInfoAlterer.php. The prefix `Foo` can be whatever string you want. The file must end in `CommandInfoAlterer.php`.
1. The class must implement the `\Consolidation\AnnotatedCommand\CommandInfoAltererInterface`.
1. Implement the alteration logic in the `alterCommandInfo()` method.
1. Along with the alter code, it's strongly recommended to log a debug message explaining what exactly was altered. This makes things easier on others who may need to debug the interaction of the alter code with other modules. Also it's a good practice to inject the the logger in the class constructor.

For an example, see [WootCommandInfoAlterer](https://github.com/drush-ops/drush/blob/13.x/sut/modules/unish/woot/src/Drush/CommandInfoAlterers/WootCommandInfoAlterer.php) provided by the testing 'woot' module.
In the module that wants to alter a command info, add a class that:

## Symfony Console Commands
1. The class namespace, relative to base namespace, should be `Drupal\<module-name>\Drush\Listeners` and the class file should be located under the `src/Drush/Listeners` directory.
1. The filename must have a name like FooListener.php. The prefix `Foo` can be whatever string you want. The file must end in `Listener.php`.
1. The class should implement the `#[AsListener]` PHP Attribute.
1. Implement the alteration logic via a `__invoke(ConsoleDefinitionsEvent $event)` method.
1. Along with the alter code, it's strongly recommended to log a debug message explaining what exactly was altered. This makes things easier on others who may need to debug the interaction of the alter code with other modules. Also it's a good practice to inject the logger in the class constructor.

Drush lists and runs Symfony Console commands, in addition to more typical annotated commands.
See [GreetCommands](https://github.com/drush-ops/drush/blob/13.x/sut/modules/unish/woot/src/Drush/Commands/GreetCommands.php) as an example. Note that these commands must conform to the usual class name and class namespace requirements. You might need to extend the Console class if you can't rename and move it.
For an example, see [WootDefinitionListener](https://github.com/drush-ops/drush/blob/13.x/sut/modules/unish/woot/src/Drush/Liseners/WootDefinitionListener.php) provided by the testing 'woot' module.

## Auto-discovered commands (PSR4)

Expand Down
3 changes: 1 addition & 2 deletions src-symfony-compatibility/v6/Style/DrushStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ public function confirm(string $question, bool $default = true, string $yes = 'Y
return confirm($question, $default, $yes, $no, $required, $validate, $hint);
}

#[Deprecated('Use select() or multiselect() instead.')]
public function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false, int $scroll = 10, ?\Closure $validate = null, string $hint = '', bool|string $required = true): mixed
public function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false, int $scroll = 15, ?\Closure $validate = null, string $hint = '', bool|string $required = true): mixed
{
if ($multiSelect) {
// For backward compat. Deprecated.
Expand Down
36 changes: 36 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Drush\Boot\DrupalBootLevels;
use Drush\Command\RemoteCommandProxy;
use Drush\Config\ConfigAwareTrait;
use Drush\Event\ConsoleDefinitionsEvent;
use Drush\Runtime\RedispatchHook;
use Drush\Runtime\ServiceManager;
use Drush\Runtime\TildeExpansionHook;
Expand Down Expand Up @@ -309,6 +310,8 @@ public function configureAndRegisterCommands(InputInterface $input, OutputInterf
// any of the configuration steps we do here.
$this->configureIO($input, $output);

$this->addListeners($commandfileSearchpath);

// Directly add the yaml-cli commands.
$this->addCommands($this->serviceManager->instantiateYamlCliCommands());

Expand All @@ -327,6 +330,9 @@ public function configureAndRegisterCommands(InputInterface $input, OutputInterf
// Note that Robo::register can accept either Annotated Command
// command handlers or Symfony Console Command objects.
Robo::register($this, $commandInstances);

// Dispatch our custom event. It also fires later in \Drush\Boot\DrupalBoot8::bootstrapDrupalFull.
Drush::getContainer()->get('eventDispatcher')->dispatch(new ConsoleDefinitionsEvent($this), ConsoleDefinitionsEvent::class);
}

/**
Expand All @@ -338,4 +344,34 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void

$this->doRenderThrowable($e, $output);
}

// Discover event listeners, and add those that do not require bootstrap.
protected function addListeners($commandfileSearchpath): void
{
$listenerClasses = $this->serviceManager->discoverListeners($commandfileSearchpath, '\Drush');
$listenerClasses = $this->serviceManager->filterListeners($listenerClasses);
$this->serviceManager->addListeners($listenerClasses, Drush::getContainer());
}

/**
* Remove a command. Initially used by WootDefinitionListener and its test.
*
* An alternative would be console.excluded https://github.com/search?q=repo%3AHuttopia%2Fconsole-bundle%20console.excluded&type=code
*/
public function remove(string $id): void
{
$rf = new \ReflectionProperty(\Symfony\Component\Console\Application::class, 'commands');
$rf->setAccessible(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super excited to do this outside of tests. Is this for some sort of "alter" hook? If we want to do this, maybe we should, during preflight, add commands to some other list and provide a specific hook to alter that before adding to the application. That might be complicated, since today we add in two steps (commands from modules being added later).

Alternately, instead of removing a command, maybe we could change its name, remove its aliases and hide it?

I'm not sure why I think that setAccissible is worse than that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add commands to some other list and provide a specific hook to alter that before adding to the application

I think thats more more easily done once we use a container to store commands and maybe use a CommandLoader. Yes, this is just used by Woot today - we can remove it if it offends the eyes.

$commands = $rf->getValue($this);
unset($commands[$id]);
$rf->setValue($this, $commands);
}

/**
* A base URL for help.
*/
public function getDocsBaseUrl(): string
{
return 'https://www.drush.org/latest';
}
}
2 changes: 2 additions & 0 deletions src/Attributes/DefaultFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Drush\Attributes;

use Attribute;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Call \Drush\Formatters\FormatterTrait::configureFormatter during configure()')]
#[Attribute(Attribute::TARGET_METHOD)]
class DefaultFields extends \Consolidation\AnnotatedCommand\Attributes\DefaultFields
{
Expand Down
2 changes: 2 additions & 0 deletions src/Attributes/DefaultTableFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Drush\Attributes;

use Attribute;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Call \Drush\Formatters\FormatterTrait::configureFormatter during configure()')]
#[Attribute(Attribute::TARGET_METHOD)]
class DefaultTableFields extends \Consolidation\AnnotatedCommand\Attributes\DefaultTableFields
{
Expand Down
2 changes: 2 additions & 0 deletions src/Attributes/FieldLabels.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Drush\Attributes;

use Attribute;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Call \Drush\Formatters\FormatterTrait::configureFormatter during configure()')]
#[Attribute(Attribute::TARGET_METHOD)]
class FieldLabels extends \Consolidation\AnnotatedCommand\Attributes\FieldLabels
{
Expand Down
2 changes: 1 addition & 1 deletion src/Attributes/FilterDefaultField.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class FilterDefaultField extends \Consolidation\AnnotatedCommand\Attributes\FilterDefaultField
{
}
1 change: 0 additions & 1 deletion src/Attributes/Format.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Drush\Boot\Kernels;
use JetBrains\PhpStorm\ExpectedValues;

#[Attribute(Attribute::TARGET_METHOD)]
Expand Down
4 changes: 3 additions & 1 deletion src/Attributes/OptionsetSql.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Commands\DrushCommands;
use JetBrains\PhpStorm\Deprecated;

#[Attribute(Attribute::TARGET_METHOD)]
#[Deprecated(replacement: 'Directly add options by calling \Drush\Commands\OptionSets::sql during configure()')]
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class OptionsetSql
{
public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
Expand Down
3 changes: 2 additions & 1 deletion src/Attributes/OptionsetTableSelection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Commands\DrushCommands;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Call \Drush\Commands\OptionSets::tableSelection during configure()')]
#[Attribute(Attribute::TARGET_METHOD)]
class OptionsetTableSelection
{
Expand All @@ -18,7 +20,6 @@ public static function handle(\ReflectionAttribute $attribute, CommandInfo $comm
$commandInfo->addOption('tables-key', 'A key in the $tables array.', [], DrushCommands::REQ);
$commandInfo->addOption('skip-tables-list', 'A comma-separated list of tables to exclude completely.', [], DrushCommands::REQ);
$commandInfo->addOption('structure-tables-list', 'A comma-separated list of tables to include for structure, but not data.', [], DrushCommands::REQ);
$commandInfo->addOption('skip-tables-list', 'A comma-separated list of tables to exclude completely.', [], DrushCommands::REQ);
$commandInfo->addOption('tables-list', 'A comma-separated list of tables to transfer.', [], DrushCommands::REQ);
}
}
2 changes: 1 addition & 1 deletion src/Attributes/Topics.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Topics extends \Consolidation\AnnotatedCommand\Attributes\Topics
{
}
2 changes: 2 additions & 0 deletions src/Attributes/ValidateEntityLoad.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Drush\Utils\StringUtils;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Copy \Drush\Commands\core\ImageFlushCommand::validateEntityLoad into command and call during execute()')]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we maybe use a command hook to find and dispatch validate hooks?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have experimented with that approach earlier in this PR and can't decide whats best. Currently the validation is done right in execute() and isn't not DRY. See ImageFlushCommand. Compare with https://github.com/drush-ops/drush/blob/f923a801dd50d4aa17fd2390790336bc962785a3/src/Listeners/ValidateModulesEnabledListener.php and its associated Attribute. IMO the current approach is less magical and I'm slightly valuing that these days.

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateEntityLoad extends ValidatorBase implements ValidatorInterface
{
Expand Down
2 changes: 2 additions & 0 deletions src/Attributes/ValidateFileExists.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Attribute;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Copy \Drush\Commands\core\ImageDeriveCommand::validateFileExists into command and call during execute()')]
#[Attribute(Attribute::TARGET_METHOD)]
class ValidateFileExists extends ValidatorBase implements ValidatorInterface
{
Expand Down
2 changes: 2 additions & 0 deletions src/Attributes/ValidateModulesEnabled.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Attribute;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use JetBrains\PhpStorm\Deprecated;

#[Deprecated(replacement: 'Copy \Drush\Commands\core\ImageFlushCommand::validateModulesEnabled into command and call during execute()')]
#[Attribute(Attribute::TARGET_METHOD)]
class ValidateModulesEnabled extends ValidatorBase implements ValidatorInterface
{
Expand Down
24 changes: 22 additions & 2 deletions src/Boot/DrupalBoot8.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
use Drush\Config\ConfigLocator;
use Drush\Drupal\DrushLoggerServiceProvider;
use Drush\Drush;
use Drush\Event\ConsoleDefinitionsEvent;
use Drush\Runtime\LegacyServiceFinder;
use Drush\Runtime\LegacyServiceInstantiator;
use Drush\Runtime\ServiceManager;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Robo\Robo;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -215,12 +214,20 @@ public function bootstrapDrupalFull(BootstrapManager $manager): void
// Directly add the Drupal core bootstrapped commands.
Drush::getApplication()->addCommands($this->serviceManager->instantiateDrupalCoreBootstrappedCommands());

$this->addBootstrapListeners();

$this->addDrupalModuleDrushCommands($manager);

// Dispatch our custom event. It also fires earlier in \Drush\Application::configureAndRegisterCommands.
Drush::getContainer()->get('eventDispatcher')->dispatch(new ConsoleDefinitionsEvent(Drush::getApplication()), ConsoleDefinitionsEvent::class);

// Set a default account to make sure the correct timezone is set
$this->kernel->getContainer()->get('current_user')->setAccount(new AnonymousUserSession());
}

/**
* Adds module supplied commands, as well as Drush Console commands that require bootstrap.
*/
public function addDrupalModuleDrushCommands(BootstrapManager $manager): void
{
$application = Drush::getApplication();
Expand Down Expand Up @@ -323,4 +330,17 @@ public function bootstrapDrupalSite(BootstrapManager $manager)
{
$this->bootstrapDoDrupalSite($manager);
}

// Add the Listeners that require bootstrap.
public function addBootstrapListeners(): void
{
$listenersInThisModule = [];
$moduleHandler = \Drupal::moduleHandler();
foreach ($moduleHandler->getModuleList() as $moduleId => $extension) {
$path = DRUPAL_ROOT . '/' . $extension->getPath() . '/src/Drush';
$listenersInThisModule = array_merge($listenersInThisModule, $this->serviceManager->discoverListeners([$path], "\Drupal\\$moduleId\Drush"));
}
$classes = $this->serviceManager->bootstrapListenerClasses();
$this->serviceManager->addListeners(array_merge($listenersInThisModule, $classes), Drush::getContainer(), \Drupal::getContainer());
}
}
2 changes: 0 additions & 2 deletions src/Commands/AutowireTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ trait AutowireTrait
*
* @param ContainerInterface $container
* The service container this instance should use.
*
* @return static
*/
public static function create(ContainerInterface $container)
{
Expand Down
Loading