Zend Framework 2.0 Patterns Tutorial

277

description

Tutorial for PHP Community Conference, 2011 edition, covering new components and patterns found within Zend Framework 2.0 development.

Transcript of Zend Framework 2.0 Patterns Tutorial

Page 1: Zend Framework 2.0 Patterns Tutorial
Page 2: Zend Framework 2.0 Patterns Tutorial

In the beginning. . .

Page 3: Zend Framework 2.0 Patterns Tutorial

ZF2 Patterns 3

A Brief History of ZF

Page 4: Zend Framework 2.0 Patterns Tutorial

Initial Announcements and Work

ZF2 Patterns 4

• October 2005: Announced the project

Page 5: Zend Framework 2.0 Patterns Tutorial

Initial Announcements and Work

ZF2 Patterns 4

• October 2005: Announced the project• March 2006: First public preview release, 0.1.0

Page 6: Zend Framework 2.0 Patterns Tutorial

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

Page 7: Zend Framework 2.0 Patterns Tutorial

1.0.0 - July 2007

ZF2 Patterns 5

• First stable release• Basic MVC system, with plugins, action helpers,

automated view rendering etc.

Page 8: Zend Framework 2.0 Patterns Tutorial

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

Page 9: Zend Framework 2.0 Patterns Tutorial

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

Page 10: Zend Framework 2.0 Patterns Tutorial

1.5.0 - March 2008

ZF2 Patterns 6

• First minor release

Page 11: Zend Framework 2.0 Patterns Tutorial

1.5.0 - March 2008

ZF2 Patterns 6

• First minor release• Zend_Form introduced

Page 12: Zend Framework 2.0 Patterns Tutorial

1.5.0 - March 2008

ZF2 Patterns 6

• First minor release• Zend_Form introduced• Zend_Layout introduced

Page 13: Zend Framework 2.0 Patterns Tutorial

1.5.0 - March 2008

ZF2 Patterns 6

• First minor release• Zend_Form introduced• Zend_Layout introduced• Layout-aware view helper system introduced

Page 14: Zend Framework 2.0 Patterns Tutorial

1.6.0 - September 2008

ZF2 Patterns 7

• Dojo integration

Page 15: Zend Framework 2.0 Patterns Tutorial

1.6.0 - September 2008

ZF2 Patterns 7

• Dojo integration• PHPUnit scaffolding for testing controllers

Page 16: Zend Framework 2.0 Patterns Tutorial

1.6.0 - September 2008

ZF2 Patterns 7

• Dojo integration• PHPUnit scaffolding for testing controllers• Introduction of the ContextSwitch action helper

Page 17: Zend Framework 2.0 Patterns Tutorial

1.7.0 - November 2008

ZF2 Patterns 8

• AMF support

Page 18: Zend Framework 2.0 Patterns Tutorial

1.7.0 - November 2008

ZF2 Patterns 8

• AMF support• Performance improvements

Page 19: Zend Framework 2.0 Patterns Tutorial

1.8.0 - April 2009

ZF2 Patterns 9

• Introduction of Zend_Tool

Page 20: Zend Framework 2.0 Patterns Tutorial

1.8.0 - April 2009

ZF2 Patterns 9

• Introduction of Zend_Tool• Introduction of Zend_Application

Page 21: Zend Framework 2.0 Patterns Tutorial

1.8.0 - April 2009

ZF2 Patterns 9

• Introduction of Zend_Tool• Introduction of Zend_Application• First widely usable release of ZF

Page 22: Zend Framework 2.0 Patterns Tutorial

1.9.0 - August 2009

ZF2 Patterns 10

• Addition of Zend_Feed_Reader

Page 23: Zend Framework 2.0 Patterns Tutorial

1.9.0 - August 2009

ZF2 Patterns 10

• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility

Page 24: Zend Framework 2.0 Patterns Tutorial

1.9.0 - August 2009

ZF2 Patterns 10

• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions

Page 25: Zend Framework 2.0 Patterns Tutorial

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

Page 26: Zend Framework 2.0 Patterns Tutorial

1.10.0 - January 2010

ZF2 Patterns 11

• Integration of ControllerTestCase withZend_Application

Page 27: Zend Framework 2.0 Patterns Tutorial

