You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Garden CLI is a PHP command line interface library meant to provide a full set of functionality with a clean and simple api.
9
16
10
-
## Why use Garden CLI?
17
+
###Why use Garden CLI?
11
18
12
19
PHP's `getopt()` provides little functionality and is prone to failure where one typo in your command line options can wreck and entire command call. Garden CLI solves this problem and provides additional functionality.
13
20
@@ -16,7 +23,7 @@ PHP's `getopt()` provides little functionality and is prone to failure where one
16
23
* Have command options parsed and validated with error information automatically printed out.
17
24
* A simple, elegant syntax so that even your most basic command line scripts will take little effort to implement robust parsing.
18
25
19
-
## Installation
26
+
###Installation
20
27
21
28
*Garden CLI requires PHP 7.0 or higher*
22
29
@@ -28,7 +35,11 @@ Garden CLI is [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accep
28
35
}
29
36
```
30
37
31
-
## Basic Example
38
+
## Defining The CLI
39
+
40
+
The `Cli` class provides a fluent interface for defining commands, opts, and args.
41
+
42
+
### Basic Example
32
43
33
44
Here is a basic example of a command line script that uses Garden CLI to parse its options. Let's say you are writing a script called `dbdump.php` to dump some data from your database.
34
45
@@ -61,7 +72,7 @@ This example returns an `Args` object or exits to show help or an error message.
61
72
* If you want your option to have a short code then specify in with `name` argument separated by a colon.
62
73
* If you specify a short code for an option this will act like an alias for the parameter name in `$argv` only. You always access an option by its full name after parsing.
63
74
64
-
## Option Types
75
+
###Option Types
65
76
66
77
The `opt` method has a `$type` parameter that you can use to specify a type for the option. The valid types are `integer`, `string`, and `boolean` with string as the default.
If you were to call the basic example with a `--help` option then you'd see the following help printed:
78
89
@@ -92,7 +103,7 @@ Dump some information from your database.
92
103
93
104
All of the options are printed in a compact table and required options are printed in bold. The table will automatically expand to accommodate longer option names and wrap if you provide extra long descriptions.
94
105
95
-
## Displaying Errors
106
+
###Displaying Errors
96
107
97
108
Let's say you call the basic example with just `-P foo`. What you'd see is the following error message:
Once you've successfully parsed the `$argv` using `Cli->parse($argv)` you can use the various methods on the returned `Args` object.
108
119
@@ -115,7 +126,7 @@ $database = $args['database']; // use the args like an array too
115
126
$port = $args->getOpt('port', 123); // get port with default 123
116
127
```
117
128
118
-
## Multiple Commands Example
129
+
###Multiple Commands Example
119
130
120
131
Let's say you are writing a git-like command line utility called `nit.php` that pushes and pulls information from a remote repository.
121
132
@@ -147,32 +158,148 @@ Like the basic example, `parse()` will return a `Args` object on a successful pa
147
158
* If the type of `opt()` is `integer` then you can count the number of times an option is supplied. In this example, this allowes you to specify multiple levels of verbosity by adding multiple `-v`s.
148
159
* The `arg()` method lets you define arguments that go after the options on the command line. More on this below.
149
160
150
-
## Listing Commands
161
+
###Listing Commands
151
162
152
163
Calling a script that has commands with no options or just the `--help` option will display a list of commands. Here is the output from the multiple commands example above.
The `Args` class differentiates between args and opts. There are methods to access both opts and args on that class.
165
176
166
177
* Opts are passed by `--name` full name or `-s` short code. They are named and can have types.
167
178
* Args are passed after the options as just strings separated by spaces.
168
179
* When calling a script from the command line you can use `--` to separate opts from args if there is ambiguity.
169
180
170
-
## Formatting Output with the TaskLogger
181
+
## The CliApplication Class
182
+
183
+
The basic `Cli` class works well for defining and documenting opts and args. However, you still need to wire up the parsed command line args to your own code. If you want to reduce this boilerplate, you can use the `CliApplication` class.
184
+
185
+
*Note: In order to use the `CliApplication` functionality you will need to require some extra dependencies. See the suggested packages in composer.json for more information.*
186
+
187
+
### Defining a Subclass of CliApplication
188
+
189
+
To use the `CliApplication` you usually subclass it and override the `configureContainer()` and `configureCli()` methods to define the commands in your app.
190
+
191
+
```php
192
+
class App extends Garden\Cli\Application\CliApplication {
You can wire up class methods to the command line by using `addMethod()`. This does the following:
221
+
222
+
1. It will create a command derived from the method name. Override the command name with the `OPT_COMMAND` option.
223
+
2. It will create opts for object setters. Object setters are methods that start with the word `set` and take one argument. You can opt out of setter wiring with the `OPT_SETTERS` options.
224
+
3. It will create opts for method parameters. If the method has class type-hinted types they will not be wired up to opts, but instead will be satisfied with the container.
225
+
4. It will use method doc blocks to add descriptions for the command and opts. Make sure you use PHPDoc syntax.
226
+
227
+
You can call `addMethod()` with either a static or instance method. If you pass a static method then it will only wire up static setters. An instance method will wire up both static and instance methods.
228
+
229
+
#### Using the `addCallable()` Method
230
+
231
+
You can wire up an ad-hoc closure to the command line by using `addCallable()`. This works much like `addMethod()`, but will only reflect the callable's parameters.
232
+
233
+
Even though it's not a common practice to add a doc block to an inline closure, you can do so and it will be used to document the command. If you don't do so, but at least want a description then use the `OPT_DESCRIPTION` option to provide one.
234
+
235
+
#### Using the `addConstructor()` and `addFactory()` Methods
236
+
237
+
You can add dependencies by wiring up their constructor parameters or a factory method to the opts. The most common use case is specifying connection parameters to a database or an access token to an API client.
238
+
239
+
Use `addConstructor()` if the class has constructor parameters that make sense coming from the command line.
240
+
241
+
Use `addFactory()` if you want to clean up the names of the parameters or do some additional properties somehow.
242
+
243
+
If the constructor or factory has class type hints then not to worry. Those will be auto-wired through the container. You can then configure them through the container directory or even wire them up to opts by making additional calls to `addConstructor()` or `addFactory()`.
244
+
245
+
```php
246
+
class App extends Garden\Cli\Application\CliApplication {
247
+
protected function configureCli(): void {
248
+
parent::configureCli();
249
+
250
+
// This will make the database connection get created by the DbUtils::createMySQL() method with command line opts for the same.
You can wire up a call to a class method using the `addCall()` method. Use this for setter injection. The call will be applied when the class is instantiated.
265
+
266
+
```php
267
+
class App extends Garden\Cli\Application\CliApplication {
268
+
protected function configureCli(): void {
269
+
parent::configureCli();
270
+
271
+
// Wire up your github client's API key to the command line.
To use your application you just need to call the `main()` method.
280
+
281
+
```php
282
+
$app = new App();
283
+
$app->main($argv);
284
+
```
285
+
286
+
The main method does the following:
287
+
288
+
1. Parses the `$argv` parameter to determine the command.
289
+
2. If the command maps to an instance method then an instance is fetched from the container.
290
+
3. Setters are applied from the opts.
291
+
4. The method is invoked through the container, satisfying any arguments that were not specified as opts.
292
+
293
+
## Logging
294
+
295
+
Many CLI applications require some form of logging. Garden CLI has you covered.
296
+
297
+
### Formatting Output with the TaskLogger
171
298
172
299
The `TaskLogger` is a [PSR-3](https://www.php-fig.org/psr/psr-3/) log decorator helps you output task-based information to the console in a nice, compact style. It's good for
173
300
things like install scripts, scripts that take a long time, or scripts you put into a cron job.
174
301
175
-
### Logging Tasks
302
+
####Logging Tasks
176
303
177
304
When using the `TaskLogger` you want to think in terms of messages and tasks. A message is a single log item to output
178
305
to the user. A task has a begin and an end and can be nested as much as you want. Messages are output using the various PSR-3 methods while tasks are output with `begin()` and `end()`. Here are all of the methods you can use to log tasks.
@@ -185,40 +312,40 @@ to the user. A task has a begin and an end and can be nested as much as you want
185
312
|`endError`| Log the end of a task that resulted in an error. |
186
313
|`endHttpStatus`| Log the end of a task with an HTTP status. The log level is calculated from the number of the status. |
187
314
188
-
### Task Nesting and Durations
315
+
####Task Nesting and Durations
189
316
190
317
You can nest tasks as much as you wish by calling a `begin*` method before calling an `end*` method. Each time you nest a task it will output its messages indented another level. Tasks also calculate their duration and output it at after the call to `end`.
191
318
192
-
### Suppressing Messages
319
+
####Suppressing Messages
193
320
194
321
By default, the `TaskLogger` will only output messages that are at a level of `LogLevel::INFO` or higher. You can change this with the `setMinLevel` method. If you begin a task at a level that us suppressed, but a child message is at or above the min level then the begin task message will be output retroactively. This allows you to see what task kicked off the logged message.
195
322
196
-
### Example
323
+
####Example
197
324
198
325
```php
199
326
$log = new TaskLogger();
200
327
201
-
$log->info('This is a message.')
202
-
->error('This is an error.') // outputs in red
328
+
$log->info('This is a message.');
329
+
$log->error('This is an error.'); // outputs in red
203
330
204
-
->beginInfo('Begin a task')
205
-
// code task code goes here...
206
-
->end('done.')
331
+
$log->beginInfo('Begin a task');
332
+
// code task code goes here...
333
+
$log->end('done.');
207
334
208
-
->beginDebug('Make an API call')
209
-
->endHttpStatus(200) // treated as error or success depending on code
335
+
$log->beginDebug('Make an API call');
336
+
$log->endHttpStatus(200); // treated as error or success depending on code
210
337
211
-
->begin(LogLevel::NOTICE, 'Multi-step task')
212
-
->info('Step 1')
213
-
->info('Step 2')
214
-
->beginDebug('Step 3')
215
-
->debug('Step 3.1') // steps will be hidden because they are level 3
216
-
->debug('Step 3.2')
217
-
->end('done.')
218
-
->end('done.');
338
+
$log->begin(LogLevel::NOTICE, 'Multi-step task');
339
+
$log->info('Step 1');
340
+
$log->info('Step 2');
341
+
$log->beginDebug('Step 3');
342
+
$log->debug('Step 3.1'); // steps will be hidden because they are level 3
343
+
$log->debug('Step 3.2');
344
+
$log->end('done.');
345
+
$log->end('done.');
219
346
```
220
347
221
-
## The StreamLogger
348
+
###The StreamLogger
222
349
223
350
If you create and use a `TaskLogger` object it will output nicely to the console out of the box. Under the hood it is using a `StreamLogger` object to handle the formatting of the tasks to an output stream, in this case stdout. You can replace or modify the `StreamLogger` if you want to control logging in a more granular level. Here are some options.
224
351
@@ -230,7 +357,7 @@ If you create and use a `TaskLogger` object it will output nicely to the console
230
357
|`setTimeFormat`|`'%F %T'`| Set the time format. This can be a `strftime` string or a callback. |
231
358
|`setLevelFormat`| nothing | Set a callback to format a `LogLevel` constant. |
232
359
233
-
### Example
360
+
####Example
234
361
235
362
The following example creates a `StreamLogger` object and tweaks some of its settings before passing it into the `TaskLogger` constructor.
You can give the `TaskLogger` any PSR-3 compliant logger and it will send its output to it. In order to use some of the special task functionality, you'll have to inspect the `$contenxt` argument of your `log` method. Here the fields that you may receive.
0 commit comments