Delphi for PHP - Integrating the Zend Framework: ZCache - Part 1

By: Jose Leon

Abstract: José León posted this article on his blog. This is the first article of the "Integrating Zend Framework" series.

Integrating Zend Framework: ZCache (I)

This is the first article of the "Integrating Zend Framework" series, one of the tasks in the VCL for PHP roadmap is to improve and expand the integration of Zend Framework, so, why not to blog about it at the same time we develop the code?

On this article, we are going to develop the ZCache component, a wrapper over Zend_Cache component, which will allow us to improve the performance of our application by caching certain parts, including output, function calls, etc.

Of course, the first thing we need to do is to read the documentation of what we want to wrap, you can find it here:

http://framework.zend.com/manual/en/zend.cache.html

And, in short, you get a general idea of what we can do:

  • ZCache wrapper component, with two clear parts, frontend and backend, that determine what the cache is able to store and where that information is stored
  • A Frontend property, which will be a drop down with the following values:
    • cfOutput: To allow cache output, will check to integrate it with the Control base classe and use it to cache output
    • cfFunction: To allow cache function calls, to be used in code
    • cfClass: To allow cache classes and static methods, to be used in code
    • cfFile: To allow cache file contents, to be used in code
    • cfPage: To allow cache a full page, this looks it will integrate well with the VCL for PHP Page class
  • Backend property
    • cbFile: Stores cache on a file
    • cbSQLite: Stores cache on a SQLite database
    • cbMemCached: Uses memcached, if installed
    • cbAPC: Uses APC, if installed
    • cbZendPlatform: Uses the caching of Zend Platform, if installed
  • A frontend/backend has common properties, that are strong candidates to become properties of the ZCache object itself, the custom properties depending on the type of frontend/backend, will be designed as a grouped property
  • Methods for frontend/backend, will also be added to the ZCache object and will call the frontend/backend counterpart

Writing the wrapper

Let’s start by writing the wrapper component code and installing it on the IDE, to do that, create an empty unit and store it on the VCL for PHP folder\Zend, and name it zcache.inc.php.

Let’s add some stub code, so it looks like this:

<?php

require_once("vcl/vcl.inc.php");

use_unit("Zend/zcommon.inc.php");

use_unit("classes.inc.php");

use_unit("Zend/framework/library/Zend/Cache.php");

class ZCache extends Component

{

}

?>

The unit zcommon.inc.php contains common code to initialize properly Zend Framework session system to work well with VCL for PHP one, it’s used by all the Zend Framework wrappers. After that, let’s include the Cache.php unit that contain the code we need to develop this wrapper.

Now, open zf.package.php and add the line to install the component into the IDE:

registerComponents("Zend",array("ZCache"),"Zend/zcache.inc.php");

Using Component | Packages, uncheck and check again the VCL for PHP components for Zend Framework package, so we get our component installed on the Tool Palette. If we create a new form and drop the component, it will be shown as an icon, because it doesn’t provide any visual output and inherits directly from Component.

Adding properties

We need to add two properties, Frontend and Backend, and those properties can have several values from a closed set, so will be shown on the Object Inspector using a drop down. Let’s add the values for each property:

...............

use_unit("Zend/framework/library/Zend/Cache.php");

define('cfOutput','cfOutput');

define('cfFunction','cfFunction');

define('cfClass','cfClass');

define('cfFile','cfFile');

define('cfPage','cfPage');

define('cbFile','cbFile');

define('cbSQLite','cbSQLite');

define('cbMemcached','cbMemcached');

define('cbAPC','cbAPC');

define('cbZendPlatform','cbPlatform');

class ZCache extends Component

...............

And now, add the properties using Shift+Ctrl+Alt+U, and set their default values also:

protected $_frontend=cfOutput;

function getFrontend() { return $this->_frontend; }

function setFrontend($value) { $this->_frontend=$value; }

function defaultFrontend() { return cfOutput; }

protected $_backend=cbFile;

function getBackend() { return $this->_backend; }

function setBackend($value) { $this->_backend=$value; }

function defaultBackend() { return cbFile; }

Adding common Frontend properties

Like stated earlier, frontends have common properties, here is the list, so let’s add them to the component, but following a common naming structure to match with the VCL for PHP:

protected $_enabled="1";

function getEnabled() { return $this->_enabled; }

function setEnabled($value) { $this->_enabled=$value; }

function defaultEnabled() { return "1"; }

protected $_prefix="";

function getPrefix() { return $this->_prefix; }

function setPrefix($value) { $this->_prefix=$value; }

function defaultPrefix() { return ""; }

protected $_lifetime=3600;

function getLifetime() { return $this->_lifetime; }

function setLifetime($value) { $this->_lifetime=$value; }

function defaultLifetime() { return 3600; }

protected $_logging="0";

function getLogging() { return $this->_logging; }

function setLogging($value) { $this->_logging=$value; }

function defaultLogging() { return "0"; }

protected $_checkwrite="1";

function getCheckWrite() { return $this->_checkwrite; }

function setCheckWrite($value) { $this->_checkwrite=$value; }

function defaultCheckWrite() { return "1"; }

protected $_serialization="0";

function getSerialization() { return $this->_serialization; }

function setSerialization($value) { $this->_serialization=$value; }

function defaultSerialization() { return "0"; }

protected $_cleaningfactor=10;

function getCleaningFactor() { return $this->_cleaningfactor; }

function setCleaningFactor($value) { $this->_cleaningfactor=$value; }

function defaultCleaningFactor() { return 10; }