1.10.0 - January 2010

ZF2 Patterns 11

• Integration of ControllerTestCase withZend_Application

• Addition of Zend_Feed_Writer, markingcompletion of Zend_Feed refactoring

Page 28: Zend Framework 2.0 Patterns Tutorial

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”

Page 29: Zend Framework 2.0 Patterns Tutorial

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

Page 30: Zend Framework 2.0 Patterns Tutorial

1.11.0 November 2010

ZF2 Patterns 12

• Mobile support via Zend_Http_UserAgent

Page 31: Zend Framework 2.0 Patterns Tutorial

1.11.0 November 2010

ZF2 Patterns 12

• Mobile support via Zend_Http_UserAgent• SimpleCloud API via Zend_Cloud

Page 32: Zend Framework 2.0 Patterns Tutorial

Where do we go from here?

Page 33: Zend Framework 2.0 Patterns Tutorial
Page 34: Zend Framework 2.0 Patterns Tutorial
Page 35: Zend Framework 2.0 Patterns Tutorial

Zend Framework 2.0’s focusis on improving consistency

and performance

Page 36: Zend Framework 2.0 Patterns Tutorial

Incremental Improvements

Page 37: Zend Framework 2.0 Patterns Tutorial

Baby steps

ZF2 Patterns 18

• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces

Page 38: Zend Framework 2.0 Patterns Tutorial

Baby steps

ZF2 Patterns 18

• Convert code from vendor prefixes (e.g.“Zend_Foo”) to PHP 5.3 namespaces

• Refactor exceptions

Page 39: Zend Framework 2.0 Patterns Tutorial

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

Page 40: Zend Framework 2.0 Patterns Tutorial

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

Page 41: Zend Framework 2.0 Patterns Tutorial
Page 42: Zend Framework 2.0 Patterns Tutorial

Namespaces

Page 43: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 21

• Lengthy class names

• Difficult to refactor

Page 44: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 21

• Lengthy class names

• Difficult to refactor• Difficult to retain semantics with shorter names

Page 45: Zend Framework 2.0 Patterns Tutorial

Basics

ZF2 Patterns 22

• Every class file declares a namespace

Page 46: Zend Framework 2.0 Patterns Tutorial

Basics

ZF2 Patterns 22

• Every class file declares a namespace• One namespace per file

Page 47: Zend Framework 2.0 Patterns Tutorial

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

Page 48: Zend Framework 2.0 Patterns Tutorial

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

Page 49: Zend Framework 2.0 Patterns Tutorial

Namespace Example

ZF2 Patterns 23

namespace Zend\EventManager;

use Zend\Stdlib\CallbackHandler;

class EventManager implements EventCollection{

/* ... */}

Page 50: Zend Framework 2.0 Patterns Tutorial

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;}

}

Page 51: Zend Framework 2.0 Patterns Tutorial

Recommendation for Migration

ZF2 Patterns 25

Use imports instead ofrequire_once calls in your

code!

Page 52: Zend Framework 2.0 Patterns Tutorial

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 {}

Page 53: Zend Framework 2.0 Patterns Tutorial

Naming

ZF2 Patterns 27

• All code in the project is in the “Zend” namespace

Page 54: Zend Framework 2.0 Patterns Tutorial

Naming

ZF2 Patterns 27

• All code in the project is in the “Zend” namespace• Each component defines a unique namespace

Page 55: Zend Framework 2.0 Patterns Tutorial

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

Page 56: Zend Framework 2.0 Patterns Tutorial

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

Page 57: Zend Framework 2.0 Patterns Tutorial

Naming Examples

ZF2 Patterns 28

Zend/EventManager|-- EventCollection.php

‘-- EventManager.php

Page 58: Zend Framework 2.0 Patterns Tutorial

Naming Examples

ZF2 Patterns 28

Zend/EventManager|-- EventCollection.php

‘-- EventManager.php

namespace Zend\EventManager;

class EventManager implementsEventCollection{}

Page 59: Zend Framework 2.0 Patterns Tutorial

Interfaces

ZF2 Patterns 29

• Interfaces are named after nouns or adjectives, anddescribe what they provide

Page 60: Zend Framework 2.0 Patterns Tutorial

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

