Zend Framework is good when it comes to web requests, involving controllers with their actions, but usually most web applications today have another entry point: running from console. Some examples of console tasks: clearing up cache, sending emails, seeding a database, extracting/merging translatable strings and generally any kind of batch jobs. At first, I’ve kept a directory of runnable scripts for this, but after some time, I realized the need to unify and organize this messy collection of scripts. Symfony Console Component elegantly solves this kind of problem, providing solid platform for building CLI applications. Being one of the core components of Symfony2 framework, it’s already intensively used in the framework itself and other PHP projects. If you are new to Symfony Console, I suggest checking out these links:
Let’s see how could we integrate it into Zend application. Suppose we have a Zend application with the structure similar to the recommended one and
~/cli-show is a root directory. Symfony Console requires PHP >= 5.3, version of Zend framework being used is 1.11.8.
Installing Symfony Console
I’m going to install it from Git. In real project, we’ll probably use git’s submodule functionality or download the archive from Github and unzip it, but for the sake of simplicity, let’s just clone it now.
[/]$ cd ~/cli-show [cli-show]$ mkdir -p library/Symfony/Component [cli-show]$ git clone https://github.com/symfony/Console.git library/Symfony/Component/Console
Also, to properly autoload Symfony classes we’ll have to register Symfony namespace (assuming
Zend_Loader_Autoloader is used for autoloading).
Symfony Console itself has some basic commands. Let’s try running them. Create the file
scripts directory, and make it executable.
[cli-show]$ mkdir scripts && touch scripts/console && chmod a+x scripts/console
This script will be the entry point for all console commands. We’ll use the default
Symfony\Component\Console\Application class provided by Symfony Console. Contents of our script:
This code is very similar to the code in
index.php and we should avoid duplicating it, but for now let’s just try it:
A nice looking output should appear, telling you possible command-line switches and commands.
Introducing Zend application
Right now CLI script doesn’t know anything about existing Zend application. In order to properly use business-logic of our application, we have into set correct application environment, instantiate instance of Zend_Application and bootstrap it. Also, we should move bootstrapping code to separate file and reuse it between our CLI script,
index-test.php files. Considering all of this, let’s rewrite the script:
We need to require and configure Zend’s autoloader by hand, because our application isn’t yet bootstrapped at this point. Zend’s library should be in include path, otherwise we must manually add it using
set_include_path. We use
Symfony\Component\Console\Input\ArgvInput to get application’s environment from command-line. If it’s not passed, ‘development’ environment will be used. Note that we might want to save
$zendApp somewhere in order to reference to it in the future. I see 2 options:
- put it into
- create a subclass of
Symfony\Component\Console\Applicationwhich will receive instance of
Zend_Applicationas a constructor argument
As you might see, we’ve moved bootstrapping code into separate
bootstrapper.php file under project’s root. It might look like this:
index.php will be using it too:
Writing console commands
Every command is a subclass of
Symfony\Component\Console\Command\Command. In order to keep commands organized, we can add a new resource type called “command” by modifying Bootstrap class:
Now we could create
application/commands directory and add our commands there. For example, here is the Time command:
After creating command, we must add it to the list of known commands by calling
addCommands. This is true for all commands (Doctrine ORM, for instance, has many console commands):
Let’s see what time is it:
[cli-show]$ scripts/console app:time Current time: 18:12:02
Symfony Console is a really great component. It’s decoupled, so you can use it in any kind of application. Even if you aren’t going to write your own commands, you can still use this approach to integrate any library which uses Symfony Console, such as Doctrine ORM. And if you’re on PHP>=5.3 and facing a problem of writing console task, you should definitely use it.