protected $_ignoreuserabort="0";

function getIgnoreUserAbort() { return $this->_ignoreuserabort; }

function setIgnoreUserAbort($value) { $this->_ignoreuserabort=$value; }

function defaultIgnoreUserAbort() { return "0"; }

Adding common Backend properties

Let’s add also the common backend properties:

protected $_cachedir='/tmp/';

function getCacheDir() { return $this->_cachedir; }

function setCacheDir($value) { $this->_cachedir=$value; }

function defaultCacheDir() { return '/tmp/'; }

protected $_filelocking="1";

function getFileLocking() { return $this->_filelocking; }

function setFileLocking($value) { $this->_filelocking=$value; }

function defaultFileLocking() { return "1"; }

protected $_checkread="1";

function getCheckRead() { return $this->_checkread; }

function setCheckRead($value) { $this->_checkread=$value; }

function defaultCheckRead() { return "1"; }

protected $_readcontroltype=rctCRC32;

function getReadControlType() { return $this->_readcontroltype; }

function setReadControlType($value) { $this->_readcontroltype=$value; }

function defaultReadControlType() { return rctCRC32; }

protected $_hasheddirectorylevel=0;

function getHashedDirectoryLevel() { return $this->_hasheddirectorylevel; }

function setHashedDirectoryLevel($value) { $this->_hasheddirectorylevel=$value; }

function defaultHashedDirectoryLevel() { return 0; }

protected $_hasheddirectoryumask='700';

function getHashedDirectoryUmask() { return $this->_hasheddirectoryumask; }

function setHashedDirectoryUmask($value) { $this->_hasheddirectoryumask=$value; }

function defaultHashedDirectoryUmask() { return '700'; }

protected $_filenameprefix='zend_cache';

function getFileNamePrefix() { return $this->_filenameprefix; }

function setFileNamePrefix($value) { $this->_filenameprefix=$value; }

function defaultFileNamePrefix() { return 'zend_cache'; }

protected $_cachefileumask='700';

function getCacheFileUmask() { return $this->_cachefileumask; }

function setCacheFileUmask($value) { $this->_cachefileumask=$value; }

function defaultCacheFileUmask() { return '700'; }

protected $_metadatasize=100;

function getMetadataSize() { return $this->_metadatasize; }

function setMetadataSize($value) { $this->_metadatasize=$value; }

function defaultMetadataSize() { return 100; }

Adding design-time interface for the properties

Some properties have boolean values, and also there is a property that can take several values, so let’s register a valid property editor for them in the package:

registerPropertyValues("ZCache", "ReadControlType", array('rctCRC32', 'rctMD5', 'rctADLER32', 'rctSTRLEN'));

registerBooleanProperty("ZCache", "Enabled");

registerBooleanProperty("ZCache", "Logging");

registerBooleanProperty("ZCache", "CheckWrite");

registerBooleanProperty("ZCache", "Serialization");

registerBooleanProperty("ZCache", "IgnoreUserAbort");

registerBooleanProperty("ZCache", "FileLocking");

registerBooleanProperty("ZCache", "CheckRead");

Adding grouped properties for Frontend options

Some frontends have custom properties, so we need to create classes to hold those properties, on the article, we are going only to see the implementation of the Frontend Function properties, the rest are omitted to prevent this article to became big:

class ZCacheFrontendFunctionOptions extends Persistent

{

protected $_cachebydefault = "1";

function getCacheByDefault() { return $this->_cachebydefault; }

function setCacheByDefault($value) { $this->_cachebydefault = $value; }

function defaultCacheByDefault() { return "1"; }

protected $_cachedfunctions = array();

function getCachedFunctions() { return $this->_cachedfunctions; }

function setCachedFunctions($value) { $this->_cachedfunctions = $value; }

function defaultCachedFunctions() { return array(); }

protected $_noncachedfunctions = array();

function getNonCachedFunctions() { return $this->_noncachedfunctions; }

function setNonCachedFunctions($value) { $this->_noncachedfunctions = $value; }

function defaultNonCachedFunctions() { return array(); }

}

This class must inherit from Persistent, so the IDE is able to identify we want to make a subproperty, now, let’s add the property to the component:

protected $_frontendfunctionoptions = null;

function getFrontendFunctionOptions() { return $this->_frontendfunctionoptions; }

function setFrontendFunctionOptions($value) { $this->_frontendfunctionoptions = $value; }

function defaultFrontendFunctionOptions() { return null; }

And initialize it on the component constructor:

class ZCache extends Component

{

function __construct($aowner = null)

{

//Calls inherited constructor

parent::__construct($aowner);

$this->_frontendfunctionoptions= new ZCacheFrontendFunctionOptions();

}

....................

Now, when you drop a ZCache component into a Page, you will see a grouped property you can expand using the (+) at the left of the name, and get the subproperties for this property.

Now, you just need to repeat the process for all frontends options.

Registering property editors for subproperties

You also need to tell the IDE which property editor to use to edit those subproperties, so let’s add them:

registerBooleanProperty("ZCache", "FrontendFunctionOptions.CacheByDefault");

registerPropertyEditor("ZCache","FrontendFunctionOptions.CachedFunctions","TStringListPropertyEditor","native");

registerPropertyEditor("ZCache","FrontendFunctionOptions.NonCachedFunctions","TStringListPropertyEditor","native");

And once you have all in place, this is the final result you get in the OI:

Hide image
Hide image

I will continue this article by adding all Backend options and creating the Zend_Cache object using all these properties, stay tuned!

Server Response from: ETNASC03