topics: php , zend framework 2 (post)

An Introduction to Zend Framework 2

Overview

Zend Framework 2 (ZF2) is a modern PHP Library utilizing PHP 5.3 Object Oriented features including Namespaces, Late Static Bindings and Lamba Functions. Prominent core features of the library include:

Alongside the core components of Zend Framework 2 are a plethora of Utility components:

Authentication, Barcode, Cacha, Captcha, Code, Config, Console, Crypt, DB, Debug, Di, DOM, Escaper, Feed, File, Filter, Form, HTTP, I18n, Input Filter, JSON, LDAP, Loader, Log, Mail, Math, Memory, MIME, Module Manager, Navigation, Paginator, Permissions, Progress Bar, Serializer, Server, Session, SOAP, StdLib, Tag, Test, Text, Uri, Validator, View, XMLRPC.

Zend Framework 2 is maintained as a Git repository at GitHub, Issues are tracked at GitHub and the documentation can be found at http://framework.zend.com/docs. Zend Framework 2 includes composer.json definitions for both the framework as a whole and individual components of the library.

Skeleton Application

Zend provide an example ZF2 Application, ZendSkeletonApplication as a basis from which new adopers of ZF2 are encouraged to start. The ZF2 Skeleton Application demonstrates a very basic MVC Application with functionality such as Routing, Translations and View Helpers. Generally, the Skeleton Application is promoted as an example from which projects can be based. A CLI tool, ZFTool may be installed via composer to provide ZF2 project creation functionality, although at the time of writting this tool is not yet feature complete.

Zend\ServiceManagaer

The Service Manager component in Zend Framework 2 serves as an implementation of the Service Locator design pattern. The Service Manager has the ability to map requests for a named service to a defined or generic implementation of an Abstract Factory, return a previously constructed object, map an alias to a class for Lazy Loading, instantiate a class, apply initialization via an initializer and ties in with Dependency Injection.

Scoped Service Managers

Zend Framework 2 utilizes Scoped Service Managers to manage some families of object in one place. The full set of scoped Service Managers includes controllers, view_helpers, controller_plugins, validators, filters, form_elements, route_manager, serializers, hydrators and input_filters. In early versions of Zend Framework 2 there existed an issue corrolating a url to an attempt to instantiate an object via alias. This issue could potentially lead to unexpected and unintended behaviour with the potential instantiation of objects destructive in the wrong context. Requests to a Service Manager with Controller scope can be more confident in the resulting object returned being a Controller then is the case with a single generic Service Manager.

Scoped Service Managers are configured independently from the parent Service Manager. The configuration keys that could be utilized in config, allowing for different types of components to utilize all Service Manager options are as follows:

<?php
    return array(
		'service_manager' => array(
			'aliases' => array(
				/**
				 * Map a fully qualified class name to an alias
				 */
				'My\Service\Class' => 'my_service_alias',
			),
			'invokables' => array(
				/**
				 * Map an alias to a FQCN that can be instantiated
				 */
				'an_alias' => 'My\Class',
			),
			'factories' => array(
				/**	
				 * Map an Alias to a Factory Class
				 */
				'another_alias' => 'My\Factory\Class',
				/**
				 * additionally a closure may be defined
				 */
				'closure_created_object' => function(){
					return new My\Factory\Class;
				},
			),
			'abstract_factories' => array(
				/**
				 * List of Abstract Factories that might be able to create a class.
				 */
				'My\Abstractfactory',
			),
			'services' => array(
				/**
				 * Services maps aliases to existing objects
				 */
				'my_object' => new My\Serivce\Class(),
			),
			'shared' => array(
				/**
				 * Requests to the service manager for "an_alias" should always return
				 * a new instance.
				 */
				'an_alias' => false,
			),
		),
		/**
		 * Scoped Service Managers that can be configured and used as above
		 */
		'controllers' => array(),
		'view_helpers' => array(),
		'controller_plugins' => array(),
		'validators' => array(),
		'filters' => array(),
		'form_elements' => array(),
		'route_manager' => array(),
		'serializers' => array(),
		'hydrators' => array(),
		'input_filters' => array(),
	);

For example to add a view_helper named “myViewHelper”, created by factory \My\Module\ViewHelper\MyViewHelperFactory:

	<?php 
	return array(
		'view_helpers' => array(
			'factories' => array(
				'myViewHelper' => "My\Module\ViewHelper\MyViewHelperFactory",
			),
		),
	);

If a factory was written to correctly instantiate “myViewHelper”, the helper would be available in a view as a plugin via

$this->myViewHelper();

Zend\EventManager

