Whether you have a big or small budget are time rich or poor, there’s always the pressure to build applications with the future in mind. This means that we, as developers, have to ensure that they are built around two key concepts:
No matter how much people tell us that “I only want a simple application”, after building more than a handful of applications and working with a number of clients, your experience will begin to tell you that they’ll often want more.
Now this can be a good thing. When you do a good job, and clients pay, you can be happily rewarded for your efforts. When they don’t is a matter for another time and post. What’s more, put your hand up if you know the valid truth of:
It’s cheaper to keep an existing client than to gain a new one
So amongst the multitude of other advice you’ll receive throughout your life, building applications that are readily extensible and extendable – in a simple, clean and cost-efficient manner – is essential to keeping input as low as possible, whilst maximising output, and accompanying client satisfaction (or boss satisfaction if you’re full-time employed).
Now, like all things, there are many ways to skin a cat. But as Malt Blue is all about learning the Zend Framework, I want to show you a way to build easily extendable and extensible applications with it.
To do this, I’m going to show you an approach based a component that’s already available within the context of the Framework, one of its most effective aspects in my, not so, humble opinion.
What is it? It’s none other than:
Let’s have a quick introduction then get started building a simple example. This will show why it’s so effective in building extensible applications.
Quoting the Zend_Application reference section from the Zend Framework Manual:
Zend_Application provides a bootstrapping facility for applications which provides reusable resources, common- and module-based bootstrap classes and dependency checking. It also takes care of setting up the PHP environment and introduces autoloading by default.
Whether it’s the managing translations that are rendered through the view templates; connecting to one or more databases so that we can manipulate data in an RDBMS; or accessing system-wide caches so that we can store application objects, results of database queries, view templates or something else entirely; resource plugins take care of common and reusable functionality that we should only need to configure once, not repeatedly in a multitude of different ways.
And implementing resource plugins as the cornerstone of how we work with the framework, allows us to have a clear and consistent interface to the various components that we use, yet at the same time, provide us with the ability to adjust how it works, under the hood, in so doing adjust to meet the changing needs of our users as the needs demand.
It’s all made possible because they’re based around …
Wikipedia defines the strategy pattern as follows:
the strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.[1]
In short, the strategy pattern provides resource plugins the capability to expose a resource to our controller actions, yet not be concerned with the underlying algorithm or implementation doing the work.
If you’ve used the Zend Framework for any length of time, you’ll be familiar with both the Db and Log resource plugins. Through the use of the strategy pattern in both of these resource plugins, we can use the same interface, yet:
Have a look at the following examples, taken with liberty, from the Zend Framework manual):
resources.db.adapter = "pdo_mysql" resources.db.params.host = "localhost" resources.db.params.username = "webuser" resources.db.params.password = "XXXXXXX" resources.db.params.dbname = "test" resources.db.isDefaultTableAdapter = true |
We could instead export the schema and adjust it to work with PostgreSQL, SQLServer, Firebird, or SQLite, import the data and continue working. Our users wouldn’t know the difference – unless there was a performance drop.
resources.log.stream.writerName = "Stream" resources.log.stream.writerParams.stream = APPLICATION_PATH "/../data/logs/application.log" resources.log.stream.writerParams.mode = "a" resources.log.stream.filterName = "Priority" resources.log.stream.filterParams.priority = 4 |
Say we migrated to a host that doesn’t have a persistent filesystem, such as cloudControl, we could change the configuration to use FirePHP, or we could write our own adapter to store the results in Memcache or MongoDB.
In both of these scenarios, we don’t have to change any of our controller code when we make changes in the underlying resource. New developers don’t need to be experts in the technology and we’re now bound to a specific technology or approach to solving a situation.
So that’s why I’m advocating that to build extensible and extendable Zend Framework-based applications, we need to use this approach as one of the key aspects in how we develop with it.
Now it’s all well and good to talk about one, but what about when the rubber meets the road? As Danny Devito said to Arnold Schwarzenegger in Twins, “Money Talks and Bullshit Walks”.
So let’s consider a tangible scenario now. Let’s say that you’re building an application that needs to store files. Let’s say that people can register and upload their favourite recipes of what they cook to the interweb for all their friends and family to see – in the age of Facebook, Flickr etc, this is quite feasible.
Let’s say that it’s a proof of concept and you’re not sure if it’s going to take off or not, so you don’t want to bet the farm and over-invest at this early stage. But you want something that can at least be a reliable test bed. What do you do?
Well, you do like any sane-minded person would do – you keep it simple, using proven options and grow as your customers demand. So we’re going to write a resource plugin that allows us to store files.
Now no, it won’t be all singing and all dancing, but you’ll see just how easy it is to do for starters and secondly that you have a single, consistent programming interface to use in your controller actions – one that won’t require any changes later, but will be super flexible and capable.
Ready? Great. Let’s Go!
To do it is actually quite easy, but does involve a couple of steps. These are:
So let’s get started and build our shiny new resource plugin:
Under the library folder create the following directory structure:
Sample/ File/ Storer/ Adapter/ |
Then, create a file called Interface.php in Sample/File/Storer that looks like the following:
interface Sample_File_Storer_Interface { public function persist($userId, $filename); public function update($userId, $oldFile, $newFile); public function unlink($userId, $filename); } |
This defines three methods that each adapter must implement:
Though we’re not implementing update and unlink in this example, they’re there for a sense of completeness. Next, create a file, Factory.php in Sample/File/Storer that looks like the following:
class Sample_File_Storer_Factory { private function __construct() {;} public static function factory($options = null) { $adapterClass = 'Sample_File_Storer_Adapter_' . ucfirst(strtolower($options->adapter)); if (class_exists($adapterClass)) { if (!empty($options)) { $class = new $adapterClass($options); } else { $class = new $adapterClass(); } return $class; } else { throw new Sample_File_Storer_Exception(sprintf( 'Specified adapter \'%s\' is not available', $adapterClass )); } return null; } } |
This will return a Sample_File_File_Storer adapter class, based on the adapter type we set in the resource plugin configuration, which we’re setting up later. If an adapter class is not found, matching the one we specify, an exception will be thrown.
Next, create a file, Exception.php in Sample/File/Storer that looks like the following:
class Sample_File_Storer_Exception extends Exception { } |
This is a simple exception class, based off of the core PHP exception class. Then create a file, File.php in Sample/File/Storer/Adapter that looks like the following:
class Sample_File_Storer_Adapter_File implements Sample_File_Storer_Interface { protected $_basepath; public function __construct($options) { $this->_basepath = $options->basepath; } public function persist($userId, $filename) { if (!is_writable($this->_basepath)) { return false; } if ($this->_prepareStorage($userId)) { if (copy($filename, $this->_basepath . $userId . '/' . basename($filename)) === FALSE) { return false; } unlink($filename); } return true; } protected function _prepareStorage($userId) { if (!file_exists($this->_basepath . $userId)) { if (mkdir($this->_basepath . $userId) === FALSE) { return false; } } } } |
This is the adapter, which is responsible for managing files on the filesystem. It utilises one configuration, basepath, which gives it a place in the filesystem where it will store files under.
Now we need to create a file, Filemanager.php in Sample/Application/Resource that looks like the following:
class Sample_Application_Resource_Filemanager extends Zend_Application_Resource_ResourceAbstract { protected $_storageAdapter; public function init() { return $this->initialiseResource(); } public function setAdapter($adapter) { $this->_storageAdapter = $adapter; return $this; } public function initialiseResource() { // get the resource options $options = (object)$this->getOptions(); $this->setAdapter( Sample_File_Storer_Factory::factory($options) ); return $this->_storageAdapter; } } |
This takes care of calling the factory method on Sample_File_Storer_Factory for the adapter that we’ve specified when we make use of the plugin. This affords us a simple interface for initialising the adapter class, irrespective of the one that is chosen.
In application.ini, add the following configuration. This adds our resource plugin to the application.
; Sample resource plugins pluginPaths.Sample_Application_Resource = APPLICATION_PATH "/../library/Sample/Application/Resource" |
Then add the following, which sets the adapter type, in this case ‘file’ and the basepath for storing files.
resources.filemanager.adapter = "file" resources.filemanager.basepath = APPLICATION_PATH "/../public/videos/" |
With all this in place, we’re ready to use it to store files throughout our application. So let’s use it.
In your controller action, add the following code:
$front = Zend_Controller_Front::getInstance(); $this->_fileManager = $front->getParam('bootstrap')->getResource('filestorer'); if ($this->_fileManager->persist($this->_auth->getIdentity()->id, $form->videofile->getFileName()) ) { $this->_flashMessenger->addMessage('File post-processed'); } else { $this->_flashMessenger->addMessage('File not able to be post-processed'); } |
This will retrieve a copy of the resource plugin and attempt to use it to store a file. I’ve assumed here that you’re uploading a file using the Zend_Form file element and you’ve gone through the normal validation process.
If you’re not familiar with the Zend_Form file element, have a look at the documentation in the manual. It’s not quite complete, but is worth reading – along with posts from Rob Allen.
So ok, the application’s up and running and going well, but you’re finding that the filesystem is just not keeping up with the demands of the application. No matter what kind of configuration you try, it’s just not up to the task.
So you want to test out mongoDB instead. It has built-in sharding, balancing and fail-over. You’ve done some research, you see that some pretty smart people are involved with it from the PHP community and believe that it will be a good candidate to allow you to grow in to the future. How do we use it instead of the filesystem adapter?
Well, without going in to the specifics of a mongoDB implementation, the steps involved would, roughly, be as follows:
Like anything worthwhile, there’ll be more to it than this, but the fundamental aspect is that:
And there you have it. To be fair, it is a little bit of work, but you can see from this simple example, that we’re able to provide a reusable file persistence plugin that is:
Now, ok I’m not aware of any silver bullet that will solve all the future demands and directions of your applications, but using the Zend Framework and resource plugins, you will go a long way towards future-proofing the ones that you create.
So, share your thoughts in the comments.
Image copyright © Atlantic
If you're new to or migrating to the Zend Framework this book will help you get up and running quickly.
Whether you're completely new to Zend Framework, have experience in PHP or other MVC-based frameworks, this book will teach you what you need to know to successfully develop applications with Zend Framework 2. Register your interest TODAY to get your copy of the book when it's released in April
Why Kohana is an Excellent Alternative to Zend Framework
20 Jul 2012

Writing a simple blog with Zend Framework and mongoDB
07 Nov 2010

Zend Framework 2 – Hydrators, Models and the TableGateway Pattern
15 May 2013

Zend Framework 2 Event Manager – A Gentle Introduction
15 Jan 2013
[...] http://www.maltblue.com/zend-framework/how-to-build-and-extendable-zend-framework-application [...]