Page 61: Zend Framework 2.0 Patterns Tutorial

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

Page 62: Zend Framework 2.0 Patterns Tutorial

Interface Examples

ZF2 Patterns 30

Zend/Session|-- Storage.php‘-- Storage

|-- ArrayStorage.php

‘-- SessionStorage.php

Page 63: Zend Framework 2.0 Patterns Tutorial

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{

/* ... */}

Page 64: Zend Framework 2.0 Patterns Tutorial

Concrete Implementation

ZF2 Patterns 31

namespace Zend\Session\Storage;

use ArrayObject,Zend\Session\Storage,Zend\Session\Exception;

class ArrayStorage extends ArrayObject implements Storage{

/* ... */}

Page 65: Zend Framework 2.0 Patterns Tutorial

Exceptions

Page 66: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 33

• All exceptions derived from a common class

Page 67: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 33

• All exceptions derived from a common class• Inability to extend semantic exception types offered

in the SPL

Page 68: Zend Framework 2.0 Patterns Tutorial

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

Page 69: Zend Framework 2.0 Patterns Tutorial

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

Page 70: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach

ZF2 Patterns 34

• We eliminated Zend_Exception entirely

Page 71: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach

ZF2 Patterns 34

• We eliminated Zend_Exception entirely• Each component defines a marker Exception

interface

Page 72: Zend Framework 2.0 Patterns Tutorial

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

Page 73: Zend Framework 2.0 Patterns Tutorial

What the solution provides

ZF2 Patterns 35

• Catch specific exception types

Page 74: Zend Framework 2.0 Patterns Tutorial

What the solution provides

ZF2 Patterns 35

• Catch specific exception types• Catch SPL exception types

Page 75: Zend Framework 2.0 Patterns Tutorial

What the solution provides

ZF2 Patterns 35

• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions

Page 76: Zend Framework 2.0 Patterns Tutorial

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

Page 77: Zend Framework 2.0 Patterns Tutorial

Exception Definitions

ZF2 Patterns 36

Zend/EventManager|-- Exception.php‘-- Exception

‘--InvalidArgumentException.php

Page 78: Zend Framework 2.0 Patterns Tutorial

Exception Definitions

ZF2 Patterns 36

Zend/EventManager|-- Exception.php‘-- Exception

‘--InvalidArgumentException.php

namespace Zend\EventManager;

interface Exception {}

Page 79: Zend Framework 2.0 Patterns Tutorial

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

{}

Page 80: Zend Framework 2.0 Patterns Tutorial

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) {}

Page 81: Zend Framework 2.0 Patterns Tutorial

Autoloading

Page 82: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 39

• Performance issues

• Many classes are used JIT, and shouldn’t beloaded until needed

Page 83: Zend Framework 2.0 Patterns Tutorial

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

Page 84: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach

ZF2 Patterns 40

• No more require_once calls!

Page 85: Zend Framework 2.0 Patterns Tutorial

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

Page 86: Zend Framework 2.0 Patterns Tutorial

ZF1-Style Autoloading

ZF2 Patterns 41

require_once ’Zend/Loader/StandardAutoloader.php’;$loader = new Zend\Loader\StandardAutoloader(array(

’fallback_autoloader’ => true,));$loader->register();

Page 87: Zend Framework 2.0 Patterns Tutorial

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();

Page 88: Zend Framework 2.0 Patterns Tutorial

Class-Map Autoloading

ZF2 Patterns 43

return array(’My\Foo\Bar’ => __DIR__ . ’/Foo/Bar.php’,

);

Page 89: Zend Framework 2.0 Patterns Tutorial

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();

Page 90: Zend Framework 2.0 Patterns Tutorial

Class-Maps? Won’t those require work?

ZF2 Patterns 44

• Yes, they will. But we already have a tool,bin/classmap_generator.php.

Page 91: Zend Framework 2.0 Patterns Tutorial

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

Page 92: Zend Framework 2.0 Patterns Tutorial

Why?

ZF2 Patterns 45

• Class-Maps show a 25% improvement on the ZF1autoloader when no acceleration is present

Page 93: Zend Framework 2.0 Patterns Tutorial

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!

