Zend Framework 2.0 Patterns Tutorial
-
Upload
matthew-weier-ophinney -
Category
Technology
-
view
69.448 -
download
1
description
Transcript of Zend Framework 2.0 Patterns Tutorial
In the beginning. . .
ZF2 Patterns 3
A Brief History of ZF
Initial Announcements and Work
ZF2 Patterns 4
• October 2005: Announced the project
Initial Announcements and Work
ZF2 Patterns 4
• October 2005: Announced the project• March 2006: First public preview release, 0.1.0
Initial Announcements and Work
ZF2 Patterns 4
• October 2005: Announced the project• March 2006: First public preview release, 0.1.0• Fall 2006: Rewrite of the MVC
1.0.0 - July 2007
ZF2 Patterns 5
• First stable release• Basic MVC system, with plugins, action helpers,
automated view rendering etc.
1.0.0 - July 2007
ZF2 Patterns 5
• First stable release• Basic MVC system, with plugins, action helpers,
automated view rendering etc.• Many web service API consumers
1.0.0 - July 2007
ZF2 Patterns 5
• First stable release• Basic MVC system, with plugins, action helpers,
automated view rendering etc.• Many web service API consumers• Server classes for XML-RPC, REST
1.5.0 - March 2008
ZF2 Patterns 6
• First minor release
1.5.0 - March 2008
ZF2 Patterns 6
• First minor release• Zend_Form introduced
1.5.0 - March 2008
ZF2 Patterns 6
• First minor release• Zend_Form introduced• Zend_Layout introduced
1.5.0 - March 2008
ZF2 Patterns 6
• First minor release• Zend_Form introduced• Zend_Layout introduced• Layout-aware view helper system introduced
1.6.0 - September 2008
ZF2 Patterns 7
• Dojo integration
1.6.0 - September 2008
ZF2 Patterns 7
• Dojo integration• PHPUnit scaffolding for testing controllers
1.6.0 - September 2008
ZF2 Patterns 7
• Dojo integration• PHPUnit scaffolding for testing controllers• Introduction of the ContextSwitch action helper
1.7.0 - November 2008
ZF2 Patterns 8
• AMF support
1.7.0 - November 2008
ZF2 Patterns 8
• AMF support• Performance improvements
1.8.0 - April 2009
ZF2 Patterns 9
• Introduction of Zend_Tool
1.8.0 - April 2009
ZF2 Patterns 9
• Introduction of Zend_Tool• Introduction of Zend_Application
1.8.0 - April 2009
ZF2 Patterns 9
• Introduction of Zend_Tool• Introduction of Zend_Application• First widely usable release of ZF
1.9.0 - August 2009
ZF2 Patterns 10
• Addition of Zend_Feed_Reader
1.9.0 - August 2009
ZF2 Patterns 10
• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility
1.9.0 - August 2009
ZF2 Patterns 10
• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions
1.9.0 - August 2009
ZF2 Patterns 10
• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions• Beginning of monthly bug hunts in October
1.10.0 - January 2010
ZF2 Patterns 11
• Integration of ControllerTestCase withZend_Application
1.10.0 - January 2010
ZF2 Patterns 11
• Integration of ControllerTestCase withZend_Application
• Addition of Zend_Feed_Writer, markingcompletion of Zend_Feed refactoring
1.10.0 - January 2010
ZF2 Patterns 11
• Integration of ControllerTestCase withZend_Application
• Addition of Zend_Feed_Writer, markingcompletion of Zend_Feed refactoring
• Documentation changes: adoption of PhD to renderend-user manual, introduction of comment system,and new “Learning Zend Framework section”
1.10.0 - January 2010
ZF2 Patterns 11
• Integration of ControllerTestCase withZend_Application
• Addition of Zend_Feed_Writer, markingcompletion of Zend_Feed refactoring
• Documentation changes: adoption of PhD to renderend-user manual, introduction of comment system,and new “Learning Zend Framework section”
• Primarily community-led additions
1.11.0 November 2010
ZF2 Patterns 12
• Mobile support via Zend_Http_UserAgent
1.11.0 November 2010
ZF2 Patterns 12
• Mobile support via Zend_Http_UserAgent• SimpleCloud API via Zend_Cloud
Where do we go from here?
Zend Framework 2.0’s focusis on improving consistency
and performance
Incremental Improvements
Baby steps
ZF2 Patterns 18
• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces
Baby steps
ZF2 Patterns 18
• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces
• Refactor exceptions
Baby steps
ZF2 Patterns 18
• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces
• Refactor exceptions• Switch ZF to be autoload-only
Baby steps
ZF2 Patterns 18
• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces
• Refactor exceptions• Switch ZF to be autoload-only• Improve and standardize the plugin system
Namespaces
The Problem
ZF2 Patterns 21
• Lengthy class names
• Difficult to refactor
The Problem
ZF2 Patterns 21
• Lengthy class names
• Difficult to refactor• Difficult to retain semantics with shorter names
Basics
ZF2 Patterns 22
• Every class file declares a namespace
Basics
ZF2 Patterns 22
• Every class file declares a namespace• One namespace per file
Basics
ZF2 Patterns 22
• Every class file declares a namespace• One namespace per file• Any class used that is not in the current namespace
(or a subnamespace) is imported and typicallyaliased
Basics
ZF2 Patterns 22
• Every class file declares a namespace• One namespace per file• Any class used that is not in the current namespace
(or a subnamespace) is imported and typicallyaliased
• Global resolution is discouraged, except in the caseof classes referenced in strings
Namespace Example
ZF2 Patterns 23
namespace Zend\EventManager;
use Zend\Stdlib\CallbackHandler;
class EventManager implements EventCollection{
/* ... */}
Using Aliases
ZF2 Patterns 24
namespace Zend\Mvc;use Zend\Stdlib\Dispatchable,
Zend\Di\ServiceLocator as Locator;
class FrontController implements Dispatchable{
public function __construct(Locator $locator){
$this->serviceLocator = $locator;}
}
Recommendation for Migration
ZF2 Patterns 25
Use imports instead ofrequire_once calls in your
code!
Importing ZF1 Classes
ZF2 Patterns 26
use Zend_Controller_Action as Controller;class FooController extends Controller {}
// Later, this might become:use Zend\Controller\Action as Controller;class FooController extends Controller {}
Naming
ZF2 Patterns 27
• All code in the project is in the “Zend” namespace
Naming
ZF2 Patterns 27
• All code in the project is in the “Zend” namespace• Each component defines a unique namespace
Naming
ZF2 Patterns 27
• All code in the project is in the “Zend” namespace• Each component defines a unique namespace• Classes within a component all live in that
namespace or a subnamespace
Naming
ZF2 Patterns 27
• All code in the project is in the “Zend” namespace• Each component defines a unique namespace• Classes within a component all live in that
namespace or a subnamespace• Typically, a class named after the component is the
gateway class
Naming Examples
ZF2 Patterns 28
Zend/EventManager|-- EventCollection.php
‘-- EventManager.php
Naming Examples
ZF2 Patterns 28
Zend/EventManager|-- EventCollection.php
‘-- EventManager.php
namespace Zend\EventManager;
class EventManager implementsEventCollection{}
Interfaces
ZF2 Patterns 29
• Interfaces are named after nouns or adjectives, anddescribe what they provide
Interfaces
ZF2 Patterns 29
• Interfaces are named after nouns or adjectives, anddescribe what they provide
• In most cases, concrete implementations ofinterfaces live in a subnamespace named after theinterface
Interfaces
ZF2 Patterns 29
• Interfaces are named after nouns or adjectives, anddescribe what they provide
• In most cases, concrete implementations ofinterfaces live in a subnamespace named after theinterface
• More solid Contract-Oriented paradigm
Interface Examples
ZF2 Patterns 30
Zend/Session|-- Storage.php‘-- Storage
|-- ArrayStorage.php
‘-- SessionStorage.php
Interface Examples
ZF2 Patterns 30
Zend/Session|-- Storage.php‘-- Storage
|-- ArrayStorage.php
‘-- SessionStorage.php
namespace Zend\Session;
use Traversable, ArrayAccess,Serializable, Countable;
interface Storageextends Traversable,
ArrayAccess, Serializable,Countable{
/* ... */}
Concrete Implementation
ZF2 Patterns 31
namespace Zend\Session\Storage;
use ArrayObject,Zend\Session\Storage,Zend\Session\Exception;
class ArrayStorage extends ArrayObject implements Storage{
/* ... */}
Exceptions
The Problem
ZF2 Patterns 33
• All exceptions derived from a common class
The Problem
ZF2 Patterns 33
• All exceptions derived from a common class• Inability to extend semantic exception types offered
in the SPL
The Problem
ZF2 Patterns 33
• All exceptions derived from a common class• Inability to extend semantic exception types offered
in the SPL• Limited catching strategies
The Problem
ZF2 Patterns 33
• All exceptions derived from a common class• Inability to extend semantic exception types offered
in the SPL• Limited catching strategies• Hard dependency for each and every component
ZF2 Approach
ZF2 Patterns 34
• We eliminated Zend_Exception entirely
ZF2 Approach
ZF2 Patterns 34
• We eliminated Zend_Exception entirely• Each component defines a marker Exception
interface
ZF2 Approach
ZF2 Patterns 34
• We eliminated Zend_Exception entirely• Each component defines a marker Exception
interface• Concrete exceptions live in an Exception
subnamespace, and extend SPL exceptions
What the solution provides
ZF2 Patterns 35
• Catch specific exception types
What the solution provides
ZF2 Patterns 35
• Catch specific exception types• Catch SPL exception types
What the solution provides
ZF2 Patterns 35
• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions
What the solution provides
ZF2 Patterns 35
• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions• Catch based on global exception type
Exception Definitions
ZF2 Patterns 36
Zend/EventManager|-- Exception.php‘-- Exception
‘--InvalidArgumentException.php
Exception Definitions
ZF2 Patterns 36
Zend/EventManager|-- Exception.php‘-- Exception
‘--InvalidArgumentException.php
namespace Zend\EventManager;
interface Exception {}
Exception Definitions
ZF2 Patterns 36
Zend/EventManager|-- Exception.php‘-- Exception
‘--InvalidArgumentException.php
namespace Zend\EventManager;
interface Exception {}
namespace Zend\EventManager\Exception;
use Zend\EventManager\Exception;
class InvalidArgumentExceptionextends \InvalidArgumentExceptionimplements Exception
{}
Catching Exceptions
ZF2 Patterns 37
namespace Zend\EventManager\Exception;use Zend\EventManager\Exception;try {
$events->trigger(’foo.bar’, $object);} catch (InvalidArgumentException $e) {} catch (Exception $e) {} catch (\InvalidArgumentException $e) {} catch (\Exception $e) {}
Autoloading
The Problem
ZF2 Patterns 39
• Performance issues
• Many classes are used JIT, and shouldn’t beloaded until needed
The Problem
ZF2 Patterns 39
• Performance issues
• Many classes are used JIT, and shouldn’t beloaded until needed
• Missing require_once calls lead to errors
ZF2 Approach
ZF2 Patterns 40
• No more require_once calls!
ZF2 Approach
ZF2 Patterns 40
• No more require_once calls!• Deliver multiple autoloading approaches
• ZF1-style include_path autoloader• Per- namespace/vendor prefix autoloading• Class-Map autoloading
ZF1-Style Autoloading
ZF2 Patterns 41
require_once ’Zend/Loader/StandardAutoloader.php’;$loader = new Zend\Loader\StandardAutoloader(array(
’fallback_autoloader’ => true,));$loader->register();
ZF2 NS/Prefix Autoloading
ZF2 Patterns 42
require_once ’Zend/Loader/StandardAutoloader.php’;$loader = new Zend\Loader\StandardAutoloader();$loader->registerNamespace(’My’, __DIR__ . ’/../library/My’)
->registerPrefix(’Phly_’, __DIR__ . ’/../library/Phly’);$loader->register();
Class-Map Autoloading
ZF2 Patterns 43
return array(’My\Foo\Bar’ => __DIR__ . ’/Foo/Bar.php’,
);
Class-Map Autoloading
ZF2 Patterns 43
return array(’My\Foo\Bar’ => __DIR__ . ’/Foo/Bar.php’,
);
require_once ’Zend/Loader/ClassMapAutoloader.php’;$loader = new Zend\Loader\ClassMapAutoloader();$loader->registerAutoloadMap(__DIR__ . ’/../library/.classmap.php’);$loader->register();
Class-Maps? Won’t those require work?
ZF2 Patterns 44
• Yes, they will. But we already have a tool,bin/classmap_generator.php.
Class-Maps? Won’t those require work?
ZF2 Patterns 44
• Yes, they will. But we already have a tool,bin/classmap_generator.php.
• Usage is trivial:
prompt> cd your/libraryprompt> php /path/to/classmap_generator.php -w# Class-Map now exists in .classmap.php
Why?
ZF2 Patterns 45
• Class-Maps show a 25% improvement on the ZF1autoloader when no acceleration is present
Why?
ZF2 Patterns 45
• Class-Maps show a 25% improvement on the ZF1autoloader when no acceleration is present• and 60-85% improvements when an opcode cache is in place!
Why?
ZF2 Patterns 45
• Class-Maps show a 25% improvement on the ZF1autoloader when no acceleration is present• and 60-85% improvements when an opcode cache is in place!
• Pairing namespaces/prefixes with specific pathsshows >10% gains with no acceleration
Why?
ZF2 Patterns 45
• Class-Maps show a 25% improvement on the ZF1autoloader when no acceleration is present• and 60-85% improvements when an opcode cache is in place!
• Pairing namespaces/prefixes with specific pathsshows >10% gains with no acceleration• and 40% improvements when an opcode cache is in place!
Autoloader Factory
ZF2 Patterns 46
• With multiple strategies comes the need for a factory
Autoloader Factory
ZF2 Patterns 46
• With multiple strategies comes the need for a factory• Choose several strategies
Autoloader Factory
ZF2 Patterns 46
• With multiple strategies comes the need for a factory• Choose several strategies
• Class-Map for fastest lookup
Autoloader Factory
ZF2 Patterns 46
• With multiple strategies comes the need for a factory• Choose several strategies
• Class-Map for fastest lookup• Namespace/prefix paths for common code
Autoloader Factory
ZF2 Patterns 46
• With multiple strategies comes the need for a factory• Choose several strategies
• Class-Map for fastest lookup• Namespace/prefix paths for common code• ZF1/PSR0-style fallback autoloader for
development
Autoloader Factory Example
ZF2 Patterns 47
require_once ’Zend/Loader/AutoloaderFactory.php’;use Zend\Loader\AutoloaderFactory;AutoloaderFactory::factory(array(
’Zend\Loader\ClassMapAutoloader’ => array(__DIR__ . ’/../library/.classmap.php’,__DIR__ . ’/../application/.classmap.php’,
),’Zend\Loader\StandardAutoloader’ => array(
’namespaces’ => array(’Zend’ => __DIR__ . ’/../library/Zend’,
),’fallback_autoloader’ => true,
),));
Start Migrating
ZF2 Patterns 48
You can use the ZF2
autoloaders and class-map
generation facilities today;start migrating now!
Plugin Loading
Terminology
ZF2 Patterns 50
• For our purposes, a “plugin” is any class that isdetermined at runtime.
Terminology
ZF2 Patterns 50
• For our purposes, a “plugin” is any class that isdetermined at runtime.
• Action and view helpers• Adapters• Filters and validators
The Problem
ZF2 Patterns 51
• Varying approaches to dynamically discoveringplugin classes
The Problem
ZF2 Patterns 51
• Varying approaches to dynamically discoveringplugin classes
• Paths relative to the calling class• Prefix-path stacks (most common)• Setters to indicate classes
The Problem
ZF2 Patterns 51
• Varying approaches to dynamically discoveringplugin classes
• Paths relative to the calling class• Prefix-path stacks (most common)• Setters to indicate classes
• Most common approach is terrible
The Problem
ZF2 Patterns 51
• Varying approaches to dynamically discoveringplugin classes
• Paths relative to the calling class• Prefix-path stacks (most common)• Setters to indicate classes
• Most common approach is terrible
• Bad performance• Hard to debug• No caching of discovered plugins
ZF2 Approach: Plugin Broker
ZF2 Patterns 52
• Separate Plugin Location interface• Allows varying implementation of plugin lookup
ZF2 Approach: Plugin Broker
ZF2 Patterns 52
• Separate Plugin Location interface• Allows varying implementation of plugin lookup
• Separate Plugin Broker interface• Composes a Plugin Locator
Plugin Locator Interface
ZF2 Patterns 53
namespace Zend\Loader;interface ShortNameLocator{
public function isLoaded($name);public function getClassName($name);public function load($name);
}
Plugin broker interface
ZF2 Patterns 54
namespace Zend\Loader;
interface Broker{
public function load($plugin, array $options = null);public function getPlugins();public function isLoaded($name);public function register($name, $plugin);public function unregister($name);public function setClassLoader(ShortNameLocator $loader);public function getClassLoader();
}
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader• Create a default plugin broker
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class• Optionally, define static configuration
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class• Optionally, define static configuration• Optionally, pass broker and loader configuration
How do I use it?
ZF2 Patterns 55
• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class• Optionally, define static configuration• Optionally, pass broker and loader configuration• Optionally, register plugins with locator and/or broker
Plugin Locator Implementation
ZF2 Patterns 56
namespace Zend\View;use Zend\Loader\PluginClassLoader;class HelperLoader extends PluginClassLoader{
/*** @var array Pre-aliased view helpers
*/protected $plugins = array(
’action’ => ’Zend\View\Helper\Action’,’base_url’ => ’Zend\View\Helper\BaseUrl’,/* ... */
);}
Plugin broker implementation
ZF2 Patterns 57
class HelperBroker extends PluginBrokerprotected $defaultClassLoader = ’Zend\View\HelperLoader’;public function load($plugin, array $options = null){
$helper = parent::load($plugin, $options);if (null !== ($view = $this->getView())) {
$helper->setView($view);}return $helper;
}protected function validatePlugin($plugin){
if (! $plugin instanceof Helper) {throw new InvalidHelperException();
}return true;
}}
Composing a broker
ZF2 Patterns 58
use Zend\View\HelperLoader;class Foo{
protected $broker;
public function broker($spec = null, array $options = array()){
if ($spec instanceof Broker) {$this->broker = $spec;return $spec;
} elseif (null === $this->broker) {$this->broker = new PluginBroker();
}if (null === $spec) {
return $this->broker;} elseif (!is_string($spec)) {
throw new \Exception();}return $this->broker->load($spec, $options);
}}
Locator Precedence
ZF2 Patterns 59
(From least specific to most specific)
• Map defined in concrete plugin loader
Locator Precedence
ZF2 Patterns 59
(From least specific to most specific)
• Map defined in concrete plugin loader• Static maps (latest registration having precedence)
Locator Precedence
ZF2 Patterns 59
(From least specific to most specific)
• Map defined in concrete plugin loader• Static maps (latest registration having precedence)• Mapping passed via instantiation
Locator Precedence
ZF2 Patterns 59
(From least specific to most specific)
• Map defined in concrete plugin loader• Static maps (latest registration having precedence)• Mapping passed via instantiation• Explicit mapping provided programmatically
Defining static maps
ZF2 Patterns 60
use Zend\View\HelperLoader;
HelperLoader::addStaticMap(array(’url’ => ’My\Helper\Url’,’base_url’ => ’Project\Helper\BaseUrl’,
));$loader = new HelperLoader();$class = $loader->load(’url’); // "My\Helper\Url"
Passing maps via configuration
ZF2 Patterns 61
use Zend\View\HelperLoader;
$config = array(’url’ => ’My\Helper\Url’,’base_url’ => ’Project\Helper\BaseUrl’,
);
$loader = new HelperLoader($config);$class = $loader->load(’url’); // "My\Helper\Url"
Passing maps to maps!
ZF2 Patterns 62
use Zend\View\HelperLoader,Zend\Loader\PluginClassLoader;
class HelperMap extends PluginClassLoader{
protected $plugins = array(’url’ => ’My\Helper\Url’,’base_url’ => ’Project\Helper\BaseUrl’,
);}$helpers = new HelperMap();$loader = new HelperLoader($helpers);$class = $loader->load(’url’); // "My\Helper\Url"
Extending loaders
ZF2 Patterns 63
use Zend\View\HelperLoader;
class HelperMap extends HelperLoader{
public function __construct($options = null){
// Addes to and/or overrides map in HelperLoader$this->registerPlugins(array(
’url’ => ’My\Helper\Url’,’base_url’ => ’Project\Helper\BaseUrl’,
));parent::__construct($options);
}}
$helpers = new HelperMap();$class = $loader->load(’url’); // "My\Helper\Url"
Passing maps via broker
ZF2 Patterns 64
use Zend\View\HelperBroker;
$broker = new HelperBroker(array(’class_loader’ => array(
’class’ => ’HelperMap’,’options’ => array(
’base_url’ => ’App\Helper\BaseUrl’,),
),));$plugin = $broker->load(’base_url’); // "App\Helper\BaseUrl"
Creating maps manually
ZF2 Patterns 65
use Zend\View\HelperLoader;
$loader = new HelperLoader();$loader->registerPlugin(’url’, ’My\Helper\Url’)
->registerPlugins(array(’base_url’ => ’Project\Helper\BaseUrl’,
));$class = $loader->load(’url’); // "My\Helper\Url"
Managing plugins via a broker
ZF2 Patterns 66
• By default, it consults the loader for a classname,and instantiates that class with the given arguments
Managing plugins via a broker
ZF2 Patterns 66
• By default, it consults the loader for a classname,and instantiates that class with the given arguments
• Optionally, you can also seed the broker, manuallyregistering plugin objects under a given name
Registering a plugin with the broker
ZF2 Patterns 67
use My\Helper\Url;
// Assumes:// - $request == Request object// - $router == Router object// - $broker == HelperBroker
$url = new Url($request, $router);$broker->registerPlugin(’url’, $url); // OR:$broker->registerPlugins(array(
’url’ => $url,));
$url = $broker->load(’url’); // === $url from above
What about lazy-loading?
ZF2 Patterns 68
• Often you need to configure plugins
What about lazy-loading?
ZF2 Patterns 68
• Often you need to configure plugins• But you don’t want an instance hanging around until
it’s actually requested
What about lazy-loading?
ZF2 Patterns 68
• Often you need to configure plugins• But you don’t want an instance hanging around until
it’s actually requested• Enter the Zend\Loader\LazyLoadingBroker
LazyLoadingBroker Interface
ZF2 Patterns 69
namespace Zend\Loader;interface LazyLoadingBroker extends Broker{
public function registerSpec($name, array $spec = null);public function registerSpecs($specs);public function unregisterSpec($name);public function getRegisteredPlugins();public function hasPlugin($name);
}
Using the LazyLoadingBroker
ZF2 Patterns 70
• Register “specs” with the broker
Using the LazyLoadingBroker
ZF2 Patterns 70
• Register “specs” with the broker• When that plugin is requested, the provided options
will be used unless new options are provided
Using the LazyLoadingBroker
ZF2 Patterns 70
• Register “specs” with the broker• When that plugin is requested, the provided options
will be used unless new options are provided• In all other ways, it behaves like other brokers,
including allowing explicit registration of plugins
LazyLoadingBroker Usage
ZF2 Patterns 71
$broker->registerSpec(’url’, array($request, $router));$broker->registerSpecs(array(
’url’ => array($request, $router),));
if (!$broker->hasPlugin(’url’)) {// no spec!
}
$plugins = $broker->getRegisteredPlugins(); // array(’url’)
$url = $broker->load(’url’); // With $request, $router injected
LazyLoadingBroker Usage Via Configuration
ZF2 Patterns 72
use Zend\View\HelperBroker;
$config = array(’specs’ => array(
’url’ => array($request, $rourter),),
);
$broker = new HelperBroker($config);$url = $broker->load(’url’); // With $request, $router injected
New Components
New Components
ZF2 Patterns 75
• Zend\EventManager• Zend\Di
The EventManager
The Problem
ZF2 Patterns 77
• How do we introduce logging/debug points inframework code?
The Problem
ZF2 Patterns 77
• How do we introduce logging/debug points inframework code?
• How do we allow users to introduce caching withoutneeding to extend framework code?
The Problem
ZF2 Patterns 77
• How do we introduce logging/debug points inframework code?
• How do we allow users to introduce caching withoutneeding to extend framework code?
• How do we allow users to introduce validation,filtering, ACL checks, etc., without needing to extendframework code?
The Problem
ZF2 Patterns 77
• How do we introduce logging/debug points inframework code?
• How do we allow users to introduce caching withoutneeding to extend framework code?
• How do we allow users to introduce validation,filtering, ACL checks, etc., without needing to extendframework code?
• How do we allow users to manipulate the order inwhich plugins, intercepting filters, events, etc.,trigger?
The Problem
ZF2 Patterns 77
• How do we introduce logging/debug points inframework code?
• How do we allow users to introduce caching withoutneeding to extend framework code?
• How do we allow users to introduce validation,filtering, ACL checks, etc., without needing to extendframework code?
• How do we allow users to manipulate the order inwhich plugins, intercepting filters, events, etc.,trigger?
• How can we provide tools for userland code tobenefit from the above?
Solution: Aspect Oriented Programming
ZF2 Patterns 78
• Code defines various “aspects” that may beinteresting to observe and/or attach to from aconsumer
Solution: Aspect Oriented Programming
ZF2 Patterns 78
• Code defines various “aspects” that may beinteresting to observe and/or attach to from aconsumer
• Basically, all of the solutions we’ll look at can beused to implement AOP in a code base.
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both• Preferably while retaining non-global state or allowing overriding
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both• Preferably while retaining non-global state or allowing overriding
• Allow interruption of execution
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both• Preferably while retaining non-global state or allowing overriding
• Allow interruption of execution• Allow prioritization of handlers
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both• Preferably while retaining non-global state or allowing overriding
• Allow interruption of execution• Allow prioritization of handlers• Predictability of arguments passed to handlers
Requirements
ZF2 Patterns 79
• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,
preferably both• Preferably while retaining non-global state or allowing overriding
• Allow interruption of execution• Allow prioritization of handlers• Predictability of arguments passed to handlers• Ability to attach to many event-emitting components
at once
Solution: Subject-Observer
ZF2 Patterns 80
• Pros• Simple to understand
Solution: Subject-Observer
ZF2 Patterns 80
• Pros• Simple to understand• SPL interfaces are well-known (but limited)
Solution: Subject-Observer
ZF2 Patterns 80
• Pros• Simple to understand• SPL interfaces are well-known (but limited)
• Cons• Typically, cannot interrupt execution of remaining observers
Solution: Subject-Observer
ZF2 Patterns 80
• Pros• Simple to understand• SPL interfaces are well-known (but limited)
• Cons• Typically, cannot interrupt execution of remaining observers• Requires a system for each component and/or class
Solution: Subject-Observer
ZF2 Patterns 80
• Pros• Simple to understand• SPL interfaces are well-known (but limited)
• Cons• Typically, cannot interrupt execution of remaining observers• Requires a system for each component and/or class• Typically, no ability to prioritize handlers
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
• Cons• Often, need to test the Event provided to ensure you can handle
it
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
• Cons• Often, need to test the Event provided to ensure you can handle
it• Global usage means static aggregation and/or static
dependencies
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
• Cons• Often, need to test the Event provided to ensure you can handle
it• Global usage means static aggregation and/or static
dependencies• . . . but per-component means boiler-plate to compose in each
class using it
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
• Cons• Often, need to test the Event provided to ensure you can handle
it• Global usage means static aggregation and/or static
dependencies• . . . but per-component means boiler-plate to compose in each
class using it• Typically, no ability to prioritize handlers
Solution: PubSub/Events
ZF2 Patterns 81
• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a
single, global aggregator• Well-known paradigm in UI programming (think: JavaScript)• Tends to be Turing complete
• Cons• Often, need to test the Event provided to ensure you can handle
it• Global usage means static aggregation and/or static
dependencies• . . . but per-component means boiler-plate to compose in each
class using it• Typically, no ability to prioritize handlers
• more on this later. . .
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
• Typically, compose a signal manager into a class, but canintegrate with a global manager as well
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
• Typically, compose a signal manager into a class, but canintegrate with a global manager as well
• Usually has some abilities for prioritizing handlers
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
• Typically, compose a signal manager into a class, but canintegrate with a global manager as well
• Usually has some abilities for prioritizing handlers
• Cons• Verbiage is not well-known amongst PHP developers
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
• Typically, compose a signal manager into a class, but canintegrate with a global manager as well
• Usually has some abilities for prioritizing handlers
• Cons• Verbiage is not well-known amongst PHP developers• Arguments will vary between signals
Solution: SignalSlots
ZF2 Patterns 82
• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)
• Typically, compose a signal manager into a class, but canintegrate with a global manager as well
• Usually has some abilities for prioritizing handlers
• Cons• Verbiage is not well-known amongst PHP developers• Arguments will vary between signals• Same issues with composition per-class and static usage as
seen in event systems
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter• Depending on the design, can allow static/global access
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter• Depending on the design, can allow static/global access
• Cons• Sometimes difficult to accomplish complex workflows
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter• Depending on the design, can allow static/global access
• Cons• Sometimes difficult to accomplish complex workflows• Same issues with composition per-class and static usage as
seen in event systems
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter• Depending on the design, can allow static/global access
• Cons• Sometimes difficult to accomplish complex workflows• Same issues with composition per-class and static usage as
seen in event systems• Easy to forget to invoke next filter in chain
Solution: Intercepting Filters
ZF2 Patterns 83
• Pros• Similar to previous solutions, except that each handler receives
the filter chain as an argument, and is responsible for calling thenext in the chain
• Often, the entire “work” of a method is simply a filter• Depending on the design, can allow static/global access
• Cons• Sometimes difficult to accomplish complex workflows• Same issues with composition per-class and static usage as
seen in event systems• Easy to forget to invoke next filter in chain• Typically, no ability to prioritize filters
ZF2: EventManager Component
ZF2 Patterns 84
• Cherry-picks from each of PubSub, SignalSlot, andIntercepting Filters to provide a comprehensivesolution
ZF2: EventManager Component
ZF2 Patterns 84
• Cherry-picks from each of PubSub, SignalSlot, andIntercepting Filters to provide a comprehensivesolution
• Cannot completely solve the composition/staticusage issues• We can solve the composition problem in PHP 5.4 via Traits
ZF2: EventManager Component
ZF2 Patterns 84
• Cherry-picks from each of PubSub, SignalSlot, andIntercepting Filters to provide a comprehensivesolution
• Cannot completely solve the composition/staticusage issues• We can solve the composition problem in PHP 5.4 via Traits• There are some elegant ways to handle static usage
EventCollection Interface
ZF2 Patterns 85
namespace Zend\EventManager;use Zend\Stdlib\CallbackHandler;
interface EventCollection{
public function trigger($event, $context, $argv = array());public function triggerUntil($event, $context, $argv, $callback);public function attach($event, $callback, $priority = 1);public function detach(CallbackHandler $handle);public function getEvents();public function getHandlers($event);public function clearHandlers($event);
}
Triggering Events
ZF2 Patterns 86
use Zend\EventManager\EventManager;
$events = new EventManager();$events->trigger($eventName, $object, $params);/* Where:
* - $eventName is the name of the event; usually the current
* method name
* - $object is the object triggering the event
* - $params are the parameters the handler might need to access,
* usually the method arguments
*/
CallbackHandler
ZF2 Patterns 87
$handler = $events->attach(’some-event’, function($e) use ($log) {$event = $e->getName();$context = get_class($e->getTarget());$params = json_encode($e->getParams());$log->info(sprintf("%s: %s: %s", $event, $context, $params));
});
CallbackHandler with priority
ZF2 Patterns 88
$handler = $events->attach(’some-event’, function($e) use ($log) {/* same as before */
}, 100); // Prioritize! (higher numbers win)
Interrupting execution: testing results
ZF2 Patterns 89
$results = $events->triggerUntil(’some-event’, $o, $argv,function($result) {
return ($result instanceof SomeType);});if ($results->stopped()) {
return $results->last();}
Interrupting execution: via handlers
ZF2 Patterns 90
$events->attach(’some-event’, function($e) {$result = new Result;$e->stopPropagation(true);return $result;
});$results = $events->trigger(’some-event’, $object, $params);if ($results->stopped()) {
return $results->last();}
Composing an EventManager
ZF2 Patterns 91
use Zend\EventManager\EventCollection as Events,Zend\EventManager\EventManager;
class Foo{
protected $events;
public function events(Events $events = null){
if (null !== $events) {$this->events = $events;
} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);
}return $this->events;
}
public function doSomething($param1, $param2){
$params = compact(’param1’, ’param2’);$this->events()->trigger(__FUNCTION__, $this, $params);
}}
Using a Trait!
ZF2 Patterns 92
use Zend\EventManager\EventCollection as Events,Zend\EventManager\EventManager;
trait Eventful{
public function events(Events $events = null){
if (null !== $events) {$this->events = $events;
} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);
}return $this->events;
}}
class Foo{
use Eventful;protected $events;
}
Connecting handlers statically
ZF2 Patterns 93
use Zend\EventManager\StaticEventManager;
$events = StaticEventManager::getInstance();$events->connect(’Foo’, ’some-event’, function ($e) {
/* ... */});
Recommendations
ZF2 Patterns 94
• Name your events using __FUNCTION__• If triggering multiple events in the same method, suffix with a
“.(pre|post|etc.)”
Recommendations
ZF2 Patterns 94
• Name your events using __FUNCTION__• If triggering multiple events in the same method, suffix with a
“.(pre|post|etc.)”
• Provide the EventManager constructor with both theclass name and one or more “service” names, tomake static attachment more semantic
Recommendations
ZF2 Patterns 94
• Name your events using __FUNCTION__• If triggering multiple events in the same method, suffix with a
“.(pre|post|etc.)”
• Provide the EventManager constructor with both theclass name and one or more “service” names, tomake static attachment more semantic• This allows a single callback to listen to many components!
Dependency Injection
What is Dependency Injection?
ZF2 Patterns 96
Quite simply: defining ways to passdependencies into an object.
What is Dependency Injection?
ZF2 Patterns 96
Quite simply: defining ways to passdependencies into an object.
namespace My\Helper;class Url{
public function __construct(Request $request){
$this->request = $request;}
public function setRouter(Router $router){
$this->router = $router;}
}
So, why do people fear it?
ZF2 Patterns 97
• They don’t.
So, why do people fear it?
ZF2 Patterns 97
• They don’t.• They fear Dependency Injection Containers.
What’s a Dependency Injection Container?
ZF2 Patterns 98
Put simply:
an object graph for mapping
dependency relationsbetween objects.
Again, why do people fear it?
ZF2 Patterns 99
It looks like magic.
Object with Dependencies
ZF2 Patterns 100
namespace My\Helper;class Url{
public function __construct(Request $request){
$this->request = $request;}
public function setRouter(Router $router){
$this->router = $router;}
}
Another Object with Dependencies
ZF2 Patterns 101
namespace mwop\Mvc;class Router{
public function addRoute(Route $route){
$this->routes->push($route);}
}
Grabbing an object and using it
ZF2 Patterns 102
$urlHelper = $di->get(’url-helper’);echo $url->generate(’/css/site.css’);echo $url->generate(array(’id’ => $id), array(’name’ => ’blog’));
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.• You retrieve the object via the container, which ensures the
definitions are used.
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.• You retrieve the object via the container, which ensures the
definitions are used.
• Where do I define these?
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.• You retrieve the object via the container, which ensures the
definitions are used.
• Where do I define these?• Either programmatically, via configuration, or using a tool.
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.• You retrieve the object via the container, which ensures the
definitions are used.
• Where do I define these?• Either programmatically, via configuration, or using a tool.
• If I call $object = new Foo(), how do I forceusing different dependencies?
The questions
ZF2 Patterns 103
• How can I be sure I have my dependencies?• You define them explicitly.• You retrieve the object via the container, which ensures the
definitions are used.
• Where do I define these?• Either programmatically, via configuration, or using a tool.
• If I call $object = new Foo(), how do I forceusing different dependencies?• Calling new doesn’t use the container. In fact, nothing forces you
to use one!
Why use one?
ZF2 Patterns 104
If instantiation of your object is not under yourdirect control (e.g. controllers), how do youretain control over your dependencies?
Why use one?
ZF2 Patterns 104
If instantiation of your object is not under yourdirect control (e.g. controllers), how do youretain control over your dependencies?• Different data access based on application
environment
Why use one?
ZF2 Patterns 104
If instantiation of your object is not under yourdirect control (e.g. controllers), how do youretain control over your dependencies?• Different data access based on application
environment• Substituting mock/stub implementations during
testing
ZF2 Approach
ZF2 Patterns 105
• Standardize on a Service Locator interface
ZF2 Approach
ZF2 Patterns 105
• Standardize on a Service Locator interface• Provide a performant DI solution, and integrate it into
a Service Locator
ZF2 Approach
ZF2 Patterns 105
• Standardize on a Service Locator interface• Provide a performant DI solution, and integrate it into
a Service Locator• Provide tooling to aid in creating DI definitions during
development
Service Locator interface
ZF2 Patterns 106
namespace Zend\Di;
interface ServiceLocation{
public function set($name, $service);public function get($name, array $params = null);
}
Dependency Injector interface
ZF2 Patterns 107
namespace Zend\Di;
interface DependencyInjection{
public function get($name, array $params = null);public function newInstance($name, array $params = null);public function setDefinitions($definitions);public function setDefinition(
DependencyDefinition $definition, $serviceName = null);public function setAlias($alias, $serviceName);public function getDefinitions();public function getAliases();
}
Definitions
ZF2 Patterns 108
namespace Zend\Di;
interface DependencyDefinition{
public function __construct($className);public function getClass();public function setConstructorCallback($callback);public function getConstructorCallback();public function hasConstructorCallback();public function setParam($name, $value);public function setParams(array $params);public function setParamMap(array $map);public function getParams();public function setShared($flag = true);public function isShared();public function addTag($tag);public function addTags(array $tags);public function getTags();public function hasTag($tag);public function addMethodCall($name, array $args);public function getMethodCalls();
}
References
ZF2 Patterns 109
namespace Zend\Di;
interface DependencyReference{
public function __construct($serviceName);public function getServiceName();
}
Class Definition
ZF2 Patterns 110
use Zend\Di\Definition,Zend\Di\Reference;
$mongo = new Definition(’Mongo’);
$mongoDB = new Definition(’MongoDB’);$mongoDB->setParam(’conn’, new Reference(’mongo’))
->setParam(’name’, ’test’);
$coll = new Definition(’MongoCollection’);$coll->setParam(’db’, new Reference(’mongodb’))
->setParam(’name’, ’resource’);
$di->setDefinitions(array(’mongo’ => $mongo,’mongodb’ => $mongoDB,’resource’ => $coll,
));
$resource = $di->get(’resource’);
Setter Injection
ZF2 Patterns 111
use Zend\Di\Definition,Zend\Di\Reference;
$service = new Definition(’mwop\Service\Resources’);$service->addMethod(’setResource’, array(
new Reference(’resource’)));
$di->setDefinition(’resources’, $service);
$resources = $di->get(’resources’);
Making it faster
ZF2 Patterns 112
• Specify constructor parameter maps in definitions
Making it faster
ZF2 Patterns 112
• Specify constructor parameter maps in definitions• Generate Service Locators from a DI container
Parameter maps
ZF2 Patterns 113
$mongoDB->setParam(’conn’, new Reference(’mongo’))->setParam(’name’, ’test’)->setParamMap(array(
’conn’ => 0,’name’ => 1,
));// Ensures parameters are in order, without needing// to resort to Reflection API.
Generating a Service Locator from DI
ZF2 Patterns 114
use Zend\Di\ContainerBuilder as DiBuilder;
$builder = new DiBuilder($injector);$builder->setContainerClass(’AppContext’);$container = $builder->getCodeGenerator(
__DIR__ . ’/../application/AppContext.php’); // Returns instance of Zend\CodeGenerator\Php\PhpFile$container->write(); // Write to disk
Example of a generated locator
ZF2 Patterns 115
use Zend\Di\DependencyInjectionContainer;class AppContext extends DependencyInjectionContainer{
public function get($name, array $params = array()){
switch ($name) {case ’request’:case ’Zend\Http\Request’:
return $this->getZendHttpRequest();default:
return parent::get($name, $params);}
}public function getZendHttpRequest(){
if (isset($this->services[’Zend\Http\Request’])) {return $this->services[’Zend\Http\Request’];
}$object = new \Zend\Http\Request();$this->services[’Zend\Http\Request’] = $object;return $object;
}}
Using a generated locator
ZF2 Patterns 116
$context = new AppContext();$request = $context->get(’request’);// Same as using a Service Locator or DI Container!
Making it simpler
ZF2 Patterns 117
• Use configuration files
Making it simpler
ZF2 Patterns 117
• Use configuration files• Can use any format supported by Zend\Config
Configuration (JSON)
ZF2 Patterns 118
{"production": { "definitions": [
{ "class": "Mongo" },{ "class": "MongoDB","params": {
"conn": {"__reference": "mongocxn"},"name": "mwoptest"
},"param_map": { "conn": 0, "name": 1 }
},{ "class": "MongoCollection","params": {
"db": {"__reference": "MongoDB"},"name": "entries"
},"param_map": { "db": 0, "name": 1 }
}], "aliases": {
"mongocxn": "Mongo","mongo-collection-entries": "MongoCollection"
}}
}
What are the use cases in ZF2?
ZF2 Patterns 119
One big one.
What are the use cases in ZF2?
ZF2 Patterns 119
One big one.
Pulling MVC controllersfrom the container
An Action Controller
ZF2 Patterns 120
namespace Blog\Controller;class Entry implements Dispatchable{
public function setResource(Resource $resource){
$this->resource = $resource;}
public function dispatch(Request $request, Response $response =null)
{/* ... */$entry = $this->resource->get($id);/* ... */
}}
The Front Controller
ZF2 Patterns 121
class FrontController implements Dispatchable{
public function __construct(DependencyInjection $di){
$this->di = $di;}
public function dispatch(Request $request, Response $response =null)
{/* ... */$controller = $this->di->get($controllerName);$result = $controller->dispatch($request, $response);/* ... */
}}
Benefits to using DI this way
ZF2 Patterns 122
• Performance
Benefits to using DI this way
ZF2 Patterns 122
• Performance• Code de-coupling
Benefits to using DI this way
ZF2 Patterns 122
• Performance• Code de-coupling• Simplification of controller code
More to come!
ZF2 Patterns 123
• First-run compilation
More to come!
ZF2 Patterns 123
• First-run compilation• Tools for scanning classes or namespaces to build
definitions
More to come!
ZF2 Patterns 123
• First-run compilation• Tools for scanning classes or namespaces to build
definitions• Interface injection
More to come!
ZF2 Patterns 123
• First-run compilation• Tools for scanning classes or namespaces to build
definitions• Interface injection• . . . and likely more.
MVC Patterns
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?• How do we accommodate different controller
patterns?• What if we want to fine-tune action selection after routing, based
on other data in the request environment?
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?• How do we accommodate different controller
patterns?• What if we want to fine-tune action selection after routing, based
on other data in the request environment?• What if we want to pass arguments to action names, or
prevalidate arguments?
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?• How do we accommodate different controller
patterns?• What if we want to fine-tune action selection after routing, based
on other data in the request environment?• What if we want to pass arguments to action names, or
prevalidate arguments?• What if we don’t like the “Action” suffix in action methods?
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?• How do we accommodate different controller
patterns?• What if we want to fine-tune action selection after routing, based
on other data in the request environment?• What if we want to pass arguments to action names, or
prevalidate arguments?• What if we don’t like the “Action” suffix in action methods?• What if . . . ?
• How can we better use server components withinthe MVC?
The Problems
ZF2 Patterns 125
• How do controllers get dependencies?• How do we accommodate different controller
patterns?• What if we want to fine-tune action selection after routing, based
on other data in the request environment?• What if we want to pass arguments to action names, or
prevalidate arguments?• What if we don’t like the “Action” suffix in action methods?• What if . . . ?
• How can we better use server components withinthe MVC?
• How can we make the MVC more performant?
ZF2 Patterns 126
The basic structure of a webapplication is that of a
Request/Response lifecycle
The Dispatchable Interface
ZF2 Patterns 127
namespace Zend\Stdlib;
interface Dispatchable{
public function dispatch(Request $request, Response $response = null
);}
Request and Response
ZF2 Patterns 128
• Both the Request and Response simply aggregatemetadata and content
Request and Response
ZF2 Patterns 128
• Both the Request and Response simply aggregatemetadata and content
• The Response also has the ability to send itself
Request and Response
ZF2 Patterns 128
• Both the Request and Response simply aggregatemetadata and content
• The Response also has the ability to send itself• HTTP-specific variants will be the core of the MVC
• To provide convenience around superglobals, cookies, andcommon tasks such as determining Accept and Content-Typeheaders
Anything dispatchable can attach to the MVC
ZF2 Patterns 129
Dispatchable is simply a formalization ofthe Command pattern
Anything dispatchable can attach to the MVC
ZF2 Patterns 129
Dispatchable is simply a formalization ofthe Command pattern• Controllers
Anything dispatchable can attach to the MVC
ZF2 Patterns 129
Dispatchable is simply a formalization ofthe Command pattern• Controllers• Servers
Anything dispatchable can attach to the MVC
ZF2 Patterns 129
Dispatchable is simply a formalization ofthe Command pattern• Controllers• Servers• Whatever you may dream of! Just implement
Dispatchable!
Simple Front Controller Prototype
ZF2 Patterns 130
public function dispatch(Request $request, Response $response = null){
$params = compact(’request’, ’response’);$this->events()->trigger(__FUNCTION__ . ’.route.pre’, $this,
$params);$result = $this->getRouter()->route($request);if (!$result) {
$result = array(’controller’ => ’page’, ’page’ => 404);}$params[’routing’] = (object) $result;$this->events()->trigger(__FUNCTION__ . ’.route.post’, $params);
$controller = $this->di->get($params[’routing’]->controller);if (!$controller instanceof Dispatchable) {
$controller = new NotFoundController();}$result = $controller->dispatch($request, $response);$params[’__RESULT__’] = $result;$this->events()->trigger(__FUNCTION__ . ’.dispatch.post’,
$params);
return $response;}
Getting Involved
Contribute to ZF2!
ZF2 Patterns 133
• ZF2 wiki:http://bit.ly/zf2wiki
• zf-contributors mailing list:[email protected]
• IRC:#zftalk.dev on Freenode
ZF2 Git Repository
ZF2 Patterns 134
• Git guide:http://bit.ly/zf2gitguide
• GitHub:http://github.com/zendframework/zf2
• Official repo:git://git.zendframework.com/zf.githttp://git.zendframework.com/
• You still need to sign a CLA!
References
ZF2 Patterns 135
• ZF2 Dependency Injection Proposalhttp://bit.ly/zf2diproposalhttp://bit.ly/zf2diprototype
• ZF2 DI/MVC prototype sandboxhttp://bit.ly/zf2sandbox(mobile-layout branch is latest)
Thank You!
ZF2 Patterns 136
• Feedback:http://joind.in/3339
• Twitter:http://twitter.com/weierophinney
• Zend Framework:http://framework.zend.com/