Zend Framework 2 Patterns
Matthew Weier O'Phinney
Project Lead, Zend Framework


To watch the webinar please go to:
http://www.zend.com/en/webinar/Framework/70170000000bX3J-
webinar-zf-2-patterns-20110330.flv


                                                © All rights reserved. Zend Technologies, Inc.
Roadmap for today
●   Namespaces and Autoloading
●   Exceptions
●   Configuration
●   Plugin systems
●   Dispatching
●   Inversion of Control




                     © All rights reserved. Zend Technologies, Inc.
Format
●   List The Problems
●   Detail the ZF2 Approach




                    © All rights reserved. Zend Technologies, Inc.
But first, some history




     © All rights reserved. Zend Technologies, Inc.
Zend Framework 1.X
●   1.0 Released in July 2007
●   Largely evolutionary development
    ▶   Inconsistencies in APIs, particularly surrounding
        plugins and configuration
    ▶   Best practices have been discovered over time
    ▶   Many key features for modern applications have
        been added in recent versions




                         © All rights reserved. Zend Technologies, Inc.
Zend Framework 2.0
●   First new major release
    ▶   Allowing us to break backwards compatibility
●   Focus is on:
    ▶   Consistency
    ▶   Performance
    ▶   Documentation
    ▶   User productivity




                        © All rights reserved. Zend Technologies, Inc.
Namespaces and Autoloading




7          © All rights reserved. Zend Technologies, Inc.
The Problems
●   Lengthy class names
    ▶   Difficult to refactor
    ▶   Difficult to retain semantics with shorter names
●   Performance issues
    ▶   Many classes are used JIT, and shouldn't be loaded
        until needed
●   Missing require_once statements lead to errors




                          © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Namespaces
●   Formalize the prefixes used in ZF1
    ▶   Namespace separator correlates to directory
        separator
●   Help identify dependencies (imports)
    ▶   Allows refactoring using different implementations
        easier
    ▶   Makes packaging easier




                        © All rights reserved. Zend Technologies, Inc.
Namespaces


namespace ZendEventManager;

use ZendStdlibCallbackHandler;

class EventManager implements EventCollection
{
    /* ... */
}




                   © All rights reserved. Zend Technologies, Inc.
Namespaces
●   Interfaces as namespaces
    ▶   Interface names are adjectives or nouns
    ▶   Concrete implementations in a sub-namespace
        named after the interface
    ▶   Contract-Oriented paradigm




                        © All rights reserved. Zend Technologies, Inc.
Interfaces as Namespaces
Zend/Session              namespace ZendSession;
|-- Storage.php           interface Storage
`-- Storage
                          {
    |--
                              /* ... */
ArrayStorage.php
                          }
    `--
SessionStorage.php
namespace ZendSessionStorage;
use ArrayObject,
    ZendSessionStorage,
    ZendSessionException;
class ArrayStorage
    extends ArrayObject
    implements Storage
{ /* ... */ }
                   © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Autoloading
●   No more require_once calls!
●   Multiple approaches
    ▶   ZF1-style include_path autoloader
    ▶   Per-namespace/prefix autoloading
    ▶   Class-map autoloading




                        © All rights reserved. Zend Technologies, Inc.
ZF1-Style Autoloading



require_once
'Zend/Loader/StandardAutoloader.php';
$loader =
    new ZendLoaderStandardAutoloader(array(
    'fallback_autoloader' => true,
));
$loader->register();




                   © All rights reserved. Zend Technologies, Inc.
ZF2 NS/Prefix Autoloading


require_once
'Zend/Loader/StandardAutoloader.php';
$loader = new ZendLoaderStandardAutoloader();
$loader->registerNamespace(
            'My', __DIR__ . '/../library/My')
       ->registerPrefix(
            'Phly_', __DIR__ .
'/../library/Phly');
$loader->register();




                   © All rights reserved. Zend Technologies, Inc.