Page 94: Zend Framework 2.0 Patterns Tutorial

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

Page 95: Zend Framework 2.0 Patterns Tutorial

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!

Page 96: Zend Framework 2.0 Patterns Tutorial

Autoloader Factory

ZF2 Patterns 46

• With multiple strategies comes the need for a factory

Page 97: Zend Framework 2.0 Patterns Tutorial

Autoloader Factory

ZF2 Patterns 46

• With multiple strategies comes the need for a factory• Choose several strategies

Page 98: Zend Framework 2.0 Patterns Tutorial

Autoloader Factory

ZF2 Patterns 46

• With multiple strategies comes the need for a factory• Choose several strategies

• Class-Map for fastest lookup

Page 99: Zend Framework 2.0 Patterns Tutorial

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

Page 100: Zend Framework 2.0 Patterns Tutorial

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

Page 101: Zend Framework 2.0 Patterns Tutorial

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,

),));

Page 102: Zend Framework 2.0 Patterns Tutorial

Start Migrating

ZF2 Patterns 48

You can use the ZF2

autoloaders and class-map

generation facilities today;start migrating now!

Page 103: Zend Framework 2.0 Patterns Tutorial

Plugin Loading

Page 104: Zend Framework 2.0 Patterns Tutorial

Terminology

ZF2 Patterns 50

• For our purposes, a “plugin” is any class that isdetermined at runtime.

Page 105: Zend Framework 2.0 Patterns Tutorial

Terminology

ZF2 Patterns 50

• For our purposes, a “plugin” is any class that isdetermined at runtime.

• Action and view helpers• Adapters• Filters and validators

Page 106: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 51

• Varying approaches to dynamically discoveringplugin classes

Page 107: Zend Framework 2.0 Patterns Tutorial

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

Page 108: Zend Framework 2.0 Patterns Tutorial

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

Page 109: Zend Framework 2.0 Patterns Tutorial

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

Page 110: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach: Plugin Broker

ZF2 Patterns 52

• Separate Plugin Location interface• Allows varying implementation of plugin lookup

Page 111: Zend Framework 2.0 Patterns Tutorial

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

Page 112: Zend Framework 2.0 Patterns Tutorial

Plugin Locator Interface

ZF2 Patterns 53

namespace Zend\Loader;interface ShortNameLocator{

public function isLoaded($name);public function getClassName($name);public function load($name);

}

Page 113: Zend Framework 2.0 Patterns Tutorial

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();

}

Page 114: Zend Framework 2.0 Patterns Tutorial

How do I use it?

ZF2 Patterns 55

• Create a default plugin loader

Page 115: Zend Framework 2.0 Patterns Tutorial

How do I use it?

ZF2 Patterns 55

• Create a default plugin loader• Create a default plugin broker

Page 116: Zend Framework 2.0 Patterns Tutorial

How do I use it?

ZF2 Patterns 55

• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class

Page 117: Zend Framework 2.0 Patterns Tutorial

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

Page 118: Zend Framework 2.0 Patterns Tutorial

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

Page 119: Zend Framework 2.0 Patterns Tutorial

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

Page 120: Zend Framework 2.0 Patterns Tutorial

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’,/* ... */

);}

Page 121: Zend Framework 2.0 Patterns Tutorial

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;

}}

Page 122: Zend Framework 2.0 Patterns Tutorial

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);

}}

Page 123: Zend Framework 2.0 Patterns Tutorial

Locator Precedence

ZF2 Patterns 59

(From least specific to most specific)

• Map defined in concrete plugin loader

Page 124: Zend Framework 2.0 Patterns Tutorial

Locator Precedence

ZF2 Patterns 59

(From least specific to most specific)

• Map defined in concrete plugin loader• Static maps (latest registration having precedence)

Page 125: Zend Framework 2.0 Patterns Tutorial

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

Page 126: Zend Framework 2.0 Patterns Tutorial

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

Page 127: Zend Framework 2.0 Patterns Tutorial

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"

Page 128: Zend Framework 2.0 Patterns Tutorial

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"

Page 129: Zend Framework 2.0 Patterns Tutorial

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"

Page 130: Zend Framework 2.0 Patterns Tutorial

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"

Page 131: Zend Framework 2.0 Patterns Tutorial

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"

