Zend Framework 2.0 Patterns

7,894 views

Published on

Describes problems encountered in Zend Framework 1.X, and approaches being u

Published in: Technology
0 Comments
17 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,894
On SlideShare
0
From Embeds
0
Number of Embeds
31
Actions
Shares
0
Downloads
210
Comments
0
Likes
17
Embeds 0
No embeds

No notes for slide

Zend Framework 2.0 Patterns

  1. 1. Zend Framework 2 PatternsMatthew Weier OPhinneyProject Lead, Zend Framework © All rights reserved. Zend Technologies, Inc.
  2. 2. Roadmap for today● Namespaces and Autoloading● Exceptions● Configuration● Plugin systems● Dispatching● Inversion of Control © All rights reserved. Zend Technologies, Inc.
  3. 3. Format● List The Problems● Detail the ZF2 Approach © All rights reserved. Zend Technologies, Inc.
  4. 4. But first, some history © All rights reserved. Zend Technologies, Inc.
  5. 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. 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. 7. Namespaces and Autoloading7 © All rights reserved. Zend Technologies, Inc.
  8. 8. The Problems● Lengthy class names ▶ Difficult to refactor ▶ Difficult to retain semantics with shorter names● Performance issues ▶ Many classes are used JIT, and shouldnt be loaded until needed● Missing require_once statements lead to errors © All rights reserved. Zend Technologies, Inc.
  9. 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. 10. Namespacesnamespace ZendEventManager; namespace ZendEventManager;use ZendStdlibCallbackHandler; use ZendStdlibCallbackHandler;class EventManager implements EventCollection class EventManager implements EventCollection{{ /* ... */ /* ... */}} © All rights reserved. Zend Technologies, Inc.
  11. 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. 12. Interfaces as NamespacesZend/Session namespace ZendSession; namespace ZendSession;|-- Storage.php interface Storage`-- Storage interface Storage |-- ArrayStorage.php { { /* ... */ /* ... */ `-- SessionStorage.php }}namespace ZendSessionStorage; namespace ZendSessionStorage;use ArrayObject, use ArrayObject, ZendSessionStorage, ZendSessionStorage, ZendSessionException; ZendSessionException;class ArrayStorage class ArrayStorage extends ArrayObject extends ArrayObject implements Storage implements Storage{{ /* ... */ }} /* ... */ © All rights reserved. Zend Technologies, Inc.
  13. 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. 14. ZF1-Style Autoloadingrequire_once Zend/Loader/StandardAutoloader.php; require_once Zend/Loader/StandardAutoloader.php;$loader == $loader new ZendLoaderStandardAutoloader(array( new ZendLoaderStandardAutoloader(array( fallback_autoloader => true, fallback_autoloader => true,)); ));$loader->register(); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  15. 15. ZF2 NS/Prefix Autoloadingrequire_once Zend/Loader/StandardAutoloader.php; require_once Zend/Loader/StandardAutoloader.php;$loader == new ZendLoaderStandardAutoloader(); $loader new ZendLoaderStandardAutoloader();$loader->registerNamespace( $loader->registerNamespace( My, __DIR__ .. /../library/My) My, __DIR__ /../library/My) ->registerPrefix( ->registerPrefix( Phly_, __DIR__ .. /../library/Phly); Phly_, __DIR__ /../library/Phly);$loader->register(); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  16. 16. ZF2 Class-Map Autoloadingreturn array( return array( MyFooBar => __DIR__ .. /Foo/Bar.php, MyFooBar => __DIR__ /Foo/Bar.php,); );require_once Zend/Loader/ClassMapAutoloader.php; require_once Zend/Loader/ClassMapAutoloader.php;$loader == new ZendLoaderClassMapAutoloader(); $loader new ZendLoaderClassMapAutoloader();$loader->registerAutoloadMap( $loader->registerAutoloadMap( __DIR__ .. /../library/.classmap.php); __DIR__ /../library/.classmap.php);$loader->register(); $loader->register(); © All rights reserved. Zend Technologies, Inc.
  17. 17. Exceptions17 © All rights reserved. Zend Technologies, Inc.
  18. 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. 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. 20. 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.
  21. 21. Exceptions in useZend/EventManager Zend/EventManager namespace ZendEventManager; namespace ZendEventManager;|-- Exception.php |-- Exception.php`-- Exception `-- Exception interface Exception {} interface Exception {} `-- InvalidArgument- `-- InvalidArgument- Exception.php Exception.phpnamespace ZendEventManagerException; namespace ZendEventManagerException;use ZendEventManagerException; use ZendEventManagerException;class InvalidArgumentException class InvalidArgumentException extends InvalidArgumentException extends InvalidArgumentException implements Exception implements Exception{} {} © All rights reserved. Zend Technologies, Inc.
  22. 22. Exceptions in usenamespace ZendEventManagerException; namespace ZendEventManagerException;use ZendEventManagerException; use ZendEventManagerException;try {{ try $events->trigger(foo.bar, $object); $events->trigger(foo.bar, $object);}} catch (InvalidArgumentException $e) {{ catch (InvalidArgumentException $e)}} catch (Exception $e) {{ catch (Exception $e)}} catch (InvalidArgumentException $e) {{ catch (InvalidArgumentException $e)}} catch (Exception $e) {{ catch (Exception $e)}} © All rights reserved. Zend Technologies, Inc.
  23. 23. Configuration23 © All rights reserved. Zend Technologies, Inc.
  24. 24. The Problems● Case-SeNSItiviTy● Varying APIs ▶ setOptions() ▶ setConfig() ▶ __construct() ▶ explicit setters © All rights reserved. Zend Technologies, Inc.
  25. 25. ZF2 Approach● Option names will be lowercase_underscore_separated_words● Standard solution across components ▶ setOptions() style, proxying to setters, or ▶ per-component configuration objects © All rights reserved. Zend Technologies, Inc.
  26. 26. setOptions() styleclass Foo class Foo{{ public function setOptions($options) public function setOptions($options) {{ if (!is_array($options) if (!is_array($options) && !($options instanceof Traversable) && !($options instanceof Traversable) )) {{ throw new InvalidArgumentException(); throw new InvalidArgumentException(); }} foreach ($options as $key => $value) {{ foreach ($options as $key => $value) $method == normalize($key); $method normalize($key); if (method_exists($this, $method)) {{ if (method_exists($this, $method)) $this->$method($value); $this->$method($value); }} }} }}}} © All rights reserved. Zend Technologies, Inc.
  27. 27. Options object styleclass FooOptions extends Options class FooOptions extends Options{{ public $bar; public $bar; public $baz; public $baz; public function __construct($options == null) public function __construct($options null) {{ if (!is_array($options) if (!is_array($options) && !($options instanceof Traversable) && !($options instanceof Traversable) )) {{ throw new InvalidArgumentException(); throw new InvalidArgumentException(); }} foreach ($options as $key => $value) {{ foreach ($options as $key => $value) $prop == normalize($key); $prop normalize($key); $this->$prop == $value; $this->$prop $value; }} }}}} © All rights reserved. Zend Technologies, Inc.
  28. 28. Options object styleclass Foo class Foo{{ public function __construct(Options $options == null) public function __construct(Options $options null) {{ if (null !== $options) {{ if (null !== $options) foreach ($options as $key => $value) {{ foreach ($options as $key => $value) $this->$key == $value; $this->$key $value; }} }} }}}} © All rights reserved. Zend Technologies, Inc.
  29. 29. Plugin Architectures29 © All rights reserved. Zend Technologies, Inc.
  30. 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. 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. 32. 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.
  33. 33. 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.
  34. 34. Plugin class locationnamespace ZendLoader; namespace ZendLoader;interface ShortNameLocater interface ShortNameLocater{{ public function isLoaded($name); public function isLoaded($name); public function getClassName($name); public function getClassName($name); public function load($name); public function load($name);}}namespace ZendView; namespace ZendView;use ZendLoaderPluginClassLoader; use ZendLoaderPluginClassLoader;class HelperLoader extends PluginClassLoader class HelperLoader extends PluginClassLoader{{ protected $plugins == array( protected $plugins array( action => ZendViewHelperAction, action => ZendViewHelperAction, baseurl => ZendViewHelperBaseUrl, baseurl => ZendViewHelperBaseUrl, /* ... */ /* ... */ ); );}} © All rights reserved. Zend Technologies, Inc.
  35. 35. Plugin brokernamespace ZendLoader; namespace ZendLoader;interface Broker interface Broker{{ public function load($plugin, array $options == null); public function load($plugin, array $options null); public function getPlugins(); public function getPlugins(); public function isLoaded($name); public function isLoaded($name); public function register($name, $plugin); public function register($name, $plugin); public function unregister($name); public function unregister($name); public function setClassLoader( public function setClassLoader( ShortNameLocater $loader); ShortNameLocater $loader); public function getClassLoader(); public function getClassLoader();}} © All rights reserved. Zend Technologies, Inc.
  36. 36. Plugin brokerclass HelperBroker extends PluginBroker {{ class HelperBroker extends PluginBroker protected $defaultClassLoader == ZendViewHelperLoader; protected $defaultClassLoader ZendViewHelperLoader; protected $view; protected $view; public function setView(Renderer $view) {} public function setView(Renderer $view) {} public function getView() {} public function getView() {} public function load($plugin, array $options == null) {{ public function load($plugin, array $options null) $helper == parent::load($plugin, $options); $helper parent::load($plugin, $options); if (null !== ($view == $this->getView())) {{ if (null !== ($view $this->getView())) $helper->setView($view); $helper->setView($view); }} return $helper; return $helper; }} protected function validatePlugin($plugin) protected function validatePlugin($plugin) {{ if (!$plugin instanceof Helper) {{ if (!$plugin instanceof Helper) throw new InvalidHelperException(); throw new InvalidHelperException(); }} return true; return true; }}}} © All rights reserved. Zend Technologies, Inc.
  37. 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. 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. 39. Triggering an eventpublic function doSomething( public function doSomething( $with, $params == array() $with, $params array())) {{ $this->events()->trigger( $this->events()->trigger( __FUNCTION__, compact(with, params) __FUNCTION__, compact(with, params) ); ); /* ... */ /* ... */}} © All rights reserved. Zend Technologies, Inc.
  40. 40. Listening to an eventuse ZendEventManagerEventManager as Events; use ZendEventManagerEventManager as Events;$events == new Events(); $events new Events();$events->attach(doSomething, function($e) use ($log) {{ $events->attach(doSomething, function($e) use ($log) $event == $e->getName(); $event $e->getName(); $target == get_class($e->getTarget()); $target get_class($e->getTarget()); $params == json_encode($e->getParams()); $params json_encode($e->getParams()); $message == sprintf(%s (%s): %s, $event, $target, $message sprintf(%s (%s): %s, $event, $target,$params); $params); $log->info($message); $log->info($message);}); }); © All rights reserved. Zend Technologies, Inc.
  41. 41. Attaching statically to an eventuse ZendEventManagerStaticEventManager as AllEvents; use ZendEventManagerStaticEventManager as AllEvents;$events == AllEvents::getInstance(); $events AllEvents::getInstance();// Specify the class composing an EventManager // Specify the class composing an EventManager// as first arg // as first arg$events->attach(Foo, doSomething, function($e) {}); $events->attach(Foo, doSomething, function($e) {}); © All rights reserved. Zend Technologies, Inc.
  42. 42. Dispatchers42 © All rights reserved. Zend Technologies, Inc.
  43. 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. 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. 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. 46. MVC Interfacesinterface Message interface Message{{ public function setMetadata($spec, $value == null); public function setMetadata($spec, $value null); public function getMetadata($key == null); public function getMetadata($key null); public function setContent($content); public function setContent($content); public function getContent(); public function getContent();}}interface Request interface Request interface Response interface Response extends Message extends Message extends Message extends Message{{ {{ public function public function public function public function __toString(); __toString(); __toString(); __toString(); public function public function public function public function fromString($string); fromString($string); fromString($string); fromString($string);}} public function send(); public function send(); }} © All rights reserved. Zend Technologies, Inc.
  47. 47. MVC Interfacesinterface Dispatchable interface Dispatchable{{ public function dispatch( public function dispatch( Request $request, Request $request, Response $response == null); Response $response null);}} © All rights reserved. Zend Technologies, Inc.
  48. 48. Inversion of Control48 © All rights reserved. Zend Technologies, Inc.
  49. 49. The Problems● How do objects get dependencies? ▶ In particular, how do Controllers get dependencies? © All rights reserved. Zend Technologies, Inc.
  50. 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. 51. Service Locatoruse ZendDiServiceLocator, use ZendDiServiceLocator, ZendEventManagerEventManager; ZendEventManagerEventManager;class MyLocator extends ServiceLocator class MyLocator extends ServiceLocator{{ protected $events; protected $events; protected $map == array(events => getEvents); protected $map array(events => getEvents); public function getEvents() public function getEvents() {{ if (null !== $this->events) {{ if (null !== $this->events) return $this->events; return $this->events; }} $this->events == new EventManager(); $this->events new EventManager(); return $this->events; return $this->events; }}}} © All rights reserved. Zend Technologies, Inc.
  52. 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. 53. Dependency Injection$db == new Definition(MyDbAdapterSqlite); $db new Definition(MyDbAdapterSqlite);$db->setParam(name, __DIR__ .. /../data/db/users.db); $db->setParam(name, __DIR__ /../data/db/users.db);$mapper == new Definition(MyMapperDb); $mapper new Definition(MyMapperDb);$mapper->addMethodCall( $mapper->addMethodCall( setAdapter, array(new Reference(db))); setAdapter, array(new Reference(db)));$service == new Definition(MyResourceUsers); $service new Definition(MyResourceUsers);$service->setParam(mapper, new Reference(mapper)); $service->setParam(mapper, new Reference(mapper));$di == new DependencyInjector; $di new DependencyInjector;$di->setDefinitions(array( $di->setDefinitions(array( db db => $db, => $db, mapper => $mapper, mapper => $mapper, users => $service, users => $service,)); ));$users == $di->get(users); // MyResourceUsers $users $di->get(users); // MyResourceUsers © All rights reserved. Zend Technologies, Inc.
  54. 54. Controllers as services● Solves issue of controller dependencies● Each request only instantiates whats needed for that request● Better testability of controllers © All rights reserved. Zend Technologies, Inc.
  55. 55. Controllers as services$userController == new Definition(SiteControllerUser); $userController new Definition(SiteControllerUser);$userController->setParam( $userController->setParam( service, new Reference(users)); service, new Reference(users));$di->setDefinition($userController, controller-user); $di->setDefinition($userController, controller-user);// Inside dispatcher: // Inside dispatcher:$controller == $di->get($controllerName); $controller $di->get($controllerName);$result == $controller->dispatch($request, $response); $result $controller->dispatch($request, $response); © All rights reserved. Zend Technologies, Inc.
  56. 56. More to come!56 © All rights reserved. Zend Technologies, Inc.
  57. 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. 58. Resources58 © All rights reserved. Zend Technologies, Inc.
  59. 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. 60. Thank you! ● http://framework.zend.com/ ● http://twitter.com/weierophinney60 © All rights reserved. Zend Technologies, Inc.

×