David Caunt

PHP and Zend Framework Engineer

Subscribe to my RSS feed

Posts Tagged ‘zend-framework’

Easy command line scripts with Zend Application

February 25th, 2010

As PHP developers, it is convenient to be able to write command line scripts in PHP. In doing so, you will almost certainly want access to Zend Framework components and their configurations as if you are writing a normal MVC app, but without invoking the MVC stack and without loading unnecessary resources. I’ve seen solutions where actions are exposed as controller actions and called by wget – these are counter-intuitive, inefficient, and will suffer from max execution timeouts and other problems.

Zend_Applicaton to the rescue

Lets start with our website’s public/index.php – the script which sets up and launches an application. It looks roughly like this:

<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));
 
require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/config.php'
);
 
$application->bootstrap()->run();

One feature of Zend Application is that you can choose to bootstrap only certain resources, rather than all of those referenced in your application config and bootstrap (_init methods.) The following assumes that our script needs to use the database, and send an email.

<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));
 
require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/config.php'
);
 
//only load resources we need for script, in this case db and mail
$application->bootstrap(array('db', 'mail'));

Having bootstrapped the resources, we can retrieve them from the application as follows:

$db = $application->getBootstrap()->getResource('db');
 
//do something!
$row = $db->fetchRow('SELECT * FROM something');

Zend Framework Pitfalls Part 2 – Zend_Db Won’t Use the Query Cache with MySQL

November 28th, 2009

This one’s not limited to Zend Framework, but is actually a ‘problem’ in MySQL. I think it is worth covering, as the paragraph in the manual is easily missed.

From the MySQL manual:

Before MySQL 5.1.17, prepared statements do not use the query cache. Beginning with 5.1.17, prepared statements use the query cache under certain conditions, which differ depending on the preparation method

This means that if you’re running MySQL 5.0.x, not uncommon at the time of writing, your applications are not going to benefit from the query cache. There’s a simple workaround, however:

If you’re using Pdo, set the following driver option:

$pdoParams = array(
    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
);
 
$params = array(
    'host'           => '127.0.0.1',
    'username'       => 'webuser',
    'password'       => 'xxxxxxxx',
    'dbname'         => 'test',
    'driver_options' => $pdoParams
);

Zend_Config_Ini [parse_ini_file()] doesn’t support class constants, so ini users will have to supply the value of PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1000, in their configs:

resources.db.adapter         = pdo_mysql
resources.db.params.host     = localhost
resources.db.params.username = webuser
resources.db.params.password = xxxxxxxx
resources.db.params.dbname   = myDb
resources.db.params.driver_options.1000 = true

Zend Framework Pitfalls Part 1 – Zend_Auth

October 12th, 2009

Foreword

Zend Framework is excellent; this series of posts entitled ‘Zend Framework Pitfalls’ won’t try and dispute that. There are, however, one or two problems and poorly implemented components that can cause problems. Before using any library component it is important to be aware of any drawbacks and issues. It is then possible to make an objective decision before investing your time, and you can avoid banging your head against the desk understanding a known bug or problem that isn’t well documented.

Component

Zend_Auth

Priority

Minor (definition)

Problem

Zend_Auth is implemented as a singleton. This singleton references a single instance of Zend_Auth_Storage_Interface, used to persist an identity. This makes management of two or more authentication systems (e.g. frontend and admin) difficult. You must manually set the storage each time you want to query a different identity.

Solution 1 – Don’t use multiple authentication systems

In most simple web applications, you can use a single user database (table) to store both common users and administrators, and expose administrator privileges as appropriate via Zend_Acl or similar.

Solution 2 – Toggle storage

Zend_Auth has a method for changing storage, setStorage. Calling this method every time before retrieving the identity object is viable, but you have to remember to do so every time or you could read the wrong storage. This can be wrapped up for practicality:

class My_Auth extends Zend_Auth {
 
	public static function getInstance($storageNamespace = 'Zend_Auth'){
 
		// set namespace
		$this->setStorage(new Zend_Auth_Storage_Session($storageNamespace));
 
		return parent::getInstance();
	}
 
}

Remember to use this getInstance method every time you need to access your auth (and namespace) rather than storing a reference to the Zend_Auth instance.

Solution 3 – Your own implementation of Zend_Auth

Zend_Auth doesn’t actually do much heavy lifting. You could write something that can take advantage of the other Zend_Auth_* components, without implementing the singleton pattern. This is suggested in the reference manual.

Summary

It is unlikely that Zend_Auth will be re-architected for the 2.0 release of Zend Framework, the earliest opportunity for a break in backwards compatibility. Whether the singleton pattern is appropriate is debatable and a strongly advantageous alternative solution would be necessary to justify any changes.

As always, your comments and solution suggestions are welcomed.

Zend Image proposal accepted

October 10th, 2009

It’s official – Zend have accepted our Zend_Image proposal. Credit goes to Dolf Schimmel for writing the initial proposal and liaising with the Zend team.

Zend_Image will initially support two adapters, Gd and Imagick (ImageMagick), and Gmagick support may be added in future. The following common image operations will be supported:

  • Resize
  • Rotate
  • Watermark
  • Filtering
  • Format Conversion (e.g. JPG to PNG)
  • Drawing (lines, arcs, ellipses, polygon, text)

Major benefits of Zend_Image include portability and a uniform API across adaptors. It will also be possible to define custom and composite actions for reuse.

We’re excited to proceed with development and hoping for inclusion in the forthcoming 1.10 release. We welcome your feedback on the proposal page if you have ideas or comments.

Top