The Event Manager implementation in Zend Framework 2 allows the addition of events to the Event Managers events collection. These events may be triggered and the associated functionality evaluated. Short circuiting is possible via Zend\EventManager\Event::stopPropagation() if the propagation of the event to further listeners is not wanted. If there are mutliple sets of functionality attached to an event name, (multiple listeners), the order by which listeners are evaluated is defined by a priority option, ranging from low to high, or order added. ###Shared Event Manager A singleton Event Manager can be used to facilitate event bindings between components without the need for a specific Event Manager instance to be provided as a dependency for each component. This Shared Event Manager , Zend\EventManager\SharedEventManager is set as a property of the Zend\EventManager\EventManager instance when constructed by the MVC Applications Event Manager Factory in Zend\MVC\Service.

Simple Zend\EventManager\EventManager usage:

	<?php
	namespace Foo;

	use Zend\EventManager\EventManager;
	use Zend\EventManager\EventManagerInterface;

	class Bar
	{
	    protected $events;

	    /**
	     * Create an Event Manager instance.
	     * Add an event called 'test' with a closure listener.
	     * Trigger the 'test' event.
	     */
	    public function __construct()
	    {
	        $this->setEvents(new EventManager());
	        $this->getEvents()->attach(
	            'test',
	            function($e){
	                var_dump($e->getParam('test'));
	            }
	        );
	        $this->getEvents()->trigger('test',NULL,array('test' => 'event parameters'));
	    }

	    protected function setEvents(EventManagerInterface $events)
	    {
	        $this->events = $events;
	    }

	    protected function getEvents()
	    {
	        return $this->events;
	    }
	}

Listener Aggregates

A class implementing Zend\EventManager\ListenerAggreateInterface can be attached to the Event Managers Event Collection. A Listener Aggregate implementation is expected to provide an attach and detach method. The attach method is called by the Event Manager with the Event Manager instance as an argument. This allows the Listener Aggregate implementation the opportunity to attach mutliple event listeners. A Listener Aggregate implementation might also be considered a good place to locate the required Listener functionality.
Listener Aggregates can be registered with the Event Manager either via the “attach” method or more directly via “attachAggregate”.

Listener Aggregate Example

module/Application/src/Application/MyListenerAggregate.php

	<?php
	namespace Application;

	use Zend\EventManager\ListenerAggregateInterface;
	use Zend\EventManager\EventManagerInterface;
	use Zend\Mvc\MvcEvent;

	class MyListenerAggregate implements ListenerAggregateInterface
	{

	    /**
	     * The event manager
	     */
	    protected $events;

	    /**
	     * 
	     */
	    public function getEvents()
	    {
	        return $this->events;
	    }

	    /**
	     * 
	     */
	    public function setEvents(EventManagerInterface $events)
	    {
	        $this->events = $events;
	    }

	    /**
	     * Take the event manager instance and attach this dispatch method
	     * to the MVC Dispatch event to it
	     */
	    public function attach(EventManagerInterface $events)
	    {
	        $this->setEvents($events);
	        $this->getEvents()->attach( MvcEvent::EVENT_ROUTE, array($this,'route') );
	        $this->getEvents()->attach( MvcEvent::EVENT_DISPATCH, array($this,'dispatch') );
	    }

	    public function detach(EventManagerInterface $events)
	    {

	    }

	    /**
	     * The dispatch event listener callback
	     */
	    public function route(MvcEvent $e)
	    {
	        var_dump("route event");
	    }

	    /**
	     * The dispatch event listener callback
	     */
	    public function dispatch(MvcEvent $e)
	    {
	        var_dump("dispatch event");
	    }

	}

module/Application/Module.php

	<?php
	namespace Application;

	class Module
	{
		/**
		 * Create an instance of MyListenerAggregate and attach it to the
		 * Event Manager
		 */
		public function onBootstrap( $e )
		{
			$listenerAggreate = new MyListenerAggregate();
			$e->getApplication()->getServiceManager()->get('EventManager')->attachAggregate(
				$listenerAggreate, -1000
			);
		}
	}

Zend\MVC

Zend Framework 2 provides a Model View Controller implementation, Zend\MVC. The main backbones of the ZF2 MVC implementation are the Event Manager and the Service Manager. The Event Manager is used to wire together the components typically required to satisfy a request to an MVC Application. These concerns include Routing, Dispatching and Request/Response management. The Service Manager is used to create these components. Through the inception of Zend Event Manager, Matthew Weier O’Phinney, lead developer of Zend Framework 2, has implemented Aspect Oriented methodologies, seperating the concerns involved in the typical execution of a PHP MVC Application. The MVC implementation that ships with ZF2 utilizes an MvcEvent Object which contains references to the core concerns alongside the Application itself. The MVC Event class defines seven event names as constants.

Typically these events are triggered during the execution of a Zend\Mvc\Application: Bootstrap, Route, Dispatch, Render, Finish. Typically a ZF2 MVC Application will be initialized statically via

$application = Zend\Mvc\Application::init($config);

The static init method calls Zend\Mvc\Application::bootstrap($eventListeners), which creates an MVC Event object and triggers the bootstrap event on the Application Event Collection with the MVC Event as the target.

Finally to run the application,

$application->run();