Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 55 additions & 0 deletions components/console/console_arguments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@

namespace Acme\Console\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Option;

#[AsCommand(name: 'demo:args', description: 'Describe args behaviors')]
class DemoArgsCommand
{
public function __invoke(
#[Option(shortcut: 'f')] bool $foo = false,
#[Option(shortcut: 'b')] string $bar = '',
#[Option(shortcut: 'c')] string|bool $cat = false,
): int {
// ...
}
}

This example uses :ref:`invokable commands <console_creating-command>` with the
``#[Option]`` attribute. If you prefer the classic approach::

namespace Acme\Console\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -87,4 +107,39 @@
``-b Hello -c World`` ``"Hello"`` ``"World"`` ``null``
============================== ================= =========== ===========

.. _console-option-constraints:

Option Attribute Constraints
----------------------------

When using the ``#[Option]`` attribute in invokable commands, the following
rules are enforced to ensure consistent behavior:

* Options **must always have a default value**. Unlike arguments, options cannot
be required since users may simply not provide them;
* Nullable bool options (``?bool``) cannot have a ``true`` or ``false`` default.
Use ``null`` as the default to enable negatable behavior;
* Nullable non-bool options (e.g. ``?string``) must have ``null`` as the default value;
* Union types are only allowed for ``string|bool``, ``int|bool``, and ``float|bool``,
and must have ``false`` as the default value.

Examples of valid option definitions::

#[Option] bool $verbose = false // VALUE_NONE

Check failure on line 128 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_STRING, expecting T_TRAIT or T_INTERFACE or T_ENUM
#[Option] bool $colors = true // VALUE_NEGATABLE (--colors or --no-colors)

Check failure on line 129 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_STRING, expecting T_TRAIT or T_INTERFACE or T_ENUM

Check failure on line 129 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_ATTRIBUTE
#[Option] ?bool $debug = null // VALUE_NEGATABLE (--debug or --no-debug)

Check failure on line 130 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected '?', expecting T_TRAIT or T_INTERFACE or T_ENUM

Check failure on line 130 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_ATTRIBUTE
#[Option] string $format = 'json' // VALUE_REQUIRED

Check failure on line 131 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_STRING, expecting T_TRAIT or T_INTERFACE or T_ENUM

Check failure on line 131 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_ATTRIBUTE
#[Option] ?string $filter = null // VALUE_REQUIRED (optional value)

Check failure on line 132 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected '?', expecting T_TRAIT or T_INTERFACE or T_ENUM

Check failure on line 132 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_ATTRIBUTE
#[Option] int $limit = 10 // VALUE_REQUIRED

Check failure on line 133 in components/console/console_arguments.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_ATTRIBUTE
#[Option] array $roles = [] // VALUE_IS_ARRAY
#[Option] string|bool $output = false // VALUE_OPTIONAL (--output or --output=file.txt)

Examples of **invalid** option definitions::

#[Option] string $format // ERROR: no default value
#[Option] ?bool $debug = true // ERROR: nullable bool with true default
#[Option] ?string $filter = 'default' // ERROR: nullable with non-null default
#[Option] string|bool $output = true // ERROR: union type with true default
#[Option] array|bool $items = false // ERROR: unsupported union type

.. _docopt: http://docopt.org/
205 changes: 203 additions & 2 deletions console/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,65 @@ Using Command Arguments

Arguments are the strings - separated by spaces - that
come after the command name itself. They are ordered, and can be optional
or required. For example, to add an optional ``last_name`` argument to the command
or required.

Using Arguments in Invokable Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In :ref:`invokable commands <console_creating-command>`, use the
:class:`Symfony\\Component\\Console\\Attribute\\Argument` attribute
to define arguments directly in the ``__invoke()`` method parameters::

// ...
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'app:greet')]
class GreetCommand
{
public function __invoke(
// required argument (no default value)
#[Argument]
string $name,

// optional argument (has default value)
#[Argument]
string $lastName = '',
): int {
// ...
}
}

The ``Argument`` attribute accepts the following parameters:

``description``
A description of the argument shown when displaying the command help.
For example: ``#[Argument(description: 'Your username')]``.

``name``
The name of the argument (by default, the parameter name converted to ``kebab-case``).
For example: ``#[Argument(name: 'user-name')]``.

``suggestedValues``
An array or a callable that provides :ref:`suggested values for the argument <console-input-completion>`.
For example: ``#[Argument(suggestedValues: ['Alice', 'Bob'])]``.

.. versionadded:: 7.3

The ``#[Argument]`` and ``#[Option]`` attributes were introduced in Symfony 7.3.

The argument mode (required, optional, array) is inferred from the parameter type:

* **Required**: Parameters without a default value and not nullable (e.g. ``string $name``);
* **Optional**: Parameters with a default value (e.g. ``string $name = ''`` or ``?string $name = null``);
* **Array**: Parameters with the ``array`` type (e.g. ``array $names = []``);

Using the Classic configure() Method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you prefer the classic approach, or need to extend the ``Command`` class,
you can use the ``addArgument()`` method in the ``configure()`` method.
For example, to add an optional ``last_name`` argument to the command
and make the ``name`` argument required::