ZF2 Class-Map Autoloading

return array(
    'MyFooBar' => __DIR__ . '/Foo/Bar.php',
);



require_once
'Zend/Loader/ClassMapAutoloader.php';
$loader = new ZendLoaderClassMapAutoloader();
$loader->registerAutoloadMap(
    __DIR__ . '/../library/.classmap.php');
$loader->register();



                   © All rights reserved. Zend Technologies, Inc.
Exceptions




17   © All rights reserved. Zend Technologies, Inc.
The Problems
●   All exceptions derived from a common class
●   No ability to extend more semantic exception
    types offered in SPL




                    © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Eliminated Zend_Exception
●   Each component defines a marker Exception
    interface
●   Additional exception types are created in an
    Exception subnamespace
    ▶   These extend SPL exceptions, and implement the
        component-level exception interface




                       © All rights reserved. Zend Technologies, Inc.
What the solution provides
●   Catch specific exception types
●   Catch SPL exception types
●   Catch any component-level exception
●   Catch based on global exception type




                     © All rights reserved. Zend Technologies, Inc.
Exceptions in use
Zend/EventManager                               namespace
|-- Exception.php                               ZendEventManager;
`-- Exception
    `-- InvalidArgument-                        interface Exception {}
        Exception.php



namespace ZendEventManagerException;

use ZendEventManagerException;

class InvalidArgumentException
    extends InvalidArgumentException
    implements Exception
{}


                     © All rights reserved. Zend Technologies, Inc.
Exceptions in use

namespace ZendEventManagerException;
use ZendEventManagerException;
try {
    $events->trigger('foo.bar', $object);
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
}




                    © All rights reserved. Zend Technologies, Inc.
Configuration




23   © All rights reserved. Zend Technologies, Inc.
The Problems
●   Case-SeNSItiviTy
●   Varying APIs
    ▶   setOptions()
    ▶   setConfig()
    ▶   __construct()
    ▶   explicit setters




                           © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Option names will be
    lowercase_underscore_separated_word
    s
●   Standard solution across components
    ▶   setOptions() style, proxying to setters, or
    ▶   per-component configuration objects




                        © All rights reserved. Zend Technologies, Inc.
setOptions() style
class Foo
{
    public function setOptions($options)
    {
        if (!is_array($options)
            && !($options instanceof
Traversable)
        ) {
            throw new
InvalidArgumentException();
        }

       foreach ($options as $key => $value) {
           $method = normalize($key);
           if (method_exists($this, $method)) {
               $this->$method($value);
           }
       }           © All rights reserved. Zend Technologies, Inc.
Options object style
class FooOptions extends Options
{
    public $bar;
    public $baz;

    public function __construct($options = null)
    {
        if (!is_array($options)
            && !($options instanceof Traversable)
        ) {
            throw new InvalidArgumentException();
        }

        foreach ($options as $key => $value) {
            $prop = normalize($key);
            $this->$prop = $value;
        }
    }
}                    © All rights reserved. Zend Technologies, Inc.
Options object style


class Foo
{
    public function __construct(Options $options =
null)
    {
        if (null !== $options) {
            foreach ($options as $key => $value) {
                $this->$key = $value;
            }
        }
    }
}



                     © All rights reserved. Zend Technologies, Inc.
Plugin Architectures




29       © All rights reserved. Zend Technologies, Inc.
Terminology
●   For our purposes, a “plugin” is any class that is
    determined at runtime.
    ▶   Action and view helpers
    ▶   Adapters
    ▶   Filters and validators




                         © All rights reserved. Zend Technologies, Inc.
The Problems
●   Varying approaches to dynamically discovering
    plugin classes
    ▶   Prefix-path stacks (most common)
    ▶   Paths relative to the calling class
    ▶   Setters to indicate classes
●   Most common approach is terrible
    ▶   Bad performance
    ▶   Hard to debug
    ▶   No caching of discovered plugins

                          © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Plugin Broker
●   Separate Plugin Location interface
    ▶   Allows varying implementation of plugin lookup
●   Separate Plugin Broker interface
    ▶   Composes a Plugin Locator




                        © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Plugin Broker
●   Standard implementation across components
    ▶   Subclassing standard implementation allows type-
        hinting, caching discovered plugins, etc.
    ▶   while allowing you to substitute your own
        implementations
●   Class-map location by default
●   2-5x performance gains!
●   Easier to debug


                        © All rights reserved. Zend Technologies, Inc.
Plugin class location
namespace ZendLoader;

interface ShortNameLocater
{
    public function isLoaded($name);
    public function getClassName($name);
    public function load($name);
}
namespace ZendView;
use ZendLoaderPluginClassLoader;
class HelperLoader extends PluginClassLoader
{
    protected $plugins = array(
        'action' => 'ZendViewHelperAction',
        'baseurl' => 'ZendViewHelperBaseUrl',
        /* ... */
    );
}
                     © All rights reserved. Zend Technologies, Inc.
Plugin broker

namespace ZendLoader;

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(
        ShortNameLocater $loader);
    public function getClassLoader();
}