Page 132: Zend Framework 2.0 Patterns Tutorial

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"

Page 133: Zend Framework 2.0 Patterns Tutorial

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

Page 134: Zend Framework 2.0 Patterns Tutorial

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

Page 135: Zend Framework 2.0 Patterns Tutorial

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

Page 136: Zend Framework 2.0 Patterns Tutorial

What about lazy-loading?

ZF2 Patterns 68

• Often you need to configure plugins

Page 137: Zend Framework 2.0 Patterns Tutorial

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

Page 138: Zend Framework 2.0 Patterns Tutorial

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

Page 139: Zend Framework 2.0 Patterns Tutorial

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);

}

Page 140: Zend Framework 2.0 Patterns Tutorial

Using the LazyLoadingBroker

ZF2 Patterns 70

• Register “specs” with the broker

Page 141: Zend Framework 2.0 Patterns Tutorial

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

Page 142: Zend Framework 2.0 Patterns Tutorial

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

Page 143: Zend Framework 2.0 Patterns Tutorial

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

Page 144: Zend Framework 2.0 Patterns Tutorial

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

Page 145: Zend Framework 2.0 Patterns Tutorial
Page 146: Zend Framework 2.0 Patterns Tutorial

New Components

Page 147: Zend Framework 2.0 Patterns Tutorial

New Components

ZF2 Patterns 75

• Zend\EventManager• Zend\Di

Page 148: Zend Framework 2.0 Patterns Tutorial

The EventManager

Page 149: Zend Framework 2.0 Patterns Tutorial

The Problem

ZF2 Patterns 77

• How do we introduce logging/debug points inframework code?

Page 150: Zend Framework 2.0 Patterns Tutorial

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?

Page 151: Zend Framework 2.0 Patterns Tutorial

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?

Page 152: Zend Framework 2.0 Patterns Tutorial

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?

Page 153: Zend Framework 2.0 Patterns Tutorial

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?

Page 154: Zend Framework 2.0 Patterns Tutorial

Solution: Aspect Oriented Programming

ZF2 Patterns 78

• Code defines various “aspects” that may beinteresting to observe and/or attach to from aconsumer

Page 155: Zend Framework 2.0 Patterns Tutorial

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.

Page 156: Zend Framework 2.0 Patterns Tutorial

Requirements

ZF2 Patterns 79

• Reasonably easy to understand design

Page 157: Zend Framework 2.0 Patterns Tutorial

Requirements

ZF2 Patterns 79

• Reasonably easy to understand design• Allow static or per-instance attachment of handlers,

preferably both

Page 158: Zend Framework 2.0 Patterns Tutorial

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

Page 159: Zend Framework 2.0 Patterns Tutorial

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

Page 160: Zend Framework 2.0 Patterns Tutorial

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

Page 161: Zend Framework 2.0 Patterns Tutorial

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

Page 162: Zend Framework 2.0 Patterns Tutorial

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

Page 163: Zend Framework 2.0 Patterns Tutorial

Solution: Subject-Observer

ZF2 Patterns 80

• Pros• Simple to understand

Page 164: Zend Framework 2.0 Patterns Tutorial

Solution: Subject-Observer

ZF2 Patterns 80

• Pros• Simple to understand• SPL interfaces are well-known (but limited)

Page 165: Zend Framework 2.0 Patterns Tutorial

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

Page 166: Zend Framework 2.0 Patterns Tutorial

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

Page 167: Zend Framework 2.0 Patterns Tutorial

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

Page 168: Zend Framework 2.0 Patterns Tutorial

Solution: PubSub/Events

ZF2 Patterns 81

• Pros• Subscribe to arbitrary notices

Page 169: Zend Framework 2.0 Patterns Tutorial

Solution: PubSub/Events

ZF2 Patterns 81

• Pros• Subscribe to arbitrary notices• Typically per-component + global usage; in many languages, a

single, global aggregator

Page 170: Zend Framework 2.0 Patterns Tutorial

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)

Page 171: Zend Framework 2.0 Patterns Tutorial

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

Page 172: Zend Framework 2.0 Patterns Tutorial

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

Page 173: Zend Framework 2.0 Patterns Tutorial

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

