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 39 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
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/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
27 changes: 27 additions & 0 deletions src/Commands/OptionSets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Drush\Commands;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;

class OptionSets
{
public static function sql(Command $command): void
{
$command->addOption('database', '', InputOption::VALUE_REQUIRED, 'The DB connection key if using multiple connections in settings.php.', 'default');
$command->addOption('db-url', '', InputOption::VALUE_REQUIRED, 'A Drupal 6 style database URL. For example <info>mysql://root:pass@localhost:port/dbname</info>');
$command->addOption('target', '', InputOption::VALUE_REQUIRED, 'The name of a target within the specified database connection.', 'default');
$command->addOption('show-passwords', '', InputOption::VALUE_NONE, 'Show password on the CLI. Useful for debugging.');
}

public static function tableSelection(Command $command): void
{
$command->addOption('skip-tables-key', '', InputOption::VALUE_REQUIRED, 'A key in the $skip_tables array. @see [Site aliases](../site-aliases.md)');
$command->addOption('structure-tables-key', '', InputOption::VALUE_REQUIRED, 'A key in the $structure_tables array. @see [Site aliases](../site-aliases.md)');
$command->addOption('tables-key', '', InputOption::VALUE_REQUIRED, 'A key in the $tables array.');
$command->addOption('skip-tables-list', '', InputOption::VALUE_REQUIRED, 'A comma-separated list of tables to exclude completely.');
$command->addOption('structure-tables-list', '', InputOption::VALUE_REQUIRED, 'A comma-separated list of tables to include for structure, but not data.');
$command->addOption('tables-list', '', InputOption::VALUE_REQUIRED, 'A comma-separated list of tables to transfer.', []);
}
}
4 changes: 2 additions & 2 deletions src/Commands/core/CoreCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace Drush\Commands\core;

use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Drush\Drush;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\Options\FormatterOptions;

final class CoreCommands extends DrushCommands
{
Expand Down
58 changes: 4 additions & 54 deletions src/Commands/core/ImageCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,17 @@

namespace Drush\Commands\core;

use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Drupal\image\Entity\ImageStyle;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Drush\Utils\StringUtils;
use Symfony\Component\Console\Input\InputInterface;
use Drush\Boot\DrupalBootLevels;
use Drush\Commands\DrushCommands;
use JetBrains\PhpStorm\Deprecated;

final class ImageCommands extends DrushCommands
{
const FLUSH = 'image:flush';
const DERIVE = 'image:derive';

/**
* Flush all derived images for a given style.
*/
#[CLI\Command(name: self::FLUSH, aliases: ['if', 'image-flush'])]
#[CLI\Argument(name: 'style_names', description: 'A comma delimited list of image style machine names. If not provided, user may choose from a list of names.')]
#[CLI\Option(name: 'all', description: 'Flush all derived images')]
#[CLI\Usage(name: 'drush image:flush', description: 'Pick an image style and then delete its derivatives.')]
#[CLI\Usage(name: 'drush image:flush thumbnail,large', description: 'Delete all thumbnail and large derivatives.')]
#[CLI\Usage(name: 'drush image:flush --all', description: 'Flush all derived images. They will be regenerated on demand.')]
#[CLI\ValidateEntityLoad(entityType: 'image_style', argumentName: 'style_names')]
#[CLI\ValidateModulesEnabled(modules: ['image'])]
#[CLI\Bootstrap(level: DrupalBootLevels::FULL)]
public function flush($style_names, $options = ['all' => false]): void
{
foreach (ImageStyle::loadMultiple(StringUtils::csvToArray($style_names)) as $style_name => $style) {
$style->flush();
$this->logger()->success(dt('Image style !style_name flushed', ['!style_name' => $style_name]));
}
}

#[CLI\Hook(type: HookManager::INTERACT, target: self::FLUSH)]
public function interactFlush(InputInterface $input, $output): void
{
$styles = array_keys(ImageStyle::loadMultiple());
$style_names = $input->getArgument('style_names');

if (empty($style_names)) {
$styles_all = $styles;
array_unshift($styles_all, 'all');
$choices = array_combine($styles_all, $styles_all);
$style_names = $this->io()->select(dt("Choose a style to flush"), $choices, 'all', scroll: 20);
if ($style_names == 'all') {
$style_names = implode(',', $styles);
}
$input->setArgument('style_names', $style_names);
}
}

#[CLI\Hook(type: HookManager::POST_INITIALIZE, target: self::FLUSH)]
public function postInit(InputInterface $input, AnnotationData $annotationData): void
{
// Needed for non-interactive calls.We use post-init phase because interact() methods run early
if ($input->getOption('all')) {
$styles = array_keys(ImageStyle::loadMultiple());
$input->setArgument('style_names', implode(",", $styles));
}
}
#[Deprecated(replacement: 'ImageFlushCommand::NAME')]
const FLUSH = ImageFlushCommand::NAME;

/**
* Create an image derivative.
Expand Down
Loading