                     © All rights reserved. Zend Technologies, Inc.
Plugin broker
class HelperBroker extends PluginBroker {
    protected $defaultClassLoader =
'ZendViewHelperLoader';
    protected $view;
    public function setView(Renderer $view) {}
    public function getView() {}
    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;
    }
}                       © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Events
●   Trigger events at interesting points in your
    application
    ▶   Use as basic subject/observer pattern
    ▶   Or as intercepting filters
    ▶   Or a full-fledged Aspect-Oriented Programming
        system




                          © All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Events
●   Compose an EventManager to a class
●   Attach handlers to events
    ▶   Handlers receive an Event
         ●   event name
         ●   target (calling) object
         ●   parameters passed
    ▶   Handlers can also be attached statically




                              © All rights reserved. Zend Technologies, Inc.
Triggering an event


public function doSomething(
    $with, $params = array()
) {
    $this->events()->trigger(
        __FUNCTION__, compact('with', 'params')
    );
    /* ... */
}




                   © All rights reserved. Zend Technologies, Inc.
Listening to an event

use ZendEventManagerEventManager as Events;

$events = new Events();
$events->attach('doSomething', function($e) use
($log) {
    $event = $e->getName();
    $target = get_class($e->getTarget());
    $params = json_encode($e->getParams());
    $message = sprintf('%s (%s): %s', $event,
$target, $params);
    $log->info($message);
});




                     © All rights reserved. Zend Technologies, Inc.
Attaching statically to an event


use ZendEventManagerStaticEventManager as
AllEvents;

$events = AllEvents::getInstance();

// Specify the class composing an EventManager
// as first arg
$events->attach('Foo', 'doSomething', function($e)
{});




                     © All rights reserved. Zend Technologies, Inc.
Dispatchers




42   © All rights reserved. Zend Technologies, Inc.
The Problems
●   Not terribly performant
●   Hard to customize
●   Hard to inject controllers with dependencies
●   Forces pre-initialization of resources if you
    want them configured by Zend_Application




                     © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Discrete Request, Response, and Dispatchable
    interfaces
    ▶   Request encompasses request environment
    ▶   Response aggregates response returned
    ▶   Dispatchable objects formalize a Strategy
        pattern




                       © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Anything Dispatchable can be attached to the
    MVC
    ▶   Server components (XML-RPC, JSON-RPC, etc.)
●   Allows building your own MVC approach
    ▶   Do you want action methods to receive explicit
        arguments?
    ▶   Do you want to select a different action method
        based on request headers?



                        © All rights reserved. Zend Technologies, Inc.