Page 174: Zend Framework 2.0 Patterns Tutorial

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

Page 175: Zend Framework 2.0 Patterns Tutorial

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

Page 176: Zend Framework 2.0 Patterns Tutorial

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. . .

Page 177: Zend Framework 2.0 Patterns Tutorial

Solution: SignalSlots

ZF2 Patterns 82

• Pros• Well-known in computer science circles

Page 178: Zend Framework 2.0 Patterns Tutorial

Solution: SignalSlots

ZF2 Patterns 82

• Pros• Well-known in computer science circles• Code emits signals, which are intercepted by slots (aka handlers)

Page 179: Zend Framework 2.0 Patterns Tutorial

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

Page 180: Zend Framework 2.0 Patterns Tutorial

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

Page 181: Zend Framework 2.0 Patterns Tutorial

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

Page 182: Zend Framework 2.0 Patterns Tutorial

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

Page 183: Zend Framework 2.0 Patterns Tutorial

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

Page 184: Zend Framework 2.0 Patterns Tutorial

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

Page 185: Zend Framework 2.0 Patterns Tutorial

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

Page 186: Zend Framework 2.0 Patterns Tutorial

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

Page 187: Zend Framework 2.0 Patterns Tutorial

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

Page 188: Zend Framework 2.0 Patterns Tutorial

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

Page 189: Zend Framework 2.0 Patterns Tutorial

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

Page 190: Zend Framework 2.0 Patterns Tutorial

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

Page 191: Zend Framework 2.0 Patterns Tutorial

ZF2: EventManager Component

ZF2 Patterns 84

• Cherry-picks from each of PubSub, SignalSlot, andIntercepting Filters to provide a comprehensivesolution

Page 192: Zend Framework 2.0 Patterns Tutorial

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

Page 193: Zend Framework 2.0 Patterns Tutorial

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

Page 194: Zend Framework 2.0 Patterns Tutorial

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);

}

Page 195: Zend Framework 2.0 Patterns Tutorial

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

*/

Page 196: Zend Framework 2.0 Patterns Tutorial

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));

});

Page 197: Zend Framework 2.0 Patterns Tutorial

CallbackHandler with priority

ZF2 Patterns 88

$handler = $events->attach(’some-event’, function($e) use ($log) {/* same as before */

}, 100); // Prioritize! (higher numbers win)

Page 198: Zend Framework 2.0 Patterns Tutorial

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();}

Page 199: Zend Framework 2.0 Patterns Tutorial

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();}

Page 200: Zend Framework 2.0 Patterns Tutorial

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);

}}

Page 201: Zend Framework 2.0 Patterns Tutorial

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;

}

Page 202: Zend Framework 2.0 Patterns Tutorial

Connecting handlers statically

ZF2 Patterns 93

use Zend\EventManager\StaticEventManager;

$events = StaticEventManager::getInstance();$events->connect(’Foo’, ’some-event’, function ($e) {

/* ... */});

Page 203: Zend Framework 2.0 Patterns Tutorial

Recommendations

ZF2 Patterns 94

• Name your events using __FUNCTION__• If triggering multiple events in the same method, suffix with a

“.(pre|post|etc.)”

Page 204: Zend Framework 2.0 Patterns Tutorial

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

Page 205: Zend Framework 2.0 Patterns Tutorial

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!

Page 206: Zend Framework 2.0 Patterns Tutorial

Dependency Injection

Page 207: Zend Framework 2.0 Patterns Tutorial

What is Dependency Injection?

ZF2 Patterns 96

Quite simply: defining ways to passdependencies into an object.

Page 208: Zend Framework 2.0 Patterns Tutorial

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;}

}

Page 209: Zend Framework 2.0 Patterns Tutorial

So, why do people fear it?

ZF2 Patterns 97

• They don’t.

Page 210: Zend Framework 2.0 Patterns Tutorial

So, why do people fear it?

ZF2 Patterns 97

• They don’t.• They fear Dependency Injection Containers.

Page 211: Zend Framework 2.0 Patterns Tutorial

What’s a Dependency Injection Container?

ZF2 Patterns 98

Put simply:

an object graph for mapping

dependency relationsbetween objects.

Page 212: Zend Framework 2.0 Patterns Tutorial

