Archive for the ‘Frameworks’ Category
Testing Zend Framework Action Controllers With Mocks
In this post I’ll demonstrate a unit test technique for testing Zend Framework Action Controllers using Mock Objects. Unit testing controllers independently has a number of advantages:
- You can develop controllers test-first (TDD).
- It allows you to develop and test all of your controller code before developing any of the view scripts.
- It helps you quickly identify problems in the controller, rather than problems in one of the combination of Model, View and Controller.
The Action Controller I’m going to test has only one method, profileAction():
tests/application/controllers/UserController.php
class UserController extends Zend_Controller_Action
{
public function profileAction()
{
$this->view->userId = $this->_getParam('user_id');
return $this->render();
}
}
tests/application/ControllerTestCase.php
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
public $application;
public function setUp()
{
$this->application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/config/application.ini'
);
$this->bootstrap = array($this, 'bootstrap');
parent::setUp();
}
public function tearDown()
{
Zend_Controller_Front::getInstance()->resetInstance();
$this->resetRequest();
$this->resetResponse();
$this->request->setPost(array());
$this->request->setQuery(array());
}
public function bootstrap()
{
$this->application->bootstrap();
}
}
tests/application/controllers/UserControllerTest.php
require_once TESTS_PATH . '/application/ControllerTestCase.php';
require_once APPLICATION_PATH . '/controllers/UserController.php';
class UserControllerTest extends ControllerTestCase
{
public function testStubRenderMethodCall()
{
$request = $this->getRequest()
->setRequestUri('/user/profile/1')
->setParams(array('user_id'=>1))
->setPathInfo(null);
$response = $this->getResponse();
$this->getFrontController()
->setRequest($request)
->setResponse($response)
->throwExceptions(true)
->returnResponse(false);
$controller = $this->getMock(
'UserController',
array('render'),
array($request, $response, $request->getParams())
);
$controller->expects($this->once())
->method('render')
->will($this->returnValue(true));
$this->assertTrue($controller->profileAction());
$this->assertTrue($controller->view->user_id == 1);
}
}
You can go further making both the tests and the implementation more sophisticated. The main point is that you can build and test a controller in a way that doesn’t require a view script to be written to do so.
Zend Framework Known Issues
By default Zend_Test_PHPUnit_ControllerTestCase sets the redirector exit value to false, leading to unexpected behavior when unit testing your code. For that reason, make sure you always add a return statement after calling a utility method:
class UserController extends Zend_Controller_Action
{
public function profileAction()
{
if (null == $this->_getParam('user_id', null) {
return $this->_redirect('/');
}
return $this->render();
}
}
If you want the Front Controller to throw exceptions, you have no other choice than to overwrite the dispatch method and pass a boolean TRUE to the throwExceptions() method:
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
...
public function dispatch($url = null)
{
// redirector should not exit
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$redirector->setExit(false);
// json helper should not exit
$json = Zend_Controller_Action_HelperBroker::getStaticHelper('json');
$json->suppressExit = true;
$request = $this->getRequest();
if (null !== $url) {
$request->setRequestUri($url);
}
$request->setPathInfo(null);
$this->getFrontController()
->setRequest($request)
->setResponse($this->getResponse())
->throwExceptions(true)
->returnResponse(false);
$this->getFrontController()->dispatch();
}
...
}
The Dispatcher not only violates the DRY principle but also suffers from amnesia. The problem is that it doesn’t store the instance of the Action Controller, instead, it destroys it (Zend_Controller_Dispatcher_Standard Line 305). You can easily get around this issue by extending the standard dispatcher and overwriting the dispatch() method:
class Zf_Controller_Dispatcher_Standard extends Zend_Controller_Dispatcher_Standard
{
...
public function dispatch($url = null)
{
...
Zend_Registry::set('Zend_Controller_Action', $controller);
// Destroy the page controller instance and reflection objects
$controller = null;
}
This will allow you to access the view object after dispatching the request:
class ExampleControllerTest extends ControllerTestCase
{
public function testDefaultActionRendersViewObject()
{
$this->dispatch('/');
$controller = Zend_Registry::get('Zend_Controller_Action');
$this->assertEquals('ExampleController', get_class($controller));
$this->assertTrue(isset($controller->view));
}
Links
PHPUnit: Testing Zend Framework Controllers
PHPUnit: Mock Objects
Symfony 1.3 Web Application Development
Packt Publishing recently sent me a copy of the book “Symfony 1.3 Web Application Development” to review.
This book is not a reference guide, but an example driven tutorial that takes you through the process of building Model-View-Controller-based web applications. You will learn how to create and develop a simple online store application. It also covers best practices for better and quicker application development.
The book is based on the latest version of the Symfony Framework, and does a great job telling you what you get out of the box and how it works, which is perfect for hitting the ground running. During the development you are introduced to the concepts and features of the MVC framework. However, for those who want to know more about the framework, the book doesn’t explain how things work under the covers. This book is more for beginners who want to get started with Symfony 1.3.
One thing I didn’t like about this book is that it uses Propel instead of Doctrine as the default ORM framework. Apart from that, it does a great job explaining and demonstrating with practical examples how to build a Web application from scratch.
Overall, and considering that some of the topics in this book have already been covered in Practical Symfony 1.3, I rate this book 4 out of 5.
Database Replication Adapter for Zend Framework Applications
Database replication is an option that allows the content of one database to be replicated to another database or databases, providing a mechanism to scale out the database. Scaling out the database allows more activities to be processed and more users to access the database by running multiple copies of the databases on different machines.
The problem with monolithic database designs is that they don’t establish an infrastructure that allows for rapid changes in business requirements. Here is where database replication comes into play. Replication can be used effectively for many different purposes, such as separating data entry and reporting, distributing load across servers, providing high availability, etc.
In 2008, Paul M. Jones announced the release of an SQL adapter that allows Solar users to connect to master/slave database installations. My first reaction was: Great! This will inspire other FOSS developers to create similar components. And guess what, it did. I wrote my own ReplicationAdapter. It’s not great, but it’s flexible enough to support the most commonly used replication scenarios:
Single-Master Replication
In the simplest replication scenario, the master copy of directory data is held in a single read-write replica on one server called the supplier server. The supplier server also maintains changelog for this replica. On another server, called the consumer server, there can be multiple read-only replicas.
Configuration array:
$db = array(
'adapter' => 'Pdo_Mysql',
'driver_options' => array(PDO::ATTR_TIMEOUT=>5),
'username' => 'root',
'password' => 'root',
'dbname' => 'test',
'master_servers' => 1,
'servers' => array(
array('host' => 'db.master-1.com'),
array('host' => 'db.slave-1.com'),
array('host' => 'db.slave-2.com')
)
);
// or ...
$db = array(
'adapter' => 'Pdo_Mysql',
'driver_options' => array(PDO::ATTR_TIMEOUT=>5),
'dbname' => 'test',
'master_servers' => 1,
'servers' => array(
array('host' => 'db.master-1.com', 'username' => 'user1', 'password'=>'pass1'),
array('host' => 'db.slave-1.com', 'username' => 'user2', 'password' => 'pass2'),
array('host' => 'db.slave-2.com', 'username' => 'user3', 'password' => 'pass3')
)
);
Zend_Registry::set('db_config_array', $db);
In the setup above, all writes will go to the master connection and all reads will be randomly distributed across the available slaves.
Multi-Master Replication
This type of configuration can work with any number of consumer servers. Each consumer server holds a read-only replica. The consumers can receive updates from all the suppliers. The consumers also have referrals defined for all the suppliers to forward any update requests that the consumers receive.
$db = array(
'adapter' => 'Pdo_Mysql',
'driver_options' => array(PDO::ATTR_TIMEOUT=>5),
'username' => 'root',
'password' => 'root',
'dbname' => 'test',
'master_servers' => 2,
'master_read' => true,
'servers' => array(
array('host' => 'db.master-1.com'),
array('host' => 'db.master-2.com')
)
);
Zend_Registry::set('db_config_array', $db);
Using a distributed memory caching system
Database connections are expensive and it’s very inefficient for an application to try to connect to a server that is down or not responding. A distributed memory caching system can help alleviate this problem by keeping a list of all the failed connections in memory, sharing that information across multiple servers and allowing the application to access it before attempting to open a connection.
To enable this option, you have to register an instance of the Memcached adapter class:
Zend_Registry::set('db_config_array', $db);
...
$cache = Zend_Cache::factory('Core', 'Zend_Cache_Backend_Memcached', $f, $b);
Zend_Registry::set('Zend_Cache', $cache);
Zend Framework Example
Here is a short and simple example of how the ReplicationAdapter might be used in a ZF application:
class SingleMasterDb extends Zf_Db_ReplicationAdapter
{
public function fecthAll()
{
$db = $this->getConnection('slave');
$query = $db->select()->from('test');
return $db->fetchAll($query);
}
public function insert($data)
{
$db = $this->getConnection('master');
$db->insert('test', $data);
return $db->lastInsertId();
}
public function update($id, $data)
{
$db = $this->getConnection('master');
$where = $db->quoteInto('id = ?', $id);
return $db->update('test', $data, $where);
}
}
Source Code:
http://fedecarg.com/repositories/show/zfreplicationadapter
Adding theme support to your Zend Framework application
This is a brief explanation on how to add theme support to your Zend Framework application and how to ensure those themes are self-contained, easy to distribute and install.
Themes are very powerful and extremely easy to develop. They allow you to quickly switch between layouts and change the look and feel of your application. You can use themes to show, for example, a mobile friendly version of your site.
Making a Zend Framework application theme-able is a three-step process.
First, modify your directory structure:
application/
controllers/
library/
public/
themes/
default/
css/
images/
templates/
custom/
css/
images/
templates/
Then, edit your Bootstrap class:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initView()
{
$theme = 'default';
if (isset($this->config->app->theme)) {
$theme = $this->config->app->theme;
}
$path = PUBLIC_PATH.'/themes/'.$theme.'/templates';
$layout = Zend_Layout::startMvc()
->setLayout('layout')
->setLayoutPath($path)
->setContentKey('content');
$view = new Zend_View();
$view->setBasePath($path);
$view->setScriptPath($baseDir);
return $view;
}
}
And finally, copy your view scripts and layouts to the templates directory:
application/
library/
public/
themes/
full-site/
css/
images/
templates/
error/
index/
partials/
layout.phtml
mobile-site/
css/
images/
templates/
Voila, mission accomplished.
Zend Framework DAL: DAOs and DataMappers
A Data Access Layer (DAL) is the layer of your application that provides simplified access to data stored in persistent storage of some kind. For example, the DAL might return a reference to an object complete with its attributes instead of a row of fields from a database table.
A Data Access Objects (DAO) is used to abstract and encapsulate all access to the data source. The DAO manages the connection with the data source to obtain and store data. Also, it implements the access mechanism required to work with the data source. The data source could be a persistent store like a database, a file or a Web service.
And finally, a DataMapper is used to move data between the object and a database while keeping them independent of each other. The DataMapper main responsibility is to transfer data between the two and also to isolate them from each other.
Zend Framework Example
app/
controllers/
UserController.php
views/
lib/
Project/
Dao/
Db/
User.php
Service/
User.php
DataMapper/
User.php
Entity/
User.php
Model/
User.php
Zf/
DataSource/
Dao/
Mapper.php
Domain/
Entity.php
Db/
Adapter.php
Database Table Structure
CREATE TABLE `user` ( `id` int(11) NOT NULL auto_increment, `first_name` varchar(100) NOT NULL, `last_name` varchar(100) NOT NULL, PRIMARY KEY (`id`) )
The User DAO
The DAO pattern provides a simple, consistent API for data access that does not require knowledge of an ORM interface. DAO does not just apply to simple mappings of one object to one relational table, but also allows complex queries to be performed and allows for stored procedures and database views to be mapped into data structures.
A typical DAO design pattern interface is shown below:
class Project_Dao_Db_User extends Zf_Db_Adapter
{
public function find($id)
{
$db = $this->getConnection();
$query = $db->select()->from('user')->where('id = ?', $id);
return $db->fetchRow($query);
}
public function findAll()
{
$db = $this->getConnection();
$query = $db->select()->from('user');
return $db->fetchAll($query);
}
public function insert($data)
{
$db = $this->getConnection();
$db->insert('user', $data);
return $db->lastInsertId();
}
public function update($id, $data)
{
$db = $this->getConnection();
$where = $db->quoteInto('id = ?', $id);
return $db->update('user', $data, $where);
}
public function delete($id)
{
$db = $this->getConnection();
$where = $db->quoteInto('id = ?', $id);
return $db->delete('user', $where);
}
}
Source Code: Zf_Db_Adapter
The User Entity
An Entity is anything that has continuity through a life cycle and distinctions independent of attributes that are important to the application’s user.
class Project_Entity_User extends Zf_Domain_Entity
{
public $id;
public $firstName;
public $lastName;
}
Source Code: Zf_Domain_Entity
The User DataMapper
class Project_DataMapper_User extends Zf_DataSource_Dao_Mapper
{
protected $_map = array(
'id' => 'id',
'first_name' => 'firstName',
'last_name' => 'lastName'
);
public function find($id)
{
$dao = new Project_Dao_Db_User();
$row = $dao->find($id);
if (!$row) {
return false;
}
return $this->map($row);
}
}
Source Code: Zf_DataSource_Dao_Mapper
The User Model
The following class represents the User Relational Model:
class Project_Model_User
{
public function getUser($id)
{
$mapper = new Project_DataMapper_User();
$mapper->setEntity(new Project_Entity_User());
$user = $mapper->find($id);
return $user;
}
}
The User Controller
class UserController extends Zend_Controller_Action
{
public function viewAction()
{
$model = new Project_Model_User();
$user = $model->getUser($this->_getParam('id'));
if ($user) {
$userId = $user->getId();
$userFirstName = $user->getFirstName();
$userLastName = $user->getLastName();
// get an array of database fields and values
$row = $user->getRow();
}
}
}
Keep in mind that ORM tools such as phpDataMapper and Doctrine offer an alternative way of modeling data. ORMs and ERMs are popular with Web frameworks, and the combination of an ORM and DDD makes DAOs redundant, however, it has not been proven to be better than a straightforward approach of implementing a collection of domain-specific data access functions.
That’s all, I hope you’ve found this post useful.
Increase speed and reduce bandwidth usage with ZF and Apache
Apache’s mod_deflate module provides the DEFLATE output filter that allows output from your server to be compressed before being sent to the client over the network.
There are two ways of enabling gzip compression:
- Using Apache’s mod_deflate
- Using PHP’s built-in functions
Encoding the output and setting the appropriate headers manually makes the code more portable. Keep in mind that there are hundreds of Linux distributions, each slightly different to significantly different. To allow portability the application should not make assumptions about the OS or config involved.
Using Apache
1. Enable mod_deflate
Debian/Ubuntu:
$ a2enmod deflate $ /etc/init.d/apache2 force-reload
2. Configure mode_deflate
$ nano /etc/apache2/mods-enabled/deflate.conf # # mod_deflate configuration # <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript DeflateCompressionLevel 9 BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html DeflateFilterNote Input instream DeflateFilterNote Output outstream DeflateFilterNote Ratio ratio </IfModule>
Using PHP
Create a gzip compressed string in your bootstrap file:
try {
$frontController = Zend_Controller_Front::getInstance();
if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {
ob_start();
$frontController->dispatch();
$output = gzencode(ob_get_contents(), 9);
ob_end_clean();
header('Content-Encoding: gzip');
echo $output;
} else {
$frontController->dispatch();
}
} catch (Exeption $e) {
if (Zend_Registry::isRegistered('Zend_Log')) {
Zend_Registry::get('Zend_Log')->err($e->getMessage());
}
$message = $e->getMessage() . "\n\n" . $e->getTraceAsString();
/* trigger event */
}
Reference
Is this the best open source CMS ever created?
Meet TYPOlight, a powerful Web content management system that specializes in accessibility (back end and front end) and uses XHTML and CSS to generate W3C/WAI compliant pages.
Accessibility
A growing number of countries around the world have introduced legislation which either directly addresses the need for websites to be accessible to people with disabilities, or which addresses the more general requirement for people with disabilities not to be discriminated against. TYPOlight does not treat accessibility as just an additional feature and is thoroughly accessible.
Web 2.0
PHP 5 and Ajax are modern “Web 2.0″ technologies that you can find in a lot of contemporary applications. TYPOlight has a solid codebase built on the new object-oriented programming features of PHP 5 and can therefore be considered a future-proof software. To ensure back end accessibility, every Ajax feature includes a graceful fallback in case JavaScript is disabled.
Page features
- Different page types
- Multiple websites in one tree
- Manual or timed publication
- Hidden pages
- Password protect pages
Editing features
- Clipboard feature
- Edit multiple records
- Built-in rich text editor (TinyMCE)
- Different content elements and modules
- Multilingual spellchecker
- Insert tags (similar to server side includes)
- Manual or timed publication
File manager
- Multiple file uploads
- Image thumbnails and file preview
- Edit uploaded files with the source editor
- File operation permissions
- Copy, move, rename files or folders
- Delete folders recursively
Form generator
- Automatic input validation
- Store uploaded files on the server
- Send form data via e-mail
- Send uploaded files as e-mail attachment
Search engine
- Automatic page indexing
- Search indexing on protected pages
- Phrase search, wildcard search, AND/OR search
- Search result caching and pagination
Full feature list
- Intuitive user interface
- Accessible XHTML strict output
- Meets W3C/WAI requirements
- Web 2.0 support (mootools-based)
- Live update service
- Accessible administration area
- Multiple back end languages and themes
- Generates search engine friendly URLs
- Multi-language support
- Powerful permission system
- Versioning and undo management
- Advanced search and sorting options
- Front end output 100% template based
- Automatic e-mail encryption (spam protection)
- Supports SMTP in addition to PHP’s mail function
- Supports multiple websites in one tree
- Supports GZip compression
- Print articles as PDF
System features
- Open Source (LGPL)
- Web-based administration
- Platform independent
- Over 150 third party extensions
- Multilingual documentation
Links
New Zend Framework Book Published
This book shows you how to build websites fast using PHP and MySQL. What’s more, it shows you how to supercharge your use of these technologies by taking advantage of a powerful, free web development solution known as the Zend Framework, which helps developers build websites with speed and efficiency.
This book embraces a teaching strategy of learning by doing, showing you how to build website features you’ll actually want to use within your own websites. Among other things you’ll learn how to manage data submitted through web forms, send unformatted and HTML e-mails through your website, manage user registrations, logins, and recover forgotten passwords, and even create the structure for a simple social network.
Along the way, you’ll learn how to take advantage of popular online services such as Google Maps, Amazon Web Services, the Facebook Platform, and PayPal to create even more compelling websites.
An Alternative to Zend_Controller
Zend Framework is very flexible and one of its strengths is that it allows developers to implement their own components. The Zend_Controller component, for example, is very powerful. Of course, it’s not my intention to replace it, but to offer an alternative that decreases the number of decisions a developer needs to make when developing an application.
Meet Zf_Controller. The Zf_Controller component has the following goals:
- Abstract complexity: Try to reduce the level of details so the developer can focus on a few concepts at a time.
- Emphasize Convention over Configuration: Emphasize CoC, meaning that the user only needs to specify unconventional aspects of the application.
- Maintain backwards compatibility: Allow the developer to replace Zf_Controller with Zend_Controller in case the application grows in size or complexity.
- Improve performance: Load less classes, execute less code.
- Remove circular references: Avoid circular references.
- Remove Singleton classes: Avoid implementing the Singleton pattern.
- Research: Learn more about the framework, what it does, how it works.
Project Structure
Zend_Controller allows you to use the project structure that best suits your needs. On the other hand, Zf_Controller is more rigid, it only allows you to use the standard project structure:
project/
app/
config/
controllers/
ErrorController.php
IndexController.php
views/
layouts/
scripts/
error/
index/
index.phtml
domain/
Model/
Example.php
lib/
Zend/
Zf/
Zf_Controller classes:
Zf/
Controller/
Action/
Helper/
Layout.php
Action.php
Front.php
Bootstrap File
Zend_Controller:
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../app'));
set_include_path(APPLICATION_PATH . '/../lib'
. PATH_SEPARATOR . get_include_path());
require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$routes = include_once APPLICATION_PATH . '/config/routes.php';
$router->addRoutes($routes);
$layout = Zend_Layout::startMvc();
$layout->setLayoutPath(APPLICATION_PATH . '/views/layouts');
$frontController->dispatch();
Zf_Controller (no Router):
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../app'));
set_include_path(APPLICATION_PATH . '/../lib'
. PATH_SEPARATOR . APPLICATION_PATH . '/../domain);
require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();
$frontController = new Zf_Controller_Front();
$frontController->setLayoutPath(APPLICATION_PATH . '/views/layouts');
$frontController->dispatch();
Action Controller
The default action controller and the default action are named “index”:
class IndexController extends Zf_Controller_Action
{
public function indexAction()
{}
}
Error Controller
Zend_Controller:
class ErrorController extends Zend_Controller_Action
{
// Action used by Zend_Controller
public function errorAction()
{
$error = $this->_getParam('error_handler');
echo $error->exception->getMessage();
}
}
Zf_Controller:
class ErrorController extends Zf_Controller_Action
{
// Action used by Zf_Controller
public function indexAction($e)
{
echo $e->getMessage();
}
}
Rendering a View Script
Zf_Controller does not use the ViewRenderer helper class. To make the code more readable and testable, you need to call the render() method and return a value:
class IndexController extends Zf_Controller_Action
{
public function indexAction()
{
$view = $this->initView();
$view->message = 'Hello';
// Renders views/scripts/index/index.phtml
return $this->render();
}
public function testAction()
{
$view = $this->initView();
$view->message = 'Goodbye';
// Renders views/scripts/index/index.phtml
return $this->render('index');
}}
index.phtml file:
<p><?php echo $this->message ?></p>
Using a Layout
By setting the path to your layouts in the Bootstrap file, you automatically enable the default layout “layout.phtml”:
$frontController = new Zf_Controller_Front(); $frontController->setLayoutPath(APPLICATION_PATH . '/views/layouts');
To disable the layout:
class IndexController extends Zf_Controller_Action
{
protected $_isLayoutEnabled = false;
}
To use a different layout:
class IndexController extends Zf_Controller_Action
{
protected $_layoutScript = 'main.phtml';
}
main.phtml file:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <?php echo $this->headTitle() ?> <?php echo $this->headScript() ?> <?php echo $this->headStyle() ?> </head> <body> <div id="content"><?php echo $this->layout()->content ?></div> </body> </html>
Source Code:
http://svn.fedecarg.com/repo/Zf/Controller/
Implementing your own Front Controller in Zend Framework
There’s no doubt that the additional complexity of implementing the default Front Controller in ZF results in a number of benefits. The most important ones are flexibility and extensibility. The Front Controller implementation takes into consideration the future growth of your application and its design reduces the level of effort required to extend it. A good example of this is the plugin architecture.
But, what if after evaluating the requirements of your system, you determine that there’s not sufficient complexity to implement the default Front Controller? What if you don’t need all that flexibility, a URL mapper, a ViewRendered plugin or an ActionStack helper. Maybe all you need is just a couple of controllers, and that’s it. It’s clear that the standard Front Controller does provide more options and meets every possible use case requirement, but at the cost of complexity and a lot of classes.
So, what to do? Do you choose a different tool for the job, or replace the default Front Controller with your own implementation? How hard can it be? Is it really that difficult to replace the most important component of the Zend Framework and maintain backwards compatibility?
You are about to find out.
In this series of posts, I’ll try to cover a few things I’ve learned about implementing my own Front Controller in Zend Framework. Most of the ideas and code are based on my previous posts:
- Zend Framework: The Cost of Flexibility is Complexity
- Zend Framework Automatic Dependency Tracking
- Zend Framework Controller: 22% Drop in Responsiveness
- Refactoring the Front Controller of the Zend Framework
- Improving the performance of Zend_Controller
- Zend Framework Architecture
Will simplicity finally meet power?