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

Add explicit support for #[Command], #[Hook], and more PHP8 Attributes #223

Merged
merged 39 commits into from
Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2326782
Add support for command and hook as attributes
weitzman Jul 26, 2021
3d619b8
Document supported params for the sake of the IDE. Simplify option/pa…
weitzman Jul 26, 2021
2da2a1c
Exclude a file from code coverage and use nullable types.
weitzman Jul 27, 2021
bb274f1
Exclude another file from linter.
weitzman Jul 27, 2021
d59812b
Handle underscore to dash for attributes. Also let apps like Drush de…
weitzman Jul 27, 2021
0e281fa
Update README
weitzman Jul 27, 2021
fb2e2ed
Fix attribute docblock parser. Add docker-compose for easy testing on…
weitzman Jul 28, 2021
7c75f68
phpcs
weitzman Jul 28, 2021
14621c4
Add .env to .gitignore
weitzman Jul 28, 2021
eceb896
Use built-in test requirement annotation.
weitzman Jul 28, 2021
8e204c3
Increase code coverage.
weitzman Jul 28, 2021
a7d257d
Merge branch 'main' into attributes-command-hook
weitzman Sep 1, 2021
4b40de0
Rename to plural 'usages' and get tests passing again.
weitzman Sep 2, 2021
7eaa20d
Mark test class as PHP8+
weitzman Sep 2, 2021
74a15c1
Use separate attributes instead of one CommandLineAttributes
weitzman Sep 3, 2021
d8befdb
PHPCS
weitzman Sep 3, 2021
52ec32c
Linter
weitzman Sep 3, 2021
d353eee
Reorg the attribute classes a bit.
weitzman Sep 3, 2021
80eb732
Add topic attribute. Tweak others.
weitzman Sep 3, 2021
8dd4e7b
Remove unneeded changes. Update README
weitzman Sep 3, 2021
764bd99
pluralize topic
weitzman Sep 3, 2021
189b1ef
Handle isHook
weitzman Sep 4, 2021
b20c1d4
try to exclude new dir from code coverage
weitzman Sep 4, 2021
372a84d
typo
weitzman Sep 4, 2021
18f5af5
Change exclude for phpunit 8
weitzman Sep 4, 2021
6b89f80
Break up Name into Hook and Command
weitzman Sep 4, 2021
edc4edd
Fix Hook attribute.
weitzman Sep 5, 2021
4cd8b7e
Require descriptions.
weitzman Sep 5, 2021
317133b
Set hook name
weitzman Sep 5, 2021
d5d8e81
Handle empty target
weitzman Sep 6, 2021
4cfcb78
Move doc up
weitzman Sep 6, 2021
c747174
hook type can use class constants.
weitzman Sep 6, 2021
c1f855a
Add Attribute classes related to tables/formatters. These might move …
weitzman Sep 7, 2021
2dc8eb7
Set return type based on method return type declaration
weitzman Sep 7, 2021
9e65d60
Fix table Attribs
weitzman Sep 7, 2021
1f5ab4d
Get rid AttributeInterface. Also fix return type handling.
weitzman Sep 8, 2021
08b5ef4
Param -> Argument.
weitzman Sep 8, 2021
214fd28
Handle Union return type. @return takes precedence
weitzman Sep 8, 2021
792caa7
Move NoArgumentsBase to drush.
weitzman Sep 10, 2021
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
phpunit.xml
vendor
build
.env
tools
.idea
.phpunit.result.cache
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Consolidation\AnnotatedCommand

Initialize Symfony Console commands from annotated command class methods.
Initialize Symfony Console commands from annotated/attributed command class methods.