Again, why do people fear it?

ZF2 Patterns 99

It looks like magic.

Page 213: Zend Framework 2.0 Patterns Tutorial

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;}

}

Page 214: Zend Framework 2.0 Patterns Tutorial

Another Object with Dependencies

ZF2 Patterns 101

namespace mwop\Mvc;class Router{

public function addRoute(Route $route){

$this->routes->push($route);}

}

Page 215: Zend Framework 2.0 Patterns Tutorial

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’));

Page 216: Zend Framework 2.0 Patterns Tutorial

The questions

ZF2 Patterns 103

• How can I be sure I have my dependencies?

Page 217: Zend Framework 2.0 Patterns Tutorial

The questions

ZF2 Patterns 103

• How can I be sure I have my dependencies?• You define them explicitly.

Page 218: Zend Framework 2.0 Patterns Tutorial

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.

Page 219: Zend Framework 2.0 Patterns Tutorial

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?

Page 220: Zend Framework 2.0 Patterns Tutorial

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.

Page 221: Zend Framework 2.0 Patterns Tutorial

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?

Page 222: Zend Framework 2.0 Patterns Tutorial

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!

Page 223: Zend Framework 2.0 Patterns Tutorial

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?

Page 224: Zend Framework 2.0 Patterns Tutorial

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

Page 225: Zend Framework 2.0 Patterns Tutorial

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

Page 226: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach

ZF2 Patterns 105

• Standardize on a Service Locator interface

Page 227: Zend Framework 2.0 Patterns Tutorial

ZF2 Approach

ZF2 Patterns 105

• Standardize on a Service Locator interface• Provide a performant DI solution, and integrate it into

a Service Locator

Page 228: Zend Framework 2.0 Patterns Tutorial

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

Page 229: Zend Framework 2.0 Patterns Tutorial

Service Locator interface

ZF2 Patterns 106

namespace Zend\Di;

interface ServiceLocation{

public function set($name, $service);public function get($name, array $params = null);

}

Page 230: Zend Framework 2.0 Patterns Tutorial

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();

}

Page 231: Zend Framework 2.0 Patterns Tutorial

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();

}

Page 232: Zend Framework 2.0 Patterns Tutorial

References

ZF2 Patterns 109

namespace Zend\Di;

interface DependencyReference{

public function __construct($serviceName);public function getServiceName();

}

Page 233: Zend Framework 2.0 Patterns Tutorial

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’);

Page 234: Zend Framework 2.0 Patterns Tutorial

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’);

Page 235: Zend Framework 2.0 Patterns Tutorial

Making it faster

ZF2 Patterns 112

• Specify constructor parameter maps in definitions

Page 236: Zend Framework 2.0 Patterns Tutorial

Making it faster

ZF2 Patterns 112

• Specify constructor parameter maps in definitions• Generate Service Locators from a DI container

Page 237: Zend Framework 2.0 Patterns Tutorial

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.

Page 238: Zend Framework 2.0 Patterns Tutorial

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

Page 239: Zend Framework 2.0 Patterns Tutorial

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;

}}

Page 240: Zend Framework 2.0 Patterns Tutorial

Using a generated locator

ZF2 Patterns 116

$context = new AppContext();$request = $context->get(’request’);// Same as using a Service Locator or DI Container!

Page 241: Zend Framework 2.0 Patterns Tutorial

Making it simpler

ZF2 Patterns 117

• Use configuration files

Page 242: Zend Framework 2.0 Patterns Tutorial

Making it simpler

ZF2 Patterns 117

• Use configuration files• Can use any format supported by Zend\Config

Page 243: Zend Framework 2.0 Patterns Tutorial

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"

}}

}

Page 244: Zend Framework 2.0 Patterns Tutorial

What are the use cases in ZF2?

ZF2 Patterns 119

One big one.

Page 245: Zend Framework 2.0 Patterns Tutorial

What are the use cases in ZF2?

ZF2 Patterns 119

One big one.

Pulling MVC controllersfrom the container

Page 246: Zend Framework 2.0 Patterns Tutorial

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);/* ... */

}}

Page 247: Zend Framework 2.0 Patterns Tutorial

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);/* ... */

}}

