Skip to content

Commit

Permalink
Attribute also does the validate (#5818)
Browse files Browse the repository at this point in the history
  • Loading branch information
weitzman authored Dec 27, 2023
1 parent 0a7eecd commit 3bcabf4
Show file tree
Hide file tree
Showing 15 changed files with 172 additions and 43 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"composer-runtime-api": "^2.2",
"chi-teck/drupal-code-generator": "^3.0",
"composer/semver": "^1.4 || ^3",
"consolidation/annotated-command": "^4.9.1",
"consolidation/annotated-command": "^4.9.2",
"consolidation/config": "^2.1.2",
"consolidation/filter-via-dot-access-data": "^2.0.2",
"consolidation/output-formatters": "^4.3.2",
Expand Down
16 changes: 8 additions & 8 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/Attributes/HookSelector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Attribute;

#[Deprecated('Create an Attribute class that commands can use.')]
#[Attribute(Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class HookSelector extends \Consolidation\AnnotatedCommand\Attributes\HookSelector
{
Expand Down
15 changes: 10 additions & 5 deletions src/Attributes/ValidateConfigName.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Commands\config\ConfigCommands;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateConfigName
class ValidateConfigName extends ValidatorBase implements ValidatorInterface
{
/**
* @param string $argumentName
Expand All @@ -20,8 +20,13 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$commandInfo->addAnnotation(ConfigCommands::VALIDATE_CONFIG_NAME, $attribute->newInstance()->argumentName);
$configName = $commandData->input()->getArgument($this->argumentName);
$config = \Drupal::config($configName);
if ($config->isNew()) {
$msg = dt('Config !name does not exist', ['!name' => $configName]);
return new CommandError($msg);
}
}
}
17 changes: 11 additions & 6 deletions src/Attributes/ValidateEntityLoad.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Commands\ValidatorsCommands;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Drush\Utils\StringUtils;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateEntityLoad
class ValidateEntityLoad extends ValidatorBase implements ValidatorInterface
{
/**
* @param $entityType
Expand All @@ -23,9 +24,13 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation(ValidatorsCommands::VALIDATE_ENTITY_LOAD, "{$args['entityType']} {$args['argumentName']}");
$names = StringUtils::csvToArray($commandData->input()->getArgument($this->argumentName));
$loaded = \Drupal::entityTypeManager()->getStorage($this->entityType)->loadMultiple($names);
if ($missing = array_diff($names, array_keys($loaded))) {
$msg = dt('Unable to load the !type: !str', ['!type' => $this->entityType, '!str' => implode(', ', $missing)]);
return new CommandError($msg);
}
}
}
24 changes: 19 additions & 5 deletions src/Attributes/ValidateFileExists.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateFileExists
class ValidateFileExists extends ValidatorBase implements ValidatorInterface
{
/**
* @param $argName
Expand All @@ -19,9 +20,22 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('validate-file-exists', $args['argName']);
$missing = [];
$argName = $this->argName;
if ($commandData->input()->hasArgument($argName)) {
$path = $commandData->input()->getArgument($argName);
} elseif ($commandData->input()->hasOption($argName)) {
$path = $commandData->input()->getOption($argName);
}
if (!empty($path) && !file_exists($path)) {
$missing[] = $path;
}

if ($missing) {
$msg = dt('File(s) not found: !paths', ['!paths' => implode(', ', $missing)]);
return new CommandError($msg);
}
}
}
14 changes: 9 additions & 5 deletions src/Attributes/ValidateModulesEnabled.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateModulesEnabled
class ValidateModulesEnabled extends ValidatorBase implements ValidatorInterface
{
/**
* @param $modules
Expand All @@ -19,9 +20,12 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('validate-module-enabled', $args['modules'] ?? $args[0]);
$missing = array_filter($this->modules, fn($module) => !\Drupal::moduleHandler()->moduleExists($module));
if ($missing) {
$msg = dt('The following modules are required: !modules', ['!modules' => implode(', ', $missing)]);
return new CommandError($msg);
}
}
}
23 changes: 18 additions & 5 deletions src/Attributes/ValidatePermissions.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Drush\Utils\StringUtils;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidatePermissions
class ValidatePermissions extends ValidatorBase implements ValidatorInterface
{
/**
* @param $argName
Expand All @@ -19,9 +21,20 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('validate-permissions', $args['argName']);
$missing = [];
$arg_or_option_name = $this->argName;
if ($commandData->input()->hasArgument($arg_or_option_name)) {
$permissions = StringUtils::csvToArray($commandData->input()->getArgument($arg_or_option_name));
} else {
$permissions = StringUtils::csvToArray($commandData->input()->getOption($arg_or_option_name));
}
$all_permissions = array_keys(\Drupal::service('user.permissions')->getPermissions());
$missing = array_diff($permissions, $all_permissions);
if ($missing) {
$msg = dt('Permission(s) not found: !perms', ['!perms' => implode(', ', $missing)]);
return new CommandError($msg);
}
}
}
14 changes: 9 additions & 5 deletions src/Attributes/ValidatePhpExtensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidatePhpExtensions
class ValidatePhpExtensions extends ValidatorBase implements ValidatorInterface
{
/**
* @param $extensions
Expand All @@ -19,9 +20,12 @@ public function __construct(
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
public function validate(CommandData $commandData)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('validate-php-extension', $args['extensions'] ?? $args[0]);
$missing = array_filter($this->extensions, fn($extension) => !extension_loaded($extension));
if ($missing) {
$msg = dt('The following PHP extensions are required: !extensions', ['!extensions' => implode(', ', $missing)]);
return new CommandError($msg);
}
}
}
36 changes: 36 additions & 0 deletions src/Attributes/ValidateQueueName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
class ValidateQueueName extends ValidatorBase implements ValidatorInterface
{
/**
* @param string $argumentName
* The name of the argument which specifies the queue name.
*/
public function __construct(
public string $argumentName = 'queue_name'
) {
}

public function validate(CommandData $commandData)
{
$queueName = $commandData->input()->getArgument($this->argumentName);
if (!in_array($queueName, self::getQueues())) {
$msg = dt('Queue not found: !name', ['!name' => $queueName]);
return new CommandError($msg);
}
}

public static function getQueues(): array
{
return array_keys(\Drupal::service('plugin.manager.queue_worker')->getDefinitions());
}
}
25 changes: 25 additions & 0 deletions src/Attributes/ValidatorBase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Drush\Attributes;

use Consolidation\AnnotatedCommand\Attributes\AttributeInterface;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Drush;

abstract class ValidatorBase
{
public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$instance = $attribute->newInstance();
$hookManager = Drush::getContainer()->get('hookManager');
$hookManager->add(
// Use a Closure to acquire $commandData.
fn(CommandData $commandData) => $instance->validate($commandData),
$hookManager::ARGUMENT_VALIDATOR,
$commandInfo->getName()
);
}
}
10 changes: 10 additions & 0 deletions src/Attributes/ValidatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Drush\Attributes;

use Consolidation\AnnotatedCommand\CommandData;

interface ValidatorInterface
{
public function validate(CommandData $commandData);
}
Loading

0 comments on commit 3bcabf4

Please sign in to comment.