MVC Interfaces
interface Message
{
    public function setMetadata($spec, $value =
null);
    public function getMetadata($key = null);
    public function setContent($content);
    public function getContent();
}
interface Request           interface Response
    extends Message             extends Message
{                           {
    public function             public function
        __toString();               __toString();
    public function             public function

fromString($string);                              fromString($string);
}                                                     public function
                                                  send();
                                                  }
                       © All rights reserved. Zend Technologies, Inc.
MVC Interfaces


interface Dispatchable
{
    public function dispatch(
        Request $request,
        Response $response = null);
}




                   © All rights reserved. Zend Technologies, Inc.
Inversion of Control




48      © All rights reserved. Zend Technologies, Inc.
The Problems
●   How do objects get dependencies?
    ▶   In particular, how do Controllers get dependencies?




                         © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Service Locator
    ▶   Basic pattern:
         ●   set($name, $service)
         ●   get($name)
    ▶   Formalization of application services
        (mailer, logger, profiler, etc.)
    ▶   Good interface for typehinting




                          © All rights reserved. Zend Technologies, Inc.
Service Locator
use ZendDiServiceLocator,
    ZendEventManagerEventManager;

class MyLocator extends ServiceLocator
{
    protected $events;
    protected $map = array('events' => 'getEvents');

    public function getEvents()
    {
        if (null !== $this->events) {
            return $this->events;
        }
        $this->events = new EventManager();
        return $this->events;
    }
}
                     © All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Dependency Injection Container
    ▶   Scaffolding for constructor and setter injection
    ▶   Use programmatically, or from configuration
    ▶   Typically used to seed a service locator




                         © All rights reserved. Zend Technologies, Inc.
Dependency Injection
$db = new Definition('MyDbAdapterSqlite');
$db->setParam('name', __DIR__ .
'/../data/db/users.db');

$mapper = new Definition('MyMapperDb');
$mapper->addMethodCall(
    'setAdapter', array(new Reference('db')));

$service = new Definition('MyResourceUsers');
$service->setParam('mapper', new
Reference('mapper'));

$di = new DependencyInjector;
$di->setDefinitions(array(
    'db'     => $db,
    'mapper' => $mapper,
    'users' => $service,
));
                     © All rights reserved. Zend Technologies, Inc.
Controllers as services
●   Solves issue of controller dependencies
●   Each request only instantiates what's needed
    for that request
●   Better testability of controllers




                      © All rights reserved. Zend Technologies, Inc.
Controllers as services


$userController = new
Definition('SiteControllerUser');
$userController->setParam(
    'service', new Reference('users'));