Page 248: Zend Framework 2.0 Patterns Tutorial

Benefits to using DI this way

ZF2 Patterns 122

• Performance

Page 249: Zend Framework 2.0 Patterns Tutorial

Benefits to using DI this way

ZF2 Patterns 122

• Performance• Code de-coupling

Page 250: Zend Framework 2.0 Patterns Tutorial

Benefits to using DI this way

ZF2 Patterns 122

• Performance• Code de-coupling• Simplification of controller code

Page 251: Zend Framework 2.0 Patterns Tutorial

More to come!

ZF2 Patterns 123

• First-run compilation

Page 252: Zend Framework 2.0 Patterns Tutorial

More to come!

ZF2 Patterns 123

• First-run compilation• Tools for scanning classes or namespaces to build

definitions

Page 253: Zend Framework 2.0 Patterns Tutorial

More to come!

ZF2 Patterns 123

• First-run compilation• Tools for scanning classes or namespaces to build

definitions• Interface injection

Page 254: Zend Framework 2.0 Patterns Tutorial

More to come!

ZF2 Patterns 123

• First-run compilation• Tools for scanning classes or namespaces to build

definitions• Interface injection• . . . and likely more.

Page 255: Zend Framework 2.0 Patterns Tutorial

MVC Patterns

Page 256: Zend Framework 2.0 Patterns Tutorial

The Problems

ZF2 Patterns 125

• How do controllers get dependencies?

Page 257: Zend Framework 2.0 Patterns Tutorial

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?

Page 258: Zend Framework 2.0 Patterns Tutorial

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?

Page 259: Zend Framework 2.0 Patterns Tutorial

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?

Page 260: Zend Framework 2.0 Patterns Tutorial

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?

Page 261: Zend Framework 2.0 Patterns Tutorial

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?

Page 262: Zend Framework 2.0 Patterns Tutorial

ZF2 Patterns 126

The basic structure of a webapplication is that of a

Request/Response lifecycle

Page 263: Zend Framework 2.0 Patterns Tutorial

The Dispatchable Interface

ZF2 Patterns 127

namespace Zend\Stdlib;

interface Dispatchable{

public function dispatch(Request $request, Response $response = null

);}

Page 264: Zend Framework 2.0 Patterns Tutorial

Request and Response

ZF2 Patterns 128

• Both the Request and Response simply aggregatemetadata and content

Page 265: Zend Framework 2.0 Patterns Tutorial

Request and Response

ZF2 Patterns 128

• Both the Request and Response simply aggregatemetadata and content

• The Response also has the ability to send itself

Page 266: Zend Framework 2.0 Patterns Tutorial

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

Page 267: Zend Framework 2.0 Patterns Tutorial

Anything dispatchable can attach to the MVC

ZF2 Patterns 129

Dispatchable is simply a formalization ofthe Command pattern

Page 268: Zend Framework 2.0 Patterns Tutorial

Anything dispatchable can attach to the MVC

ZF2 Patterns 129

Dispatchable is simply a formalization ofthe Command pattern• Controllers

Page 269: Zend Framework 2.0 Patterns Tutorial

Anything dispatchable can attach to the MVC

ZF2 Patterns 129

Dispatchable is simply a formalization ofthe Command pattern• Controllers• Servers

Page 270: Zend Framework 2.0 Patterns Tutorial

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!

Page 271: Zend Framework 2.0 Patterns Tutorial

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;}

Page 272: Zend Framework 2.0 Patterns Tutorial
Page 273: Zend Framework 2.0 Patterns Tutorial

Getting Involved

Page 274: Zend Framework 2.0 Patterns Tutorial

Contribute to ZF2!

ZF2 Patterns 133

• ZF2 wiki:http://bit.ly/zf2wiki

• zf-contributors mailing list:[email protected]

• IRC:#zftalk.dev on Freenode

Page 275: Zend Framework 2.0 Patterns Tutorial

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!

Page 276: Zend Framework 2.0 Patterns Tutorial

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)

Page 277: Zend Framework 2.0 Patterns Tutorial

Thank You!

ZF2 Patterns 136

• Feedback:http://joind.in/3339

• Twitter:http://twitter.com/weierophinney

• Zend Framework:http://framework.zend.com/