Skip to content

Commit

Permalink
Stop using SiteAliasAwareInterface (#5877)
Browse files Browse the repository at this point in the history
  • Loading branch information
weitzman authored Feb 22, 2024
1 parent fede207 commit f425f35
Show file tree
Hide file tree
Showing 20 changed files with 360 additions and 256 deletions.
75 changes: 5 additions & 70 deletions docs/dependency-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,13 @@ 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.

Types of Injection
-----------------------

There are two ways that a class can receive its dependencies. One is called “constructor injection”, and the other is called “setter injection”.

*Example of constructor injection:*
```php
public function __construct(DependencyType $service)
{
$this->service = $service;
}
```

*Example of setter injection:*
```php
public function setService(DependencyType $service)
{
$this->service = $service;
}
```
The code that is responsible for providing the dependencies a class needs is usually an object called the dependency injection container.

create() method
------------------
:octicons-tag-24: 11.6+

!!! 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 will be removed in Drush 13.
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.

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:
```php
Expand Down Expand Up @@ -69,51 +47,8 @@ mechanism is only usable by PSR-4 discovered commands packaged with Composer
projects that are *not* Drupal modules.

Inflection
-------------

!!! tip

Inflection is deprecated in Drush 12; use `create()` or `createEarly()` instead.
Some classes are no longer available for inflection in Drush 12, and more (or potentially all)
may be removed in Drush 13.

Drush will also inject dependencies that it provides using a technique called inflection. Inflection is a kind of dependency injection that works by way of a set of provided inflection interfaces, one for each available service. Each of these interfaces will define one or more setter methods (usually only one); these will automatically be called by Drush when the commandfile object is instantiated. The command only needs to implement this method and save the provided object in a class field. There is usually a corresponding trait that may be included via a `use` statement to fulfill this requirement.

For example:

```php
<?php
namespace Drupal\my_module\Commands;

use Drush\Commands\DrushCommands;
use Consolidation\OutputFormatters\StructuredData\ListDataFromKeys;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;

class MyModuleCommands extends DrushCommands implements SiteAliasManagerAwareInterface
{
use SiteAliasManagerAwareTrait;

/**
* Prints the current alias name and info.
*/
#[CLI\Command(name: 'mymodule:myAlias')]
public function myAlias(): ListDataFromKeys
{
$selfAlias = $this->siteAliasManager()->getSelf();
$this->logger()->success(‘The current alias is {name}’, [‘name’ => $selfAlias]);
return new ListDataFromKeys($aliasRecord->export());
}
}
```

All Drush command files extend DrushCommands. DrushCommands implements ConfigAwareInterface, IOAwareInterface, LoggerAwareInterface, which gives access to `$this->getConfig()`, `$this->logger()` and other ways to do input and output. See the [IO documentation](io.md) for more information.

Any additional services that are desired must be injected by implementing the appropriate inflection interface.

Additional Interfaces:

- SiteAliasManagerAwareInterface: The site alias manager [allows alias records to be obtained](site-alias-manager.md).
- CustomEventAwareInterface: Allows command files to [define and fire custom events](hooks.md) that other command files can hook.
-----------------
A command class may implement the following interfaces. When doing so, implement the corresponding trait to satisfy the interface.

Note that although the autoloader and Drush dependency injection container is available and may be injected into your command file if needed, this should be avoided. Favor using services that can be injected from Drupal or Drush. Some of the objects in the container are not part of the Drush public API, and may not maintain compatibility in minor and patch releases.
- [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)
23 changes: 18 additions & 5 deletions examples/Commands/SiteAliasAlterCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,38 @@

use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;
use Consolidation\SiteAlias\SiteAliasManagerInterface;
use Drush\Attributes as CLI;
use League\Container\Container as DrushContainer;
use Symfony\Component\Console\Input\InputInterface;

/**
* Load this example by using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/
class SiteAliasAlterCommands extends DrushCommands implements SiteAliasManagerAwareInterface
class SiteAliasAlterCommands extends DrushCommands
{
use SiteAliasManagerAwareTrait;
public function __construct(
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.
*/
#[CLI\Hook(type: HookManager::PRE_INITIALIZE, target: '*')]
public function alter(InputInterface $input, AnnotationData $annotationData)
{
$self = $this->siteAliasManager()->getSelf();
$self = $this->siteAliasManager->getSelf();
if ($self->isRemote()) {
// Always pass along ssh keys.
if (!$self->has('ssh.options')) {
Expand Down
26 changes: 13 additions & 13 deletions src/Commands/config/ConfigCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,41 @@

namespace Drush\Commands\config;

use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Drupal\Core\Config\ConfigDirectoryNotDefinedException;
use Drupal\Core\Config\ImportStorageTransformer;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\AnnotatedCommand\Input\StdinAwareInterface;
use Consolidation\AnnotatedCommand\Input\StdinAwareTrait;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;
use Consolidation\SiteAlias\SiteAliasManagerInterface;
use Consolidation\SiteProcess\Util\Escape;
use Drupal\Core\Config\ConfigDirectoryNotDefinedException;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\ImportStorageTransformer;
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\Drush;
use Drush\Exec\ExecTrait;
use Drush\SiteAlias\SiteAliasManagerAwareInterface;
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\Filesystem\Path;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\DependencyInjection\ContainerInterface;

final class ConfigCommands extends DrushCommands implements StdinAwareInterface, SiteAliasManagerAwareInterface
final class ConfigCommands extends DrushCommands implements StdinAwareInterface
{
use StdinAwareTrait;
use ExecTrait;
use SiteAliasManagerAwareTrait;

const INTERACT_CONFIG_NAME = 'interact-config-name';
const VALIDATE_CONFIG_NAME = 'validate-config-name';
Expand All @@ -58,16 +57,17 @@ public function getConfigFactory(): ConfigFactoryInterface
return $this->configFactory;
}

protected function __construct(protected ConfigFactoryInterface $configFactory, protected StorageInterface $configStorage)
protected function __construct(protected ConfigFactoryInterface $configFactory, protected StorageInterface $configStorage, protected SiteAliasManagerInterface $siteAliasManager)
{
parent::__construct();
}

public static function create(ContainerInterface $container): self
public static function create(ContainerInterface $container, Container $drush_container): self
{
$commandHandler = new static(
$container->get('config.factory'),
$container->get('config.storage')
$container->get('config.storage'),
$drush_container->get('site.alias.manager')
);

if ($container->has('config.storage.export')) {
Expand Down Expand Up @@ -242,7 +242,7 @@ public function edit($config_name, $options = []): void
// Perform import operation if user did not immediately exit editor.
if (!$options['bg']) {
$redispatch_options = Drush::redispatchOptions() + ['strict' => 0, 'partial' => true, 'source' => $temp_dir];
$self = $this->siteAliasManager()->getSelf();
$self = $this->siteAliasManager->getSelf();
$process = $this->processManager()->drush($self, ConfigImportCommands::IMPORT, [], $redispatch_options);
$process->mustRun($process->showRealtime());
}
Expand Down
35 changes: 24 additions & 11 deletions src/Commands/config/ConfigPullCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,35 @@

use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\SiteAlias\HostPath;
use Consolidation\SiteAlias\SiteAliasManagerInterface;
use Drush\Attributes as CLI;
use Drush\Commands\core\DocsCommands;
use Drush\Commands\core\RsyncCommands;
use Drush\Commands\DrushCommands;
use Drush\Drush;
use Consolidation\SiteAlias\HostPath;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use League\Container\Container as DrushContainer;

final class ConfigPullCommands extends DrushCommands implements SiteAliasManagerAwareInterface
final class ConfigPullCommands extends DrushCommands
{
use SiteAliasManagerAwareTrait;

const PULL = 'config:pull';

public function __construct(
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.
*/
Expand All @@ -37,7 +50,7 @@ final class ConfigPullCommands extends DrushCommands implements SiteAliasManager
public function pull(string $source, string $destination, array $options = ['safe' => false, 'runner' => null, 'format' => 'null']): PropertyList
{
$global_options = Drush::redispatchOptions() + ['strict' => 0];
$sourceRecord = $this->siteAliasManager()->get($source);
$sourceRecord = $this->siteAliasManager->get($source);

$export_options = [
// Use the standard backup directory on Destination.
Expand All @@ -61,11 +74,11 @@ public function pull(string $source, string $destination, array $options = ['saf
if (!str_contains($destination, ':')) {
$destination .= ':%config-sync';
}
$destinationHostPath = HostPath::create($this->siteAliasManager(), $destination);
$destinationHostPath = HostPath::create($this->siteAliasManager, $destination);

if (!$runner = $options['runner']) {
$destinationRecord = $destinationHostPath->getSiteAlias();
$runner = $sourceRecord->isRemote() && $destinationRecord->isRemote() ? $destinationRecord : $this->siteAliasManager()->getSelf();
$runner = $sourceRecord->isRemote() && $destinationRecord->isRemote() ? $destinationRecord : $this->siteAliasManager->getSelf();
}
$this->logger()
->notice(dt('Starting to rsync configuration files from !source to !dest.', [
Expand All @@ -87,7 +100,7 @@ public function pull(string $source, string $destination, array $options = ['saf
public function validateConfigPull(CommandData $commandData): void
{
if ($commandData->input()->getOption('safe')) {
$destinationRecord = $this->siteAliasManager()->get($commandData->input()->getArgument('destination'));
$destinationRecord = $this->siteAliasManager->get($commandData->input()->getArgument('destination'));
$process = $this->processManager()->siteProcess($destinationRecord, ['git', 'diff', '--quiet']);
$process->chdirToSiteRoot();
$process->run();
Expand Down
Loading

0 comments on commit f425f35

Please sign in to comment.