$di->setDefinition($userController, 'controller-
user');

// Inside dispatcher:
$controller = $di->get($controllerName);
$result = $controller->dispatch($request, $response);




                     © All rights reserved. Zend Technologies, Inc.
More to come!




56    © All rights reserved. Zend Technologies, Inc.
Zend Framework 2.0
●   Schedule:
    ▶   MVC milestone by end of May
    ▶   Preview Release following MVC milestone
    ▶   Beta release during summer
    ▶   Stable by end-of-year




                        © All rights reserved. Zend Technologies, Inc.
Resources




58   © All rights reserved. Zend Technologies, Inc.
●   ZF2 Wiki: http://bit.ly/zf2wiki
●   ZF2 Git information: http://bit.ly/zf2gitguide
●   ZF2 MVC sandbox:
    git://git.mwop.net/zf2sandbox.git
●   ZF2 DI prototype: http://bit.ly/gBBnDS




                     © All rights reserved. Zend Technologies, Inc.
Thank you!
     ●   http://framework.zend.com/
     ●   http://twitter.com/weierophinney




60                        © All rights reserved. Zend Technologies, Inc.
Webinar
    To watch the webinar please go to:
    http://www.zend.com/en/webinar/Framework/
    70170000000bX3J-webinar-zf-2-patterns-
    20110330.flv
    Or
    http://bit.ly/qXeCWI

    (short registration required)




Insert->Header & Footer             © All rights reserved. Zend Technologies, Inc.   61

Zend Framework 2 Patterns

  • 1.
    Zend Framework 2Patterns Matthew Weier O'Phinney Project Lead, Zend Framework To watch the webinar please go to: http://www.zend.com/en/webinar/Framework/70170000000bX3J- webinar-zf-2-patterns-20110330.flv © All rights reserved. Zend Technologies, Inc.
  • 2.
    Roadmap for today ● Namespaces and Autoloading ● Exceptions ● Configuration ● Plugin systems ● Dispatching ● Inversion of Control © All rights reserved. Zend Technologies, Inc.
  • 3.
    Format ● List The Problems ● Detail the ZF2 Approach © All rights reserved. Zend Technologies, Inc.
  • 4.
    But first, somehistory © All rights reserved. Zend Technologies, Inc.
  • 5.
    Zend Framework 1.X ● 1.0 Released in July 2007 ● Largely evolutionary development ▶ Inconsistencies in APIs, particularly surrounding plugins and configuration ▶ Best practices have been discovered over time ▶ Many key features for modern applications have been added in recent versions © All rights reserved. Zend Technologies, Inc.
  • 6.
    Zend Framework 2.0 ● First new major release ▶ Allowing us to break backwards compatibility ● Focus is on: ▶ Consistency ▶ Performance ▶ Documentation ▶ User productivity © All rights reserved. Zend Technologies, Inc.
  • 7.
    Namespaces and Autoloading 7 © All rights reserved. Zend Technologies, Inc.
  • 8.
    The Problems ● Lengthy class names ▶ Difficult to refactor ▶ Difficult to retain semantics with shorter names ● Performance issues ▶ Many classes are used JIT, and shouldn't be loaded until needed ● Missing require_once statements lead to errors © All rights reserved. Zend Technologies, Inc.
  • 9.
    ZF2 Approach: Namespaces ● Formalize the prefixes used in ZF1 ▶ Namespace separator correlates to directory separator ● Help identify dependencies (imports) ▶ Allows refactoring using different implementations easier ▶ Makes packaging easier © All rights reserved. Zend Technologies, Inc.
  • 10.
    Namespaces namespace ZendEventManager; use ZendStdlibCallbackHandler; classEventManager implements EventCollection { /* ... */ } © All rights reserved. Zend Technologies, Inc.
  • 11.
    Namespaces ● Interfaces as namespaces ▶ Interface names are adjectives or nouns ▶ Concrete implementations in a sub-namespace named after the interface ▶ Contract-Oriented paradigm © All rights reserved. Zend Technologies, Inc.
  • 12.
    Interfaces as Namespaces Zend/Session namespace ZendSession; |-- Storage.php interface Storage `-- Storage { |-- /* ... */ ArrayStorage.php } `-- SessionStorage.php namespace ZendSessionStorage; use ArrayObject, ZendSessionStorage, ZendSessionException; class ArrayStorage extends ArrayObject implements Storage { /* ... */ } © All rights reserved. Zend Technologies, Inc.
  • 13.
    ZF2 Approach: Autoloading ● No more require_once calls! ● Multiple approaches ▶ ZF1-style include_path autoloader ▶ Per-namespace/prefix autoloading ▶ Class-map autoloading © All rights reserved. Zend Technologies, Inc.
  • 14.
    ZF1-Style Autoloading require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new ZendLoaderStandardAutoloader(array( 'fallback_autoloader' => true, )); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  • 15.
    ZF2 NS/Prefix Autoloading require_once 'Zend/Loader/StandardAutoloader.php'; $loader= new ZendLoaderStandardAutoloader(); $loader->registerNamespace( 'My', __DIR__ . '/../library/My') ->registerPrefix( 'Phly_', __DIR__ . '/../library/Phly'); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  • 16.
    ZF2 Class-Map Autoloading returnarray( 'MyFooBar' => __DIR__ . '/Foo/Bar.php', ); require_once 'Zend/Loader/ClassMapAutoloader.php'; $loader = new ZendLoaderClassMapAutoloader(); $loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php'); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  • 17.
    Exceptions 17 © All rights reserved. Zend Technologies, Inc.
  • 18.
    The Problems ● All exceptions derived from a common class ● No ability to extend more semantic exception types offered in SPL © All rights reserved. Zend Technologies, Inc.
  • 19.
    ZF2 Approach ● Eliminated Zend_Exception ● Each component defines a marker Exception interface ● Additional exception types are created in an Exception subnamespace ▶ These extend SPL exceptions, and implement the component-level exception interface © All rights reserved. Zend Technologies, Inc.
  • 20.
    What the solutionprovides ● Catch specific exception types ● Catch SPL exception types ● Catch any component-level exception ● Catch based on global exception type © All rights reserved. Zend Technologies, Inc.
  • 21.
    Exceptions in use Zend/EventManager namespace |-- Exception.php ZendEventManager; `-- Exception `-- InvalidArgument- interface Exception {} Exception.php namespace ZendEventManagerException; use ZendEventManagerException; class InvalidArgumentException extends InvalidArgumentException implements Exception {} © All rights reserved. Zend Technologies, Inc.
  • 22.
    Exceptions in use namespaceZendEventManagerException; use ZendEventManagerException; try { $events->trigger('foo.bar', $object); } catch (InvalidArgumentException $e) { } catch (Exception $e) { } catch (InvalidArgumentException $e) { } catch (Exception $e) { } © All rights reserved. Zend Technologies, Inc.
  • 23.
    Configuration 23 © All rights reserved. Zend Technologies, Inc.
  • 24.
    The Problems ● Case-SeNSItiviTy ● Varying APIs ▶ setOptions() ▶ setConfig() ▶ __construct() ▶ explicit setters © All rights reserved. Zend Technologies, Inc.
  • 25.
    ZF2 Approach ● Option names will be lowercase_underscore_separated_word s ● Standard solution across components ▶ setOptions() style, proxying to setters, or ▶ per-component configuration objects © All rights reserved. Zend Technologies, Inc.
  • 26.
    setOptions() style class Foo { public function setOptions($options) { if (!is_array($options) && !($options instanceof Traversable) ) { throw new InvalidArgumentException(); } foreach ($options as $key => $value) { $method = normalize($key); if (method_exists($this, $method)) { $this->$method($value); } } © All rights reserved. Zend Technologies, Inc.
  • 27.
    Options object style classFooOptions extends Options { public $bar; public $baz; public function __construct($options = null) { if (!is_array($options) && !($options instanceof Traversable) ) { throw new InvalidArgumentException(); } foreach ($options as $key => $value) { $prop = normalize($key); $this->$prop = $value; } } } © All rights reserved. Zend Technologies, Inc.
  • 28.
    Options object style classFoo { public function __construct(Options $options = null) { if (null !== $options) { foreach ($options as $key => $value) { $this->$key = $value; } } } } © All rights reserved. Zend Technologies, Inc.
  • 29.
    Plugin Architectures 29 © All rights reserved. Zend Technologies, Inc.
  • 30.
    Terminology ● For our purposes, a “plugin” is any class that is determined at runtime. ▶ Action and view helpers ▶ Adapters ▶ Filters and validators © All rights reserved. Zend Technologies, Inc.
  • 31.
    The Problems ● Varying approaches to dynamically discovering plugin classes ▶ Prefix-path stacks (most common) ▶ Paths relative to the calling class ▶ Setters to indicate classes ● Most common approach is terrible ▶ Bad performance ▶ Hard to debug ▶ No caching of discovered plugins © All rights reserved. Zend Technologies, Inc.
  • 32.
    ZF2 Approach: PluginBroker ● Separate Plugin Location interface ▶ Allows varying implementation of plugin lookup ● Separate Plugin Broker interface ▶ Composes a Plugin Locator © All rights reserved. Zend Technologies, Inc.
  • 33.
    ZF2 Approach: PluginBroker ● Standard implementation across components ▶ Subclassing standard implementation allows type- hinting, caching discovered plugins, etc. ▶ while allowing you to substitute your own implementations ● Class-map location by default ● 2-5x performance gains! ● Easier to debug © All rights reserved. Zend Technologies, Inc.
  • 34.
    Plugin class location namespaceZendLoader; interface ShortNameLocater { public function isLoaded($name); public function getClassName($name); public function load($name); } namespace ZendView; use ZendLoaderPluginClassLoader; class HelperLoader extends PluginClassLoader { protected $plugins = array( 'action' => 'ZendViewHelperAction', 'baseurl' => 'ZendViewHelperBaseUrl', /* ... */ ); } © All rights reserved. Zend Technologies, Inc.
  • 35.
    Plugin broker namespace ZendLoader; interfaceBroker { 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( ShortNameLocater $loader); public function getClassLoader(); } © All rights reserved. Zend Technologies, Inc.
  • 36.
    Plugin broker class HelperBrokerextends PluginBroker { protected $defaultClassLoader = 'ZendViewHelperLoader'; protected $view; public function setView(Renderer $view) {} public function getView() {} 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; } } © All rights reserved. Zend Technologies, Inc.
  • 37.
    ZF2 Approach: Events ● Trigger events at interesting points in your application ▶ Use as basic subject/observer pattern ▶ Or as intercepting filters ▶ Or a full-fledged Aspect-Oriented Programming system © All rights reserved. Zend Technologies, Inc.
  • 38.
    ZF2 Approach: Events ● Compose an EventManager to a class ● Attach handlers to events ▶ Handlers receive an Event ● event name ● target (calling) object ● parameters passed ▶ Handlers can also be attached statically © All rights reserved. Zend Technologies, Inc.
  • 39.
    Triggering an event publicfunction doSomething( $with, $params = array() ) { $this->events()->trigger( __FUNCTION__, compact('with', 'params') ); /* ... */ } © All rights reserved. Zend Technologies, Inc.
  • 40.
    Listening to anevent use ZendEventManagerEventManager as Events; $events = new Events(); $events->attach('doSomething', function($e) use ($log) { $event = $e->getName(); $target = get_class($e->getTarget()); $params = json_encode($e->getParams()); $message = sprintf('%s (%s): %s', $event, $target, $params); $log->info($message); }); © All rights reserved. Zend Technologies, Inc.
  • 41.
    Attaching statically toan event use ZendEventManagerStaticEventManager as AllEvents; $events = AllEvents::getInstance(); // Specify the class composing an EventManager // as first arg $events->attach('Foo', 'doSomething', function($e) {}); © All rights reserved. Zend Technologies, Inc.
  • 42.
    Dispatchers 42 © All rights reserved. Zend Technologies, Inc.
  • 43.
    The Problems ● Not terribly performant ● Hard to customize ● Hard to inject controllers with dependencies ● Forces pre-initialization of resources if you want them configured by Zend_Application © All rights reserved. Zend Technologies, Inc.
  • 44.
    ZF2 Approach ● Discrete Request, Response, and Dispatchable interfaces ▶ Request encompasses request environment ▶ Response aggregates response returned ▶ Dispatchable objects formalize a Strategy pattern © All rights reserved. Zend Technologies, Inc.
  • 45.
    ZF2 Approach ● Anything Dispatchable can be attached to the MVC ▶ Server components (XML-RPC, JSON-RPC, etc.) ● Allows building your own MVC approach ▶ Do you want action methods to receive explicit arguments? ▶ Do you want to select a different action method based on request headers? © All rights reserved. Zend Technologies, Inc.
  • 46.
    MVC Interfaces interface Message { public function setMetadata($spec, $value = null); public function getMetadata($key = null); public function setContent($content); public function getContent(); } interface Request interface Response extends Message extends Message { { public function public function __toString(); __toString(); public function public function fromString($string); fromString($string); } public function send(); } © All rights reserved. Zend Technologies, Inc.
  • 47.
    MVC Interfaces interface Dispatchable { public function dispatch( Request $request, Response $response = null); } © All rights reserved. Zend Technologies, Inc.
  • 48.
    Inversion of Control 48 © All rights reserved. Zend Technologies, Inc.
  • 49.
    The Problems ● How do objects get dependencies? ▶ In particular, how do Controllers get dependencies? © All rights reserved. Zend Technologies, Inc.
  • 50.
    ZF2 Approach ● Service Locator ▶ Basic pattern: ● set($name, $service) ● get($name) ▶ Formalization of application services (mailer, logger, profiler, etc.) ▶ Good interface for typehinting © All rights reserved. Zend Technologies, Inc.
  • 51.
    Service Locator use ZendDiServiceLocator, ZendEventManagerEventManager; class MyLocator extends ServiceLocator { protected $events; protected $map = array('events' => 'getEvents'); public function getEvents() { if (null !== $this->events) { return $this->events; } $this->events = new EventManager(); return $this->events; } } © All rights reserved. Zend Technologies, Inc.
  • 52.
    ZF2 Approach ● Dependency Injection Container ▶ Scaffolding for constructor and setter injection ▶ Use programmatically, or from configuration ▶ Typically used to seed a service locator © All rights reserved. Zend Technologies, Inc.
  • 53.
    Dependency Injection $db =new Definition('MyDbAdapterSqlite'); $db->setParam('name', __DIR__ . '/../data/db/users.db'); $mapper = new Definition('MyMapperDb'); $mapper->addMethodCall( 'setAdapter', array(new Reference('db'))); $service = new Definition('MyResourceUsers'); $service->setParam('mapper', new Reference('mapper')); $di = new DependencyInjector; $di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service, )); © All rights reserved. Zend Technologies, Inc.
  • 54.
    Controllers as services ● Solves issue of controller dependencies ● Each request only instantiates what's needed for that request ● Better testability of controllers © All rights reserved. Zend Technologies, Inc.
  • 55.
    Controllers as services $userController= new Definition('SiteControllerUser'); $userController->setParam( 'service', new Reference('users')); $di->setDefinition($userController, 'controller- user'); // Inside dispatcher: $controller = $di->get($controllerName); $result = $controller->dispatch($request, $response); © All rights reserved. Zend Technologies, Inc.
  • 56.
    More to come! 56 © All rights reserved. Zend Technologies, Inc.
  • 57.
    Zend Framework 2.0 ● Schedule: ▶ MVC milestone by end of May ▶ Preview Release following MVC milestone ▶ Beta release during summer ▶ Stable by end-of-year © All rights reserved. Zend Technologies, Inc.
  • 58.
    Resources 58 © All rights reserved. Zend Technologies, Inc.
  • 59.
    ZF2 Wiki: http://bit.ly/zf2wiki ● ZF2 Git information: http://bit.ly/zf2gitguide ● ZF2 MVC sandbox: git://git.mwop.net/zf2sandbox.git ● ZF2 DI prototype: http://bit.ly/gBBnDS © All rights reserved. Zend Technologies, Inc.
  • 60.
    Thank you! ● http://framework.zend.com/ ● http://twitter.com/weierophinney 60 © All rights reserved. Zend Technologies, Inc.
  • 61.
    Webinar To watch the webinar please go to: http://www.zend.com/en/webinar/Framework/ 70170000000bX3J-webinar-zf-2-patterns- 20110330.flv Or http://bit.ly/qXeCWI (short registration required) Insert->Header & Footer © All rights reserved. Zend Technologies, Inc. 61