Security update for Core, with self-updated composer
[yaffs-website] / vendor / consolidation / annotated-command / README.md
index 676be8b28272a6c91a2deea2ae5c2246285d9320..72227e3cd0f4910b823a1d8d4545f644c2bcff4a 100644 (file)
@@ -24,7 +24,7 @@ Extant commandline tools that utilize this technique include:
 
 This library provides routines to produce the Symfony\Component\Console\Command\Command from all public methods defined in the provided class.
 
-**Note** If you are looking for a very fast way to write a Symfony Console-base command-line tool, you should consider using [Robo](https://github.com/consolidation/Robo), which is built on top of this library, and adds additional conveniences to get you going quickly. See [Using Robo as a Framework](https://github.com/consolidation/Robo/docs/framework.md).  It is possible to use this project without Robo if desired, of course.
+**Note** If you are looking for a very fast way to write a Symfony Console-base command-line tool, you should consider using [Robo](https://github.com/consolidation/Robo), which is built on top of this library, and adds additional conveniences to get you going quickly. See [Using Robo as a Framework](http://robo.li/framework/).  It is possible to use this project without Robo if desired, of course.
 
 ## Library Usage
 
@@ -72,38 +72,86 @@ The `$options` array must be an associative array whose key is the name of the o
 
 - The boolean value `false`, which indicates that the option takes no value.
 - A **string** containing the default value for options that may be provided a value, but are not required to.
-- NULL for options that may be provided an optional value, but that have no default when a value is not provided.
 - The special value InputOption::VALUE_REQUIRED, which indicates that the user must provide a value for the option whenever it is used.
+- The special value InputOption::VALUE_OPTIONAL, which produces the following behavior:
+  - If the option is given a value (e.g. `--foo=bar`), then the value will be a string.
+  - If the option exists on the commandline, but has no value (e.g. `--foo`), then the value will be `true`.
+  - If the option does not exist on the commandline at all, then the value will be `null`.
+  - If the user explicitly sets `--foo=0`, then the value will be converted to `false`.
+  - LIMITATION: If any Input object other than ArgvInput (or a subclass thereof) is used, then the value will be `null` for both the no-value case (`--foo`) and the no-option case. When using a StringInput, use `--foo=1` instead of `--foo` to avoid this problem.
+- The special value `true` produces the following behavior:
+  - If the option is given a value (e.g. `--foo=bar`), then the value will be a string.
+  - If the option exists on the commandline, but has no value (e.g. `--foo`), then the value will be `true`.
+  - If the option does not exist on the commandline at all, then the value will also be `true`.
+  - If the user explicitly sets `--foo=0`, then the value will be converted to `false`.
+  - If the user adds `--no-foo` on the commandline, then the value of `foo` will be `false`.
 - An empty array, which indicates that the option may appear multiple times on the command line.
 
-No other values should be used for the default value. For example, `$options = ['a' => 1]` is **incorrect**; instead, use `$options = ['a' => '1']`. Similarly, `$options = ['a' => true]` is unsupported, or at least not useful, as this would indicate that the value of `--a` was always `true`, whether or not it appeared on the command line.
+No other values should be used for the default value. For example, `$options = ['a' => 1]` is **incorrect**; instead, use `$options = ['a' => '1']`.
+
+Default values for options may also be provided via the `@default` annotation. See hook alter, below.
 
 ## Hooks
 
 Commandfiles may provide hooks in addition to commands. A commandfile method that contains a @hook annotation is registered as a hook instead of a command.  The format of the hook annotation is:
 ```
-@hook type commandname|annotation
+@hook type target
 ```
-The commandname may be the command's primary name (e.g. `my:command`), it's method name (e.g. myCommand) or any of its aliases.
-
-If an annotation is given instead, then this hook function will run for all commands with the specified annotation.
-
-There are ten types of hooks supported:
-
-- Command Event (Symfony)
-- Option
-- Initialize (Symfony)
-- Interact (Symfony)
-- Validate
-- Command
-- Process
-- Alter
-- Status
-- Extract
-- On-event
-- Replace Command
-
-Most of these also have "pre" and "post" varieties, to give more flexibility vis-a-vis hook ordering (and for consistency). Note that many validate, process and alter hooks may run, but the first status or extract hook that successfully returns a result will halt processing of further hooks of the same type.
+The hook **type** determines when during the command lifecycle this hook will be called. The available hook types are described in detail below.
+
+The hook **target** specifies which command or commands the hook will be attached to. There are several different ways to specify the hook target.
+
+- The command's primary name (e.g. `my:command`) or the command's method name (e.g. myCommand) will attach the hook to only that command.
+- An annotation (e.g. `@foo`) will attach the hook to any command that is annotated with the given label.
+- If the target is omitted, then the hook will be attached to every command defined in the same class as the hook implementation.
+
+There are ten types of hooks in the command processing request flow:
+
+- [Command Event](#command-event-hook) (Symfony)
+   - @pre-command-event
+   - @command-event
+   - @post-command-event
+- [Option](#option-event-hook)
+   - @pre-option
+   - @option
+   - @post-option
+- [Initialize](#initialize-hook) (Symfony)
+   - @pre-init
+   - @init
+   - @post-init
+- [Interact](#interact-hook) (Symfony)
+   - @pre-interact
+   - @interact
+   - @post-interact
+- [Validate](#validate-hook)
+   - @pre-validate
+   - @validate
+   - @post-validate
+- [Command](#command-hook)
+   - @pre-command
+   - @command
+   - @command-init
+- [Process](#process-hook)
+   - @pre-process
+   - @process
+   - @post-process
+- [Alter](#alter-hook)
+   - @pre-alter
+   - @alter
+   - @post-alter
+- [Status](#status-hook)
+   - @status
+- [Extract](#extract-hook)
+   - @extract
+   
+In addition to these, there are two more hooks available:
+
+- [On-event](#on-event-hook)
+   - @on-event
+- [Replace Command](#replace-command-hook)
+   - @replace-command
+
+The "pre" and "post" varieties of these hooks, where avalable, give more flexibility vis-a-vis hook ordering (and for consistency). Within one type of hook, the running order is undefined and not guaranteed. Note that many validate, process and alter hooks may run, but the first status or extract hook that successfully returns a result will halt processing of further hooks of the same type.
 
 Each hook has an interface that defines its calling conventions; however, any callable may be used when registering a hook, which is convenient if versions of PHP prior to 7.0 (with no anonymous classes) need to be supported.
 
@@ -113,15 +161,70 @@ The command-event hook is called via the Symfony Console command event notificat
 
 ### Option Event Hook
 
-The option event hook ([OptionHookInterface](src/Hooks/OptionHookInterface.php)) is called for a specific command, whenever it is executed, or its help command is called. Any additional options for the command may be added here by instantiating and returnng an InputOption array.
+The option event hook ([OptionHookInterface](src/Hooks/OptionHookInterface.php)) is called for a specific command, whenever it is executed, or its help command is called. Any additional options for the command may be added here by calling the `addOption` method of the provided `$command` object. Note that the option hook is only necessary for calculating dynamic options. Static options may be added via the @option annotation on any hook that uses them. See the [Alter Hook](https://github.com/consolidation/annotated-command#alter-hook) documentation below for an example.
+```
+use Consolidation\AnnotatedCommand\AnnotationData;
+use Symfony\Component\Console\Command\Command;
+
+/**
+ * @hook option some:command
+ */
+public function additionalOption(Command $command, AnnotationData $annotationData)
+{
+    $command->addOption(
+        'dynamic',
+        '',
+        InputOption::VALUE_NONE,
+        'Option added by @hook option some:command'
+    );
+}
+```
 
 ### Initialize Hook
 
 The initialize hook ([InitializeHookInterface](src/Hooks/InitializeHookInterface.php)) runs prior to the interact hook.  It may supply command arguments and options from a configuration file or other sources. It should never do any user interaction.
 
+The [consolidation/config](https://github.com/consolidation/config) project (which is used in [Robo PHP](https://github.com/consolidation/robo)) uses `@hook init` to automatically inject values from `config.yml` configuration files for options that were not provided on the command line.
+```
+use Consolidation\AnnotatedCommand\AnnotationData;
+use Symfony\Component\Console\Input\InputInterface;
+
+/**
+ * @hook init some:command
+ */
+public function initSomeCommand(InputInterface $input, AnnotationData $annotationData)
+{
+    $value = $input->getOption('some-option');
+    if (!$value) {
+        $input->setOption('some-option', $this->generateRandomOptionValue());
+    }
+}
+```
+
 ### Interact Hook
 
-The interact hook ([InteractorInterface](src/Hooks/InteractorInterface.php)) runs prior to argument and option validation. Required arguments and options not supplied on the command line may be provided during this phase by prompting the user.  Note that the interact hook is not called if the --no-interaction flag is supplied, whereas the command-event hook and the inject-configuration hook are.
+The interact hook ([InteractorInterface](src/Hooks/InteractorInterface.php)) runs prior to argument and option validation. Required arguments and options not supplied on the command line may be provided during this phase by prompting the user.  Note that the interact hook is not called if the --no-interaction flag is supplied, whereas the command-event hook and the init hook are.
+```
+use Consolidation\AnnotatedCommand\AnnotationData;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+/**
+ * @hook interact some:command
+ */
+public function interact(InputInterface $input, OutputInterface $output, AnnotationData $annotationData)
+{
+    $io = new SymfonyStyle($input, $output);
+
+    // If the user did not specify a password, then prompt for one.
+    $password = $input->getOption('password');
+    if (empty($password)) {
+        $password = $io->askHidden("Enter a password:", function ($value) { return $value; });
+        $input->setOption('password', $password);
+    }
+}
+```
 
 ### Validate Hook
 
@@ -133,24 +236,112 @@ The purpose of the validate hook ([ValidatorInterface](src/Hooks/ValidatorInterf
 - Return false. Message is empty, and status is 1. Deprecated.
 
 The validate hook may change the arguments and options of the command by modifying the Input object in the provided CommandData parameter.  Any number of validation hooks may run, but if any fails, then execution of the command stops.
+```
+use Consolidation\AnnotatedCommand\CommandData;
+
+/**
+ * @hook validate some:command
+ */
+public function validatePassword(CommandData $commandData)
+{
+    $input = $commandData->input();
+    $password = $input->getOption('password');
+
+    if (strpbrk($password, '!;$`') === false) {
+        throw new \Exception("Your password MUST contain at least one of the characters ! ; ` or $, for no rational reason whatsoever.");
+    }
+}
+```
 
 ### Command Hook
 
 The command hook is provided for semantic purposes.  The pre-command and command hooks are equivalent to the post-validate hook, and should confirm to the interface ([ValidatorInterface](src/Hooks/ValidatorInterface.php)).  All of the post-validate hooks will be called before the first pre-command hook is called.  Similarly, the post-command hook is equivalent to the pre-process hook, and should implement the interface ([ProcessResultInterface](src/Hooks/ProcessResultInterface.php)).
 
 The command callback itself (the method annotated @command) is called after the last command hook, and prior to the first post-command hook.
+```
+use Consolidation\AnnotatedCommand\CommandData;
+
+/**
+ * @hook pre-command some:command
+ */
+public function preCommand(CommandData $commandData)
+{
+    // Do something before some:command
+}
+
+/**
+ * @hook post-command some:command
+ */
+public function postCommand($result, CommandData $commandData)
+{
+    // Do something after some:command
+}
+```
 
 ### Process Hook
 
-The process hook ([ProcessResultInterface](src/Hooks/ProcessResultInterface.php)) is specifically designed to convert a series of processing instructions into a final result.  An example of this is implemented in Robo; if a Robo command returns a TaskInterface, then a Robo process hook will execute the task and return the result. This allows a pre-process hook to alter the task, e.g. by adding more operations to a task collection.
+The process hook ([ProcessResultInterface](src/Hooks/ProcessResultInterface.php)) is specifically designed to convert a series of processing instructions into a final result.  An example of this is implemented in Robo in the [CollectionProcessHook](https://github.com/consolidation/Robo/blob/master/src/Collection/CollectionProcessHook.php) class; if a Robo command returns a TaskInterface, then a Robo process hook will execute the task and return the result. This allows a pre-process hook to alter the task, e.g. by adding more operations to a task collection.
 
 The process hook should not be used for other purposes.
+```
+use Consolidation\AnnotatedCommand\CommandData;
+
+/**
+ * @hook process some:command
+ */
+public function process($result, CommandData $commandData)
+{
+    if ($result instanceof MyInterimType) {
+        $result = $this->convertInterimResult($result);
+    }
+}
+```
 
 ### Alter Hook
 
 An alter hook ([AlterResultInterface](src/Hooks/AlterResultInterface.php)) changes the result object. Alter hooks should only operate on result objects of a type they explicitly recognize. They may return an object of the same type, or they may convert the object to some other type.
 
 If something goes wrong, and the alter hooks wishes to force the command to fail, then it may either return a CommandError object, or throw an exception.
+```
+use Consolidation\AnnotatedCommand\CommandData;
+
+/**
+ * Demonstrate an alter hook with an option
+ *
+ * @hook alter some:command
+ * @option $alteration Alter the result of the command in some way.
+ * @usage some:command --alteration
+ */
+public function alterSomeCommand($result, CommandData $commandData)
+{
+    if ($commandData->input()->getOption('alteration')) {
+        $result[] = $this->getOneMoreRow();
+    }
+
+    return $result;
+}
+```
+
+If an option needs to be provided with a default value, that may be done via the `@default` annotation.
+
+```
+use Consolidation\AnnotatedCommand\CommandData;
+
+/**
+ * Demonstrate an alter hook with an option that has a default value
+ *
+ * @hook alter some:command
+ * @option $name Give the result a name.
+ * @default $name George
+ * @usage some:command --name=George
+ */
+public function nameSomeCommand($result, CommandData $commandData)
+{
+    $result['name'] = $commandData->input()->getOption('name')
+
+    return $result;
+}
+```
 
 ### Status Hook
 
@@ -231,7 +422,7 @@ The Annotated-Command project is completely agnostic to logging. If a command wi
 
 If you want to use annotations, but still want access to the Symfony Command, e.g. to get a reference to the helpers in order to call some legacy code, you may create an ordinary Symfony Command that extends \Consolidation\AnnotatedCommand\AnnotatedCommand, which is a \Symfony\Component\Console\Command\Command. Omit the configure method, and place your annotations on the `execute()` method.
 
-It is also possible to add InputInterface or OutputInterface parameters to any annotated method of a command file.
+It is also possible to add InputInterface and/or OutputInterface parameters to any annotated method of a command file (the parameters must go before command arguments).
 
 ## API Usage