whateverthing.com

The Llama Commander

When I'm in an experimental mood, or working on a proof of concept, I like to code in a scrappy way. Anonymous functions allow me to avoid pausing my train of thought to think of a name for something. However, when I'm using the Symfony Console Component to write command-line utilities, it seems that I have to write a class for each command.

No more, I say!

I've created a tiny library called beryllium/llama that lets me set the configuration and execution logic of console commands using anonymous functions, right in the constructor. When I found myself using the technique across several projects, I did what anyone would do - I gave it a silly name and threw it on GitHub and Packagist.

I even added unit tests - which, unsurprisingly, immediately revealed a few bugs that needed to be fixed. Yay for tests!

You can try it out in your Silex and/or Symfony Console Component project by running:

$ composer require beryllium/llama

Once it's installed, you can define a llama command like so:

#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';

use Symfony\Component\Console\Application as ConsoleApplication;
use Beryllium\Llama\LlamaCommand;

$console = new ConsoleApplication;
$console->add(new LlamaCommand(
    'namespace:commandname',
    function ($config) { $config->setDescription('My Command'); },
    function ($input, $output) { $output->writeln('Hello, Watson'); }
));

$console->run();

The documentation on how to work with the Symfony Console Component is pretty thorough, so the basic syntax above should be enough to get you started playing with things. In fact, you should be able to save that code as "console" in a project directory, mark it chmod a+x console, and then run it as:

$ ./console namespace:commandname

If you invoke the console without specifying a command, the help will show your command(s):

$ ./console
Console Tool

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output,
                        2 for more verbose output and 3 for debug

Available commands:
  help                   Displays help for a command
  list                   Lists commands
 namespace
  namespace:commandname  My Command

I wouldn't recommend writing a large application using this technique. You will quickly get tangled in a giant console bootstrap file hundreds of lines long. But, if you're only going to be having a few short commands that do specific things, this could be a handy tool.

For my own projects, I tend to start out with the unstructured experimental approach. Once the concept is solid or the bootstrap code starts reaching into hundreds-of-lines territory, I add unit and functional tests and begin to refactor my anonymous functions into an actual hierarchy.

Please watch for my upcoming Building Web Apps with Silex 2 book, which will cover a variety of topics, including how to grow a project from a proof of concept to the best-architected application ever written*.

* As the book is not yet finished, anything is possible.


Mentioned in this post:

Published: October 19, 2015

Categories: coding

Tags: coding, dev, development, silex, command-line