This series is designed for PHP developers who want to start using a framework, but have not examined the available frameworks in detail. This series examines why the three frameworks under examination were chosen, how to install each, and you'll get a good handle on the test application that you're going to extend in each framework. It might sound like a lot, but don't worry — we break it down into manageable chunks.
Part 1 of this series lays out the scope for the series, introduces the frameworks being examined, covers their installation, and scopes out the first test application you will build. (Phew!)
Part 2 walks you through building the sample application in each of the three frameworks, highlighting their similarities and differences.
Part 3 starts with extending the test application, then deals with exceptions to the rule. All frameworks work well when doing the tasks for which they were designed. Needing to do something the framework wasn't built to do happens on every project. Part 3 looks at such instances.
Part 4 focuses primarily on Ajax support. The use of Ajax, using native code and third-party libraries, is examined — specifically, how each framework behaves and accepts specific popular libraries.
Part 5 deals with working outside the frameworks. A single task is identified (nightly update script), and the process for accomplishing this task is examined in each framework.
Whenever an application interfaces with a database, it's not uncommon to find yourself needing to set up some automated tasks. Typically, these tasks are basic database management-oriented, such as table pruning, expiring accounts, etc. Historically speaking, it's common for these tasks to be written in Perl. While Perl is an excellent language, unless it is bringing something to the table that you don't already get from PHP, it makes more sense to write your automated tasks and your application with one language. It's easier to support, you can share code, and you don't get your syntax confused when switching back and forth.
In that spirit, since you've written Blahg in a framework, it would be awfully nice if you could continue to use the framework to execute common automated tasks. You can use the common structure that is already established, you can use methods you have already created, and you maintain that database independence you get from using a model instead of writing database interface code for a specific database. If you are going to use a framework, it makes sense to use it across the board.
In this article, you will look at writing an automated task for Blahg that prunes any posts older than 30 days. You will be able to call this task from the command line, enabling you to automate the task using a scheduler like cron. You'll build the application in each framework, getting a sense for how Zend, symfony, and CakePHP handle automated tasks differently.
You should have already gone through Parts 1-4, which cover installation, prerequisites, the initial application build and extension, and Ajax for each framework. If you haven't, you should do so now.
Note: Each article includes a ZIP file containing all the code built and discussed for the article. This file will be referred to throughout the article series as the code archive.
Let's get this out of the way now
Given the structure of the frameworks, there is a short path to creating an automated task that you can call from cron: Make the task an action in an existing (or new) controller and call the action using wget. There's absolutely no reason this will not work, and if you are looking for a down-and-dirty and, above all, insecure way of executing tasks, using wget would probably be fine.
But the word "insecure" in that sentence should raise some flags. By writing your automated tasks this way, you make them available to the world. Even if you don't link to the action in any way, use a controller named Mxyzptlk, or require a 40-character unique string that must be passed to the action before execution, the action is still available for the world to execute. Security through obscurity is no security at all. Since many automated tasks can tend to be database-intensive, you do not want these actions executed at random.
So, while there is a short path to automating your tasks you are ideally looking for a more secure approach. Each example below will show you one way to do things for each framework. There is always more than one way to do things. Once you get through the article, you may want to experiment on your own or do some additional research. See how other people have done it.
Also, do yourself a favor: back up your tables before you proceed. You will be deleting some records, and it will be helpful to be able to restore the tables to a default state for later testing.
Enough prologue. Let's dive in.
External tasks in the Zend Framework
Due to the pick-and-choose nature of the Zend Framework, creating an automated task using the framework allows for some flexibility in deciding what you use and don't use. Because you are not going to be accessing the Web application through the existing front controller, which services Web requests, you should create an additional controller to control script execution. This controller will look similar to the front controller, in that you will be registering the autoloader and defining the base adapter for the model. But an important difference may be in your PHP installation or configuration.
Compared to invoking PHP from the Web server, command-line PHP typically is executed
using a different Server Application Programming Interface (SAPI). Depending on your
installation and configuration, this may mean that the include path is different. For
this reason, you should set the include_path ini setting to include the /column/include
directory where you installed the Zend Framework files.
Note: Remember that the way you define the include_path
will be different depending on your OS. The example below is for Linux®.
Create a new directory called /column/protected/zend/scripts. This directory will be used to hold your scripts controller and any additional script-related files you create. Since you are only creating one task at this time, start by creating the file prune.php in the new scripts directory. The top half of this file will contain the primary code for your scripts controller.
Listing 1. Code for your scripts controller
<?php
ini_set('include_path', ini_get('include_path') . ':/column/include');
require_once("Zend/Loader.php");
Zend_Loader::registerAutoload();
$params = array(
'host' => 'localhost',
'username' => 'frameworks',
'password' => 'fwpw',
'dbname' => 'zend'
);
$db = Zend_Db::factory('PDO_MYSQL', $params);
Zend_Db_Table::setDefaultAdapter($db);
|
The rest of this file will contain the simple task you want to execute. Include
and instantiate the posts model, create a where clause and
run a standard delete query.
Listing 2. Task to execute
require_once("/column/protected/zend/models/Posts.php");
$posts = new Posts();
$where = $posts->getAdapter()->quoteInto('modified < ?',
date('Y-m-d H:i:s', strtotime('-30 days')));
$posts->delete($where);
?>
|
Once this is complete, you can execute this script at the command line: php /column/protected/zend/scripts/prune.php.
If you can call it from the command line, you can schedule it, batch it, or cron it. A
crontab entry to execute this script at midnight could look like this: 00 00 * * * php /column/protected/zend/scripts/prune.php.
Once you've built your scripts controller, you have a whole host of options for executing scripts using the Zend Framework. You can use the same models the rest of your application uses, create complex script objects where required, and more.
Now you have a good handle on how to do a cron job for Zend. Next, let's look at doing the same thing in symfony.
When you wanted to execute a command-line script in the Zend Framework, you created a scripts controller that would be used instead of your front controller. You will do much the same thing with symfony.
Create a directory to hold your symfony Blahg scripts — /column/protected/sf_column/apps/blahg/scripts/ — and create a file called prune.php to be your new scripts controller. The first half of this file will look much like the symfony front controller you created. You will define the required constants and require the config file. The difference in this case is in how you get the symfony instance. In the front controller, you told symfony to look for the controller and dispatch the request. For the script controller, this is not the case.
Listing 3. Defining the required constants and requiring the config file
<?php
define('SF_ROOT_DIR', '/column/protected/sf_column');
define('SF_APP', 'blahg');
define('SF_ENVIRONMENT', 'prod');
define('SF_DEBUG', false);
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR
.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
sfContext::getInstance();
|
Next, you'll create a basic Criteria to pass to the post
model and run the delete.
Listing 4. Creating the basic
Criteria
$c = new Criteria();
$c->add(PostPeer::MODIFIED, date("Y-m-d H:i:s",
strtotime("-45 days")), Criteria::LESS_THAN);
$posts = PostPeer::doDelete($c);
|
Save the file. That's all there is to it. Now you can execute the script at the
command line, much like you did in the Zend Framework: php /column/protected/sf_column/apps/blahg/scripts/prune.php.
Calling this task from a scheduler would look just like it did for the Zend Framework
(specifying the symfony script rather than the Zend script, of course). For cron, it
would look like this: 00 00 * * * php /column/protected/sf_column/apps/blahg/scripts/prune.php.
Finally, let's look at how you would do the same task in CakePHP.
The Cake console is a new feature in CakePHP V1.2 that provides a command-line interface to the Cake framework. To create your own command-line tasks, you create what is known as a shell. A shell looks much like the controllers you already created.
Start by creating the file prune.php in the
/column/protected/cakephp/app/vendors/shells directory. This is your new shell called
prune and will be used to delete any posts older than 30 days. Define a new class,
PruneShells, that extends the shell class. Since you are
going to be deleting posts, the shell will need to use the post model, which you can
specify using the $uses variable.
By default, when you tell Cake to execute a shell, and you pass no specific action,
Cake looks for a method called main and, if found, executes
the method. At this point, the empty shell would look like Listing 5.
Listing 5. Defining a new
PruneShells class
<?php
class PruneShell extends Shell {
var $uses = array('Post');
function main() {
}
}
?>
|
Now all you need to do is add code to the main method to delete any posts older than 30 days.
Listing 6. Deleting posts older than 30 days
$conditions = array (
"Post.modified" => "< " . date("Y-m-d H:i:s", strtotime("-30 days"))
);
$this->Post->deleteAll($conditions);
|
To execute this script from the command line, you tell Cake that you want to run
the prune shell. Since all the code is in the main method,
it will execute by default. You should also tell Cake what the app directory is. This
isn't necessary if you are running the command from the app directory, but a cron job
won't be executing from the right directory unless you tell it to:
/column/protected/cakephp/cake/console/cake prune -app /column/protected/cakephp/app/.
Scheduling a cron job to run at midnight that executes this shell would look like this:
00 00 * * * /column/protected/cakephp/cake/console/cake prune -app /column/protected/cakephp/app/.
Note: If you add the /column/protected/cakephp/cake/console directory to your
PATH, you don't have to specify the full path, which makes
working with the console much easier. Specifying the full path in your batch or cron
job will help ensure proper execution regardless of the user that executes the job.
Now that you can call it from the command line, you know you can batch it, cron it, or schedule it.
Writing automated tasks for your application has obvious benefits. You should be able to write these automated tasks in the framework of your choosing. By writing your tasks using your framework, you apply a consistent approach throughout your code and take advantage of the existing structure you already have in place.
As you may have noticed while testing out the prune scripts, comments and ranks associated with the posts may not have been orphaned when the pruned posts were deleted. Taking what you have already learned about the frameworks, modify each prune script so that the related comments and ranks are deleted during pruning. Try to use each frameworks particular way of interacting with related tables.
| Description | Name | Size | Download method |
|---|---|---|---|
| Part 5 sample code | os-php-fwk5-column_part5.zip | 32KB | HTTP |
Information about download methods
Learn
-
Read William Graham's blog for an example of using Ajax and Zend:
Ajax
101: A Simple Example of Using Ajax with the Zend Framework.
-
For a tutorial that will show you step by step how to create an Ajax-powered symfony
application in minutes, see "Easy Ajax in symfony."
-
See the Zend Framework manual.
-
Read the DevNetwork Forums discussion on Zend and Ajax.
-
For a good tutorial series on using the Zend Framework, read "Understanding
the Zend Framework, Part 1."
-
Another good Zend tutorial is "Getting
Started with the Zend Framework."
-
Get the symfony documentation.
-
Check out the "My first symfony project"
tutorial.
-
Get the CakePHP Manual. (Note: The manual is
written to CakePHP V1.1. There may be some variance as you are using CakePHP V1.2).
-
Read the five-part series "Cook
up Web sites fast with CakePHP."
-
Read the Wikipedia entry for an overview of software
frameworks.
-
Get an overview of Model-View-Controller architecture from Wikipedia.
-
Check out the PHP Manual.
-
PHP.net is the central resource for PHP developers.
-
Check out the "Recommended PHP reading list."
-
Browse all the PHP content on developerWorks.
-
Expand your PHP skills by checking out IBM developerWorks' PHP project resources.
-
To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
-
Using a database with PHP? Check out the Zend Core for
IBM, a seamless, out-of-the-box, easy-to-install PHP development and production environment that supports IBM DB2 V9.
-
Stay current with developerWorks' Technical events and webcasts.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
-
Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Participate in developerWorks blogs and get involved in the developerWorks community.
-
Participate in the developerWorks PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS).
Comments (Undergoing maintenance)





