Batches are dead, long life to tasks!

As any web application, your project has repetitive maintenance tasks, database operations, or other console scripts running on a regular basis.

Symfony 1.1 extends symfony 1.0 pake tasks to create a powerful and uniform command line utility for your projects, fully integrated with the symfony Command Line Interface (CLI).

  • Accessibility: Any task can be run with the help parameter prepended, to get the syntax, a description, available options, and more. Anybody will be able to run your tasks.
  • Usability: Running the symfony CLI will give you the task list, and even a non developer will be able to learn easily how to run one.
  • Uniformity: By explicitly describing every options and parameters, symfony CLI will parse them so you can forget about the troublesome repetitive task of parsing $argv. It will automatically warn the user of wrong syntax or missing parameters.
  • Environment: The context is fully controlled, thanks to the new ProjectConfiguration and ApplicationConfiguration classes. You won't worry anymore about hard-coded environment or debug settings.
  • Readability: Anyone opening the source code will get great description of the expected input and the goals of the task. Maintenance time took to understand and debug this code will be greatly reduced.

Let's create our first task

Open your symfony 1.1 project directory and type:

$ php symfony generate:task doNothing

It will bootstrap an empty task in lib/task/doNothingTask.class.php. Let's tune it a bit.

class doNothingTask extends sfBaseTask
{
  protected function configure()
  {
    $this->namespace        = 'project';
    $this->name             = 'do-nothing';
    $this->briefDescription = 'Does strictly nothing';
 
    $this->detailedDescription = <<This task is completely useless, and should be run as often as possible.
EOF;
  }
 
  protected function execute($arguments = array(), $options = array())
  {
    $this->logSection('do-nothing', 'I did nothing successfully!');
  }
}
 

This task for sure does not much, but demonstrates the first basic concepts.:

  • The configure() method describes the task. Invocation name, scope, syntax, help, options and arguments.
  • The execute() method is the one who does all the job actually, and will be called when the task is run.
  • The logSection() method can be used to print nicely formatted messages to the console.

You can play around a bit with it:

$ php symfony help project:do-nothing
$ php symfony project:do-nothing

Some command line interaction

Arguments and options are the way to give parameters to a task.

$ php symfony project:hello-world --name="Romain"

Here we're running the project:hello-world task with the name option set to Romain

$ php symfony project:hello-world Hi

Now, we run the same task with the first argument set to Hi.

Options and arguments can have default values, be optional or required and embed their purpose for automatic syntax help.

Let's write our project:hello-world task:

class doHelloWorldTask extends sfBaseTask
{
  protected function configure()
  {
    $this->addArgument('verb', sfCommandArgument::OPTIONAL, 'Customize the verb used to say hello', 'hello');
    $this->addOption('name', null, sfCommandOption::PARAMETER_OPTIONAL, 'Customize the person to say hello to', 'world');
 
    $this->namespace        = 'project';
    $this->name             = 'hello-world';
    $this->briefDescription = 'Spread the (hello) world';
 
    $this->detailedDescription = <<Runs an evolved hello world display, with customisable name and word.
EOF;
  }
 
  protected function execute($arguments = array(), $options = array())
  {
    $this->logSection('do', ucfirst($arguments['verb']).' '.ucfirst($options['name']));
  }
}
 

Now check out how symfony helps the lost user about how to use our new task:

$ php symfony project:hello-world invalid arguments given
$ php symfony help project:hello-world

And play a bit with the task:

$ php symfony project:hello-world
$ php symfony project:hello-world --name="romain"
$ php symfony project:hello-world --name=romain hi
$ php symfony project:hello-world hi --name=romain

Some other handy features

  • Do you need the database layer?

    protected function execute($arguments = array(), $options = array())
    {
      $databaseManager = new sfDatabaseManager($this->configuration);
     
      // ...
    }
     
  • Run another task within a task?

    $myOtherTask = new myOtherTask($this->dispatcher, $this->formatter);
    $myOtherTask->run($arguments = array('foo' => 'bar'), $options = array('far' => 'boo'));
     
  • Need to let the user choose the environment, while providing a default one?

    Just add the env option in the ::configure() method and symfony will use its value as the environemnt.

    $this->addOption('env', null, sfCommandOption::PARAMETER_OPTIONAL, 'Changes the environment this task is run in', 'prod');
     

What do you think? Isn't this some cherry on the cake, or for instance, some jazzy chorus over the symfony?

Comments

Symfony is always exciting. But I am really looking forward to the release of 1.1 and especially, the documentation~
Symfony is always exciting. But I am really looking forward to the release of 1.1 and especially, the documentation~
My Symfony 1.0 project has a lot of batch tasks, but it always seemed that they existed a bit outside the project.

With the new 1.1 task system, batches are fully integrated ... great! And thanks for the Cookbook recipe. :-)
$databaseManager = new sfDatabaseManager($this->configuration);
throws an exception:
Catchable fatal error: Argument 1 passed to sfDatabaseManager::__construct() must be an instance of sfApplicationConfiguration, instance of ProjectConfiguration given

i have to use:
$configuration = ProjectConfiguration::getApplicationConfiguration($options['application'], $options['env'], true);
$databaseManager = new sfDatabaseManager($configuration);
would be nice to have a common TAG for all howto blog entries ..
Those blog snippets are so useful, keep them coming people.
Markus,
I don't think we need a tag for it, the blog entries should be manifested in a cookbook recipe.
http://www.symfony-project.org/cookbook/1_1/en/
Sometimes the publishing is not synced, but generally they should be in that cookbook
@Fabian: All those posts are in the cookbook except for the i18n one as it is already explained in the forms book.

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.