// ...
Expand Down Expand Up @@ -125,6 +183,97 @@ order) and are specified with two dashes (e.g. ``--yell``). Options are
*always* optional, and can be setup to accept a value (e.g. ``--dir=src``) or
as a boolean flag without a value (e.g. ``--yell``).

Using Options in Invokable Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In :ref:`invokable commands <console_creating-command>`, use the
:class:`Symfony\\Component\\Console\\Attribute\\Option` attribute
to define options directly in the ``__invoke()`` method parameters::

// ...
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Option;

#[AsCommand(name: 'app:greet')]
class GreetCommand
{
public function __invoke(
#[Argument]
string $name,

// option that accepts a value (--iterations=5)
#[Option]
int $iterations = 1,

// boolean flag (--yell)
#[Option]
bool $yell = false,
): int {
// ...
}
}

The ``Option`` attribute accepts the following parameters:

``description``
A description of the option shown when displaying the command help.
For example: ``#[Option(description: 'Number of iterations')]``.

``name``
The name of the option (by default, the parameter name converted to ``kebab-case``).
For example: ``#[Option(name: 'max-retries')]``.

``shortcut``
A one-letter shortcut that can be used instead of the full option name.
For example: ``#[Option(shortcut: 'i')]`` allows using ``-i`` instead of ``--iterations``.

``suggestedValues``
An array or a callable that provides :ref:`suggested values for the option <console-input-completion>`.
For example: ``#[Option(suggestedValues: ['low', 'medium', 'high'])]``.

The option mode is inferred from the parameter type and default value:

* **Boolean flag** (``VALUE_NONE``): ``bool`` type with default ``false``.
Usage: ``--yell`` sets the value to ``true``::

#[Option] bool $yell = false

* **Negatable flag** (``VALUE_NEGATABLE``): ``bool`` type with default ``true`` or
nullable ``?bool`` with default ``null``. Usage: ``--yell`` or ``--no-yell``::

#[Option] bool $yell = true
#[Option] ?bool $yell = null

* **Value required** (``VALUE_REQUIRED``): ``string``, ``int`` or ``float`` types::

#[Option] string $format = 'json'
#[Option] int $limit = 10
#[Option] ?string $filter = null

* **Array of values** (``VALUE_IS_ARRAY``): ``array`` type.
Usage: ``--role=ADMIN --role=USER``::

#[Option(description: 'User roles')] array $roles = []
#[Option] ?array $tags = null

* **Value optional** (``VALUE_OPTIONAL``): Union types ``string|bool``, ``int|bool``,
or ``float|bool`` with default ``false``. Usage: ``--output`` (returns ``true``)
or ``--output=file.txt`` (returns ``'file.txt'``)::

#[Option] string|bool $output = false

.. seealso::

The ``#[Option]`` attribute enforces validation rules on type and default
value combinations. See :ref:`Option Attribute Constraints <console-option-constraints>`
for the complete list of rules and examples.

Using the Classic addOption() Method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you prefer the classic approach, or need to extend the ``Command`` class,
you can use the ``addOption()`` method in the ``configure()`` method.
For example, add a new option to the command that can be used to specify
how many times in a row the message should be printed::

Expand Down Expand Up @@ -347,6 +496,8 @@ command without having to worry about the number of arguments or options::
The :method:`Symfony\\Component\\Console\\Input\\ArgvInput::getRawTokens`
method was introduced in Symfony 7.1.

.. _console-input-completion:

Adding Argument/Option Value Completion
---------------------------------------

Expand All @@ -356,7 +507,57 @@ can also implement value completion for the input in your commands. For
instance, you may want to complete all usernames from the database in the
``name`` argument of your greet command.

To achieve this, use the 5th argument of ``addArgument()`` or the 6th argument of ``addOption()``::
Using Completion with Attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When using the ``#[Argument]`` or ``#[Option]`` attributes in invokable commands,
use the ``suggestedValues`` parameter to provide completion values::

use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Completion\CompletionInput;

public function __invoke(
// static list of suggested values
#[Argument(suggestedValues: ['Alice', 'Bob', 'Charlie'])]
string $name,

// dynamic values via a callable (method reference)
#[Option(suggestedValues: [self::class, 'suggestFormats'])]
string $format = 'json',
): int {
// ...
}

public static function suggestFormats(CompletionInput $input): array
{
return ['json', 'xml', 'csv'];
}

.. note::

You can remove the ``static`` keyword from the suggestion method to access
instance properties. In that case, the command will call the method
non-statically, allowing you to return dynamic values based on services
injected through the constructor::

public function __construct(
private UserRepository $userRepository,
) {
}

// ...

public function suggestUsers(CompletionInput $input): array
{
return $this->userRepository->findAllUsernames();
}

Using Completion with addArgument()/addOption()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When using the classic ``configure()`` method, use the 5th argument
of ``addArgument()`` or the 6th argument of ``addOption()``::

// ...
use Symfony\Component\Console\Completion\CompletionInput;
Expand Down