[![ci](https://github.com/consolidation/annotated-command/workflows/CI/badge.svg)](https://travis-ci.org/consolidation/annotated-command)
[![scrutinizer](https://scrutinizer-ci.com/g/consolidation/annotated-command/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/consolidation/annotated-command/?branch=master)
Expand Down Expand Up @@ -65,6 +65,24 @@ class MyCommandClass
}
```

or via PHP 8 attributes.

```php
#[CLI\Name(name: 'my:echo', aliases: ['c'])]
#[CLI\Help(description: 'This is the my:echo command', synopsis: "This command will concatenate two parameters. If the --flip flag\nis provided, then the result is the concatenation of two and one.",)]
#[CLI\Param(name: 'one', description: 'The first parameter')]
#[CLI\Param(name: 'two', description: 'The other parameter')]
#[CLI\Option(name: 'flip', description: 'Whether or not the second parameter should come first in the result.')]
#[CLI\Usage(name: 'bet alpha --flip', description: 'Concatenate "alpha" and "bet".')]
public function myEcho($one, $two = '', array $options = ['flip' => false])
{
if ($options['flip']) {
return "{$two}{$one}";
}
return "{$one}{$two}";
}
```

### Legacy Annotated Command Methods
The legacy method for declaring commands is still supported. When using the legacy method, the command options, if any, are declared as the last parameter of the methods. The options will be passed in as an associative array; the default options of the last parameter should list the options recognized by the command. The rest of the parameters are arguments. Parameters with a default value are optional; those without a default value are required.
```php
Expand Down Expand Up @@ -94,6 +112,7 @@ class MyCommandClass
}
}
```
## Option Default Values

The `$options` array must be an associative array whose key is the name of the option, and whose value is one of:

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"cbf": "phpcbf --standard=PSR2 -n src",
"unit": "SHELL_INTERACTIVE=true phpunit --colors=always",
"lint": [
"find src -name '*.php' -print0 | xargs -0 -n1 php -l",
"find src -name '*.php' -and ! -path 'src/Attributes/*' -print0 | xargs -0 -n1 php -l",
"find tests/src -name '*.php' -and ! -name 'ExampleAttributesCommandFile.php' -print0 | xargs -0 -n1 php -l"
],
"test": [
Expand Down
3 changes: 3 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
<exclude>
<directory suffix=".php">src/Attributes</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
28 changes: 28 additions & 0 deletions src/Attributes/Argument.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Argument
{
/**
* @param $name
* The name of the argument.
* @param $description
* A one line description.
*/
public function __construct(
public string $name,
public string $description
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addArgumentDescription($args['name'], @$args['description']);
}
}
30 changes: 30 additions & 0 deletions src/Attributes/Command.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class Command
{
/**
* @param $name
* The name of the command or hook.
* @param string[] $aliases
* An array of alternative names for this item.
*/
public function __construct(
public string $name,
public array $aliases = [],
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->setName($args['name']);
$commandInfo->addAnnotation('command', $args['name']);
$commandInfo->setAliases($args['aliases'] ?? []);
}
}
25 changes: 25 additions & 0 deletions src/Attributes/DefaultFields.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class DefaultFields
{
/**
* @param $fields
* An array of field names to show by default.
*/
public function __construct(
public array $fields,
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('default-fields', $args['fields']);
}
}
25 changes: 25 additions & 0 deletions src/Attributes/DefaultTableFields.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class DefaultTableFields
{
/**
* @param $fields
* An array of field names to show by default when using table formatter.
*/
public function __construct(
public array $fields,
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('default-table-fields', $args['fields']);
}
}
25 changes: 25 additions & 0 deletions src/Attributes/FieldLabels.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class FieldLabels
{
/**
* @param $labels
* An associative array of field names and labels for display.
*/
public function __construct(
public array $labels
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('field-labels', $args['labels']);
}
}
25 changes: 25 additions & 0 deletions src/Attributes/FilterDefaultField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class FilterDefaultField
{
/**
* @param $field
* A field name to filter on by default.
*/
public function __construct(
public string $field
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('filter-default-field', $args['field']);
}
}
33 changes: 33 additions & 0 deletions src/Attributes/Help.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class Help
{
/**
* @param $description
* A one line description.
* @param $synopsis
* A multi-line help text.
* @param bool|null $hidden
* Hide the command from the help list.
*/
public function __construct(
public string $description,
public ?string $synopsis,
public bool $hidden = false
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->setDescription($args['description']);
$commandInfo->setHelp(@$args['synopsis']);
$commandInfo->setHidden(@$args['hidden']);
}
}
31 changes: 31 additions & 0 deletions src/Attributes/Hook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use JetBrains\PhpStorm\ExpectedValues;

#[Attribute(Attribute::TARGET_METHOD)]
class Hook
{
/**
* @param $type
* When during the command lifecycle this hook will be called (e.g. validate).
* @param $target
* Specifies which command(s) the hook will be attached to.
*/
public function __construct(
#[ExpectedValues(valuesFromClass: HookManager::class)] public string $type,
public ?string $target
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->setName($args['target'] ?? '');
$commandInfo->addAnnotation('hook', $args['type'] . ' ' . $args['target'] ?? '');
}
}
25 changes: 25 additions & 0 deletions src/Attributes/Misc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class Misc
{
/**
* @param array $data
* An associative array containing arbitrary data.
*/
public function __construct(
public array $data,
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->AddAnnotation(key($args['data']), current($args['data']));
}
}
28 changes: 28 additions & 0 deletions src/Attributes/Option.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Option
{
/**
* @param $name
* The name of the option.
* @param $description
* A one line description.
*/
public function __construct(
public string $name,
public string $description
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addOptionDescription($args['name'], @$args['description']);
}
}
29 changes: 29 additions & 0 deletions src/Attributes/Topics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Consolidation\AnnotatedCommand\Attributes;

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

#[Attribute(Attribute::TARGET_METHOD)]
class Topics
{
/**
* @param string[] $topics
* An array of topics that are related to this command.
* @param $isTopic
* This command should appear on the list of topics.
*/
public function __construct(
public ?array $topics,
public bool $isTopic = false,
) {
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('topics', $args['topics'] ?? []);
$commandInfo->addAnnotation('topic', $args['is_topic'] ?? false);
}
}
Loading