Zend Framework 2.0 Patterns Tutorial

81,859 views

Published on

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

0 Comments
90 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
81,859
On SlideShare
0
From Embeds
0
Number of Embeds
26,491
Actions
Shares
0
Downloads
1,687
Comments
0
Likes
90
Embeds 0
No embeds

No notes for slide

Zend Framework 2.0 Patterns Tutorial

  1. 1. In the beginning. . .
  2. 2. A Brief History of ZF ZF2 Patterns 3
  3. 3. Initial Announcements and Work• October 2005: Announced the project ZF2 Patterns 4
  4. 4. Initial Announcements and Work• October 2005: Announced the project• March 2006: First public preview release, 0.1.0 ZF2 Patterns 4
  5. 5. Initial Announcements and Work• October 2005: Announced the project• March 2006: First public preview release, 0.1.0• Fall 2006: Rewrite of the MVC ZF2 Patterns 4
  6. 6. 1.0.0 - July 2007• First stable release• Basic MVC system, with plugins, action helpers, automated view rendering etc. ZF2 Patterns 5
  7. 7. 1.0.0 - July 2007• First stable release• Basic MVC system, with plugins, action helpers, automated view rendering etc.• Many web service API consumers ZF2 Patterns 5
  8. 8. 1.0.0 - July 2007• 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 ZF2 Patterns 5
  9. 9. 1.5.0 - March 2008• First minor release ZF2 Patterns 6
  10. 10. 1.5.0 - March 2008• First minor release• Zend_Form introduced ZF2 Patterns 6
  11. 11. 1.5.0 - March 2008• First minor release• Zend_Form introduced• Zend_Layout introduced ZF2 Patterns 6
  12. 12. 1.5.0 - March 2008• First minor release• Zend_Form introduced• Zend_Layout introduced• Layout-aware view helper system introduced ZF2 Patterns 6
  13. 13. 1.6.0 - September 2008• Dojo integration ZF2 Patterns 7
  14. 14. 1.6.0 - September 2008• Dojo integration• PHPUnit scaffolding for testing controllers ZF2 Patterns 7
  15. 15. 1.6.0 - September 2008• Dojo integration• PHPUnit scaffolding for testing controllers• Introduction of the ContextSwitch action helper ZF2 Patterns 7
  16. 16. 1.7.0 - November 2008• AMF support ZF2 Patterns 8
  17. 17. 1.7.0 - November 2008• AMF support• Performance improvements ZF2 Patterns 8
  18. 18. 1.8.0 - April 2009• Introduction of Zend_Tool ZF2 Patterns 9
  19. 19. 1.8.0 - April 2009• Introduction of Zend_Tool• Introduction of Zend_Application ZF2 Patterns 9
  20. 20. 1.8.0 - April 2009• Introduction of Zend_Tool• Introduction of Zend_Application• First widely usable release of ZF ZF2 Patterns 9
  21. 21. 1.9.0 - August 2009• Addition of Zend_Feed_Reader ZF2 Patterns 10
  22. 22. 1.9.0 - August 2009• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility ZF2 Patterns 10
  23. 23. 1.9.0 - August 2009• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions ZF2 Patterns 10
  24. 24. 1.9.0 - August 2009• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions• Beginning of monthly bug hunts in October ZF2 Patterns 10
  25. 25. 1.10.0 - January 2010• Integration of ControllerTestCase with Zend_Application ZF2 Patterns 11
  26. 26. 1.10.0 - January 2010• Integration of ControllerTestCase with Zend_Application• Addition of Zend_Feed_Writer, marking completion of Zend_Feed refactoring ZF2 Patterns 11
  27. 27. 1.10.0 - January 2010• Integration of ControllerTestCase with Zend_Application• Addition of Zend_Feed_Writer, marking completion of Zend_Feed refactoring• Documentation changes: adoption of PhD to render end-user manual, introduction of comment system, and new “Learning Zend Framework section” ZF2 Patterns 11
  28. 28. 1.10.0 - January 2010• Integration of ControllerTestCase with Zend_Application• Addition of Zend_Feed_Writer, marking completion of Zend_Feed refactoring• Documentation changes: adoption of PhD to render end-user manual, introduction of comment system, and new “Learning Zend Framework section”• Primarily community-led additions ZF2 Patterns 11
  29. 29. 1.11.0 November 2010• Mobile support via Zend_Http_UserAgent ZF2 Patterns 12
  30. 30. 1.11.0 November 2010• Mobile support via Zend_Http_UserAgent• SimpleCloud API via Zend_Cloud ZF2 Patterns 12
  31. 31. Where do we go from here?
  32. 32. Zend Framework 2.0’s focusis on improving consistency and performance
  33. 33. Incremental Improvements
  34. 34. Baby steps• Convert code from vendor prefixes (e.g. “Zend_Foo”) to PHP 5.3 namespaces ZF2 Patterns 18
  35. 35. Baby steps• Convert code from vendor prefixes (e.g. “Zend_Foo”) to PHP 5.3 namespaces• Refactor exceptions ZF2 Patterns 18
  36. 36. Baby steps• Convert code from vendor prefixes (e.g. “Zend_Foo”) to PHP 5.3 namespaces• Refactor exceptions• Switch ZF to be autoload-only ZF2 Patterns 18
  37. 37. Baby steps• 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 ZF2 Patterns 18
  38. 38. Namespaces
  39. 39. The Problem• Lengthy class names • Difficult to refactor ZF2 Patterns 21
  40. 40. The Problem• Lengthy class names • Difficult to refactor • Difficult to retain semantics with shorter names ZF2 Patterns 21
  41. 41. Basics• Every class file declares a namespace ZF2 Patterns 22
  42. 42. Basics• Every class file declares a namespace• One namespace per file ZF2 Patterns 22
  43. 43. Basics• 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 typically aliased ZF2 Patterns 22
  44. 44. Basics• 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 typically aliased• Global resolution is discouraged, except in the case of classes referenced in strings ZF2 Patterns 22
  45. 45. Namespace Example namespace ZendEventManager; use ZendStdlibCallbackHandler; class EventManager implements EventCollection { /* ... */ } ZF2 Patterns 23
  46. 46. Using Aliases namespace ZendMvc; use ZendStdlibDispatchable, ZendDiServiceLocator as Locator; class FrontController implements Dispatchable { public function __construct(Locator $locator) { $this->serviceLocator = $locator; } } ZF2 Patterns 24
  47. 47. Recommendation for Migration Use imports instead of require_once calls in your code! ZF2 Patterns 25
  48. 48. Importing ZF1 Classes use Zend_Controller_Action as Controller; class FooController extends Controller {} // Later, this might become: use ZendControllerAction as Controller; class FooController extends Controller {} ZF2 Patterns 26
  49. 49. Naming• All code in the project is in the “Zend” namespace ZF2 Patterns 27
  50. 50. Naming• All code in the project is in the “Zend” namespace• Each component defines a unique namespace ZF2 Patterns 27
  51. 51. Naming• 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 ZF2 Patterns 27
  52. 52. Naming• 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 ZF2 Patterns 27
  53. 53. Naming Examples Zend/EventManager |-- EventCollection.php ‘-- EventManager.php ZF2 Patterns 28
  54. 54. Naming Examples Zend/EventManager namespace ZendEventManager; |-- EventCollection.php class EventManager implements ‘-- EventManager.php EventCollection { } ZF2 Patterns 28
  55. 55. Interfaces• Interfaces are named after nouns or adjectives, and describe what they provide ZF2 Patterns 29
  56. 56. Interfaces• Interfaces are named after nouns or adjectives, and describe what they provide• In most cases, concrete implementations of interfaces live in a subnamespace named after the interface ZF2 Patterns 29
  57. 57. Interfaces• Interfaces are named after nouns or adjectives, and describe what they provide• In most cases, concrete implementations of interfaces live in a subnamespace named after the interface• More solid Contract-Oriented paradigm ZF2 Patterns 29
  58. 58. Interface Examples Zend/Session |-- Storage.php ‘-- Storage |-- ArrayStorage.php ‘-- SessionStorage.php ZF2 Patterns 30
  59. 59. Interface Examples Zend/Session namespace ZendSession; |-- Storage.php ‘-- Storage use Traversable, ArrayAccess, |-- ArrayStorage.php Serializable, Countable; ‘-- SessionStorage.php interface Storage extends Traversable, ArrayAccess, Serializable, Countable { /* ... */ } ZF2 Patterns 30
  60. 60. Concrete Implementation namespace ZendSessionStorage; use ArrayObject, ZendSessionStorage, ZendSessionException; class ArrayStorage extends ArrayObject implements Storage { /* ... */ } ZF2 Patterns 31
  61. 61. Exceptions
  62. 62. The Problem• All exceptions derived from a common class ZF2 Patterns 33
  63. 63. The Problem• All exceptions derived from a common class• Inability to extend semantic exception types offered in the SPL ZF2 Patterns 33
  64. 64. The Problem• All exceptions derived from a common class• Inability to extend semantic exception types offered in the SPL• Limited catching strategies ZF2 Patterns 33
  65. 65. The Problem• All exceptions derived from a common class• Inability to extend semantic exception types offered in the SPL• Limited catching strategies• Hard dependency for each and every component ZF2 Patterns 33
  66. 66. ZF2 Approach• We eliminated Zend_Exception entirely ZF2 Patterns 34
  67. 67. ZF2 Approach• We eliminated Zend_Exception entirely• Each component defines a marker Exception interface ZF2 Patterns 34
  68. 68. ZF2 Approach• We eliminated Zend_Exception entirely• Each component defines a marker Exception interface• Concrete exceptions live in an Exception subnamespace, and extend SPL exceptions ZF2 Patterns 34
  69. 69. What the solution provides• Catch specific exception types ZF2 Patterns 35
  70. 70. What the solution provides• Catch specific exception types• Catch SPL exception types ZF2 Patterns 35
  71. 71. What the solution provides• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions ZF2 Patterns 35
  72. 72. What the solution provides• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions• Catch based on global exception type ZF2 Patterns 35
  73. 73. Exception Definitions Zend/EventManager |-- Exception.php ‘-- Exception ‘-- InvalidArgumentException.php ZF2 Patterns 36
  74. 74. Exception Definitions Zend/EventManager namespace ZendEventManager; |-- Exception.php ‘-- Exception interface Exception {} ‘-- InvalidArgumentException.php ZF2 Patterns 36
  75. 75. Exception Definitions Zend/EventManager namespace ZendEventManager; |-- Exception.php ‘-- Exception interface Exception {} ‘-- InvalidArgumentException.php namespace ZendEventManagerException; use ZendEventManagerException; class InvalidArgumentException extends InvalidArgumentException implements Exception {} ZF2 Patterns 36
  76. 76. Catching Exceptions namespace ZendEventManagerException; use ZendEventManagerException; try { $events->trigger(’foo.bar’, $object); } catch (InvalidArgumentException $e) { } catch (Exception $e) { } catch (InvalidArgumentException $e) { } catch (Exception $e) { } ZF2 Patterns 37
  77. 77. Autoloading
  78. 78. The Problem• Performance issues • Many classes are used JIT, and shouldn’t be loaded until needed ZF2 Patterns 39
  79. 79. The Problem• Performance issues • Many classes are used JIT, and shouldn’t be loaded until needed• Missing require_once calls lead to errors ZF2 Patterns 39
  80. 80. ZF2 Approach• No more require_once calls! ZF2 Patterns 40
  81. 81. ZF2 Approach• No more require_once calls!• Deliver multiple autoloading approaches • ZF1-style include_path autoloader • Per- namespace/vendor prefix autoloading • Class-Map autoloading ZF2 Patterns 40
  82. 82. ZF1-Style Autoloading require_once ’Zend/Loader/StandardAutoloader.php’; $loader = new ZendLoaderStandardAutoloader(array( ’fallback_autoloader’ => true, )); $loader->register(); ZF2 Patterns 41
  83. 83. 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(); ZF2 Patterns 42
  84. 84. Class-Map Autoloading return array( ’MyFooBar’ => __DIR__ . ’/Foo/Bar.php’, ); ZF2 Patterns 43
  85. 85. 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(); ZF2 Patterns 43
  86. 86. Class-Maps? Won’t those require work?• Yes, they will. But we already have a tool, bin/classmap_generator.php. ZF2 Patterns 44
  87. 87. Class-Maps? Won’t those require work?• Yes, they will. But we already have a tool, bin/classmap_generator.php.• Usage is trivial: prompt> cd your/library prompt> php /path/to/classmap_generator.php -w # Class-Map now exists in .classmap.php ZF2 Patterns 44
  88. 88. Why?• Class-Maps show a 25% improvement on the ZF1 autoloader when no acceleration is present ZF2 Patterns 45
  89. 89. Why?• Class-Maps show a 25% improvement on the ZF1 autoloader when no acceleration is present • and 60-85% improvements when an opcode cache is in place! ZF2 Patterns 45
  90. 90. Why?• Class-Maps show a 25% improvement on the ZF1 autoloader when no acceleration is present • and 60-85% improvements when an opcode cache is in place!• Pairing namespaces/prefixes with specific paths shows >10% gains with no acceleration ZF2 Patterns 45
  91. 91. Why?• Class-Maps show a 25% improvement on the ZF1 autoloader when no acceleration is present • and 60-85% improvements when an opcode cache is in place!• Pairing namespaces/prefixes with specific paths shows >10% gains with no acceleration • and 40% improvements when an opcode cache is in place! ZF2 Patterns 45
  92. 92. Autoloader Factory• With multiple strategies comes the need for a factory ZF2 Patterns 46
  93. 93. Autoloader Factory• With multiple strategies comes the need for a factory• Choose several strategies ZF2 Patterns 46
  94. 94. Autoloader Factory• With multiple strategies comes the need for a factory• Choose several strategies • Class-Map for fastest lookup ZF2 Patterns 46
  95. 95. Autoloader Factory• With multiple strategies comes the need for a factory• Choose several strategies • Class-Map for fastest lookup • Namespace/prefix paths for common code ZF2 Patterns 46
  96. 96. Autoloader Factory• 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 ZF2 Patterns 46
  97. 97. Autoloader Factory Example require_once ’Zend/Loader/AutoloaderFactory.php’; use ZendLoaderAutoloaderFactory; AutoloaderFactory::factory(array( ’ZendLoaderClassMapAutoloader’ => array( __DIR__ . ’/../library/.classmap.php’, __DIR__ . ’/../application/.classmap.php’, ), ’ZendLoaderStandardAutoloader’ => array( ’namespaces’ => array( ’Zend’ => __DIR__ . ’/../library/Zend’, ), ’fallback_autoloader’ => true, ), )); ZF2 Patterns 47
  98. 98. Start Migrating You can use the ZF2 autoloaders and class-map generation facilities today; start migrating now! ZF2 Patterns 48
  99. 99. Plugin Loading
  100. 100. Terminology• For our purposes, a “plugin” is any class that is determined at runtime. ZF2 Patterns 50
  101. 101. Terminology• For our purposes, a “plugin” is any class that is determined at runtime. • Action and view helpers • Adapters • Filters and validators ZF2 Patterns 50
  102. 102. The Problem• Varying approaches to dynamically discovering plugin classes ZF2 Patterns 51
  103. 103. The Problem• Varying approaches to dynamically discovering plugin classes • Paths relative to the calling class • Prefix-path stacks (most common) • Setters to indicate classes ZF2 Patterns 51
  104. 104. The Problem• Varying approaches to dynamically discovering plugin classes • Paths relative to the calling class • Prefix-path stacks (most common) • Setters to indicate classes• Most common approach is terrible ZF2 Patterns 51
  105. 105. The Problem• Varying approaches to dynamically discovering plugin classes • Paths relative to the calling class • Prefix-path stacks (most common) • Setters to indicate classes• Most common approach is terrible • Bad performance • Hard to debug • No caching of discovered plugins ZF2 Patterns 51
  106. 106. ZF2 Approach: Plugin Broker• Separate Plugin Location interface • Allows varying implementation of plugin lookup ZF2 Patterns 52
  107. 107. ZF2 Approach: Plugin Broker• Separate Plugin Location interface • Allows varying implementation of plugin lookup• Separate Plugin Broker interface • Composes a Plugin Locator ZF2 Patterns 52
  108. 108. Plugin Locator Interface namespace ZendLoader; interface ShortNameLocator { public function isLoaded($name); public function getClassName($name); public function load($name); } ZF2 Patterns 53
  109. 109. Plugin broker interface 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(ShortNameLocator $loader); public function getClassLoader(); } ZF2 Patterns 54
  110. 110. How do I use it?• Create a default plugin loader ZF2 Patterns 55
  111. 111. How do I use it?• Create a default plugin loader• Create a default plugin broker ZF2 Patterns 55
  112. 112. How do I use it?• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class ZF2 Patterns 55
  113. 113. How do I use it?• Create a default plugin loader• Create a default plugin broker• Compose a broker into your class• Optionally, define static configuration ZF2 Patterns 55
  114. 114. How do I use it?• 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 ZF2 Patterns 55
  115. 115. How do I use it?• 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 ZF2 Patterns 55
  116. 116. Plugin Locator Implementation namespace ZendView; use ZendLoaderPluginClassLoader; class HelperLoader extends PluginClassLoader { /** * @var array Pre-aliased view helpers */ protected $plugins = array( ’action’ => ’ZendViewHelperAction’, ’base_url’ => ’ZendViewHelperBaseUrl’, /* ... */ ); } ZF2 Patterns 56
  117. 117. Plugin broker implementation class HelperBroker extends PluginBroker protected $defaultClassLoader = ’ZendViewHelperLoader’; 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; } } ZF2 Patterns 57
  118. 118. Composing a broker use ZendViewHelperLoader; 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); } } ZF2 Patterns 58
  119. 119. Locator Precedence(From least specific to most specific)• Map defined in concrete plugin loader ZF2 Patterns 59
  120. 120. Locator Precedence(From least specific to most specific)• Map defined in concrete plugin loader• Static maps (latest registration having precedence) ZF2 Patterns 59
  121. 121. Locator Precedence(From least specific to most specific)• Map defined in concrete plugin loader• Static maps (latest registration having precedence)• Mapping passed via instantiation ZF2 Patterns 59
  122. 122. Locator Precedence(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 ZF2 Patterns 59
  123. 123. Defining static maps use ZendViewHelperLoader; HelperLoader::addStaticMap(array( ’url’ => ’MyHelperUrl’, ’base_url’ => ’ProjectHelperBaseUrl’, )); $loader = new HelperLoader(); $class = $loader->load(’url’); // "MyHelperUrl" ZF2 Patterns 60
  124. 124. Passing maps via configuration use ZendViewHelperLoader; $config = array( ’url’ => ’MyHelperUrl’, ’base_url’ => ’ProjectHelperBaseUrl’, ); $loader = new HelperLoader($config); $class = $loader->load(’url’); // "MyHelperUrl" ZF2 Patterns 61
  125. 125. Passing maps to maps! use ZendViewHelperLoader, ZendLoaderPluginClassLoader; class HelperMap extends PluginClassLoader { protected $plugins = array( ’url’ => ’MyHelperUrl’, ’base_url’ => ’ProjectHelperBaseUrl’, ); } $helpers = new HelperMap(); $loader = new HelperLoader($helpers); $class = $loader->load(’url’); // "MyHelperUrl" ZF2 Patterns 62
  126. 126. Extending loaders use ZendViewHelperLoader; class HelperMap extends HelperLoader { public function __construct($options = null) { // Addes to and/or overrides map in HelperLoader $this->registerPlugins(array( ’url’ => ’MyHelperUrl’, ’base_url’ => ’ProjectHelperBaseUrl’, )); parent::__construct($options); } } $helpers = new HelperMap(); $class = $loader->load(’url’); // "MyHelperUrl" ZF2 Patterns 63
  127. 127. Passing maps via broker use ZendViewHelperBroker; $broker = new HelperBroker(array( ’class_loader’ => array( ’class’ => ’HelperMap’, ’options’ => array( ’base_url’ => ’AppHelperBaseUrl’, ), ), )); $plugin = $broker->load(’base_url’); // "AppHelperBaseUrl" ZF2 Patterns 64
  128. 128. Creating maps manually use ZendViewHelperLoader; $loader = new HelperLoader(); $loader->registerPlugin(’url’, ’MyHelperUrl’) ->registerPlugins(array( ’base_url’ => ’ProjectHelperBaseUrl’, )); $class = $loader->load(’url’); // "MyHelperUrl" ZF2 Patterns 65
  129. 129. Managing plugins via a broker• By default, it consults the loader for a classname, and instantiates that class with the given arguments ZF2 Patterns 66
  130. 130. Managing plugins via a broker• By default, it consults the loader for a classname, and instantiates that class with the given arguments• Optionally, you can also seed the broker, manually registering plugin objects under a given name ZF2 Patterns 66
  131. 131. Registering a plugin with the broker use MyHelperUrl; // 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 ZF2 Patterns 67
  132. 132. What about lazy-loading?• Often you need to configure plugins ZF2 Patterns 68
  133. 133. What about lazy-loading?• Often you need to configure plugins• But you don’t want an instance hanging around until it’s actually requested ZF2 Patterns 68
  134. 134. What about lazy-loading?• Often you need to configure plugins• But you don’t want an instance hanging around until it’s actually requested• Enter the ZendLoaderLazyLoadingBroker ZF2 Patterns 68
  135. 135. LazyLoadingBroker Interface namespace ZendLoader; 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); } ZF2 Patterns 69
  136. 136. Using the LazyLoadingBroker• Register “specs” with the broker ZF2 Patterns 70
  137. 137. Using the LazyLoadingBroker• Register “specs” with the broker• When that plugin is requested, the provided options will be used unless new options are provided ZF2 Patterns 70
  138. 138. Using the LazyLoadingBroker• 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 ZF2 Patterns 70
  139. 139. LazyLoadingBroker Usage $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 ZF2 Patterns 71
  140. 140. LazyLoadingBroker Usage Via Configuration use ZendViewHelperBroker; $config = array( ’specs’ => array( ’url’ => array($request, $rourter), ), ); $broker = new HelperBroker($config); $url = $broker->load(’url’); // With $request, $router injected ZF2 Patterns 72
  141. 141. New Components
  142. 142. New Components• ZendEventManager• ZendDi ZF2 Patterns 75
  143. 143. The EventManager
  144. 144. The Problem• How do we introduce logging/debug points in framework code? ZF2 Patterns 77
  145. 145. The Problem• How do we introduce logging/debug points in framework code?• How do we allow users to introduce caching without needing to extend framework code? ZF2 Patterns 77
  146. 146. The Problem• How do we introduce logging/debug points in framework code?• How do we allow users to introduce caching without needing to extend framework code?• How do we allow users to introduce validation, filtering, ACL checks, etc., without needing to extend framework code? ZF2 Patterns 77
  147. 147. The Problem• How do we introduce logging/debug points in framework code?• How do we allow users to introduce caching without needing to extend framework code?• How do we allow users to introduce validation, filtering, ACL checks, etc., without needing to extend framework code?• How do we allow users to manipulate the order in which plugins, intercepting filters, events, etc., trigger? ZF2 Patterns 77
  148. 148. The Problem• How do we introduce logging/debug points in framework code?• How do we allow users to introduce caching without needing to extend framework code?• How do we allow users to introduce validation, filtering, ACL checks, etc., without needing to extend framework code?• How do we allow users to manipulate the order in which plugins, intercepting filters, events, etc., trigger?• How can we provide tools for userland code to benefit from the above? ZF2 Patterns 77
  149. 149. Solution: Aspect Oriented Programming• Code defines various “aspects” that may be interesting to observe and/or attach to from a consumer ZF2 Patterns 78
  150. 150. Solution: Aspect Oriented Programming• Code defines various “aspects” that may be interesting to observe and/or attach to from a consumer• Basically, all of the solutions we’ll look at can be used to implement AOP in a code base. ZF2 Patterns 78
  151. 151. Requirements• Reasonably easy to understand design ZF2 Patterns 79
  152. 152. Requirements• Reasonably easy to understand design• Allow static or per-instance attachment of handlers, preferably both ZF2 Patterns 79
  153. 153. Requirements• Reasonably easy to understand design• Allow static or per-instance attachment of handlers, preferably both • Preferably while retaining non-global state or allowing overriding ZF2 Patterns 79
  154. 154. Requirements• 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 ZF2 Patterns 79
  155. 155. Requirements• 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 ZF2 Patterns 79
  156. 156. Requirements• 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 ZF2 Patterns 79
  157. 157. Requirements• 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 ZF2 Patterns 79
  158. 158. Solution: Subject-Observer• Pros • Simple to understand ZF2 Patterns 80
  159. 159. Solution: Subject-Observer• Pros • Simple to understand • SPL interfaces are well-known (but limited) ZF2 Patterns 80
  160. 160. Solution: Subject-Observer• Pros • Simple to understand • SPL interfaces are well-known (but limited)• Cons • Typically, cannot interrupt execution of remaining observers ZF2 Patterns 80
  161. 161. Solution: Subject-Observer• 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 ZF2 Patterns 80
  162. 162. Solution: Subject-Observer• 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 ZF2 Patterns 80
  163. 163. Solution: PubSub/Events• Pros • Subscribe to arbitrary notices ZF2 Patterns 81
  164. 164. Solution: PubSub/Events• Pros • Subscribe to arbitrary notices • Typically per-component + global usage; in many languages, a single, global aggregator ZF2 Patterns 81
  165. 165. Solution: PubSub/Events• 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) ZF2 Patterns 81
  166. 166. Solution: PubSub/Events• 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 ZF2 Patterns 81
  167. 167. Solution: PubSub/Events• 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 ZF2 Patterns 81
  168. 168. Solution: PubSub/Events• 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 ZF2 Patterns 81
  169. 169. Solution: PubSub/Events• 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 ZF2 Patterns 81
  170. 170. Solution: PubSub/Events• 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 ZF2 Patterns 81
  171. 171. Solution: PubSub/Events• 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. . . ZF2 Patterns 81
  172. 172. Solution: SignalSlots• Pros • Well-known in computer science circles ZF2 Patterns 82
  173. 173. Solution: SignalSlots• Pros • Well-known in computer science circles • Code emits signals, which are intercepted by slots (aka handlers) ZF2 Patterns 82
  174. 174. Solution: SignalSlots• 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 can integrate with a global manager as well ZF2 Patterns 82
  175. 175. Solution: SignalSlots• 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 can integrate with a global manager as well • Usually has some abilities for prioritizing handlers ZF2 Patterns 82
  176. 176. Solution: SignalSlots• 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 can integrate with a global manager as well • Usually has some abilities for prioritizing handlers• Cons • Verbiage is not well-known amongst PHP developers ZF2 Patterns 82
  177. 177. Solution: SignalSlots• 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 can integrate 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 ZF2 Patterns 82
  178. 178. Solution: SignalSlots• 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 can integrate 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 ZF2 Patterns 82
  179. 179. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next in the chain ZF2 Patterns 83
  180. 180. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next in the chain • Often, the entire “work” of a method is simply a filter ZF2 Patterns 83
  181. 181. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next in the chain • Often, the entire “work” of a method is simply a filter • Depending on the design, can allow static/global access ZF2 Patterns 83
  182. 182. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next 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 ZF2 Patterns 83
  183. 183. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next 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 ZF2 Patterns 83
  184. 184. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next 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 ZF2 Patterns 83
  185. 185. Solution: Intercepting Filters• Pros • Similar to previous solutions, except that each handler receives the filter chain as an argument, and is responsible for calling the next in the chain • Often, the entire “work” of a method is simply a filter • Depending on the design, can allow static/global access• Cons • Sometimes difficult to accomplish complex workflows • Same issues with composition per-class and static usage as seen in event systems • Easy to forget to invoke next filter in chain • Typically, no ability to prioritize filters ZF2 Patterns 83
  186. 186. ZF2: EventManager Component• Cherry-picks from each of PubSub, SignalSlot, and Intercepting Filters to provide a comprehensive solution ZF2 Patterns 84
  187. 187. ZF2: EventManager Component• Cherry-picks from each of PubSub, SignalSlot, and Intercepting Filters to provide a comprehensive solution• Cannot completely solve the composition/static usage issues • We can solve the composition problem in PHP 5.4 via Traits ZF2 Patterns 84
  188. 188. ZF2: EventManager Component• Cherry-picks from each of PubSub, SignalSlot, and Intercepting Filters to provide a comprehensive solution• Cannot completely solve the composition/static usage issues • We can solve the composition problem in PHP 5.4 via Traits • There are some elegant ways to handle static usage ZF2 Patterns 84
  189. 189. EventCollection Interface namespace ZendEventManager; use ZendStdlibCallbackHandler; 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); } ZF2 Patterns 85
  190. 190. Triggering Events use ZendEventManagerEventManager; $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 */ ZF2 Patterns 86
  191. 191. CallbackHandler $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)); }); ZF2 Patterns 87
  192. 192. CallbackHandler with priority $handler = $events->attach(’some-event’, function($e) use ($log) { /* same as before */ }, 100); // Prioritize! (higher numbers win) ZF2 Patterns 88
  193. 193. Interrupting execution: testing results $results = $events->triggerUntil(’some-event’, $o, $argv, function($result) { return ($result instanceof SomeType); }); if ($results->stopped()) { return $results->last(); } ZF2 Patterns 89
  194. 194. Interrupting execution: via handlers $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(); } ZF2 Patterns 90
  195. 195. Composing an EventManager use ZendEventManagerEventCollection as Events, ZendEventManagerEventManager; 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); } } ZF2 Patterns 91
  196. 196. Using a Trait! use ZendEventManagerEventCollection as Events, ZendEventManagerEventManager; 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; } ZF2 Patterns 92
  197. 197. Connecting handlers statically use ZendEventManagerStaticEventManager; $events = StaticEventManager::getInstance(); $events->connect(’Foo’, ’some-event’, function ($e) { /* ... */ }); ZF2 Patterns 93
  198. 198. Recommendations• Name your events using __FUNCTION__ • If triggering multiple events in the same method, suffix with a “.(pre|post|etc.)” ZF2 Patterns 94
  199. 199. Recommendations• 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 the class name and one or more “service” names, to make static attachment more semantic ZF2 Patterns 94
  200. 200. Recommendations• 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 the class name and one or more “service” names, to make static attachment more semantic • This allows a single callback to listen to many components! ZF2 Patterns 94
  201. 201. Dependency Injection
  202. 202. What is Dependency Injection?Quite simply: defining ways to passdependencies into an object. ZF2 Patterns 96
  203. 203. What is Dependency Injection?Quite simply: defining ways to passdependencies into an object. namespace MyHelper; class Url { public function __construct(Request $request) { $this->request = $request; } public function setRouter(Router $router) { $this->router = $router; } } ZF2 Patterns 96
  204. 204. So, why do people fear it?• They don’t. ZF2 Patterns 97
  205. 205. So, why do people fear it?• They don’t.• They fear Dependency Injection Containers. ZF2 Patterns 97
  206. 206. What’s a Dependency Injection Container? Put simply: an object graph for mapping dependency relations between objects. ZF2 Patterns 98
  207. 207. Again, why do people fear it? It looks like magic. ZF2 Patterns 99
  208. 208. Object with Dependencies namespace MyHelper; class Url { public function __construct(Request $request) { $this->request = $request; } public function setRouter(Router $router) { $this->router = $router; } } ZF2 Patterns 100
  209. 209. Another Object with Dependencies namespace mwopMvc; class Router { public function addRoute(Route $route) { $this->routes->push($route); } } ZF2 Patterns 101
  210. 210. Grabbing an object and using it $urlHelper = $di->get(’url-helper’); echo $url->generate(’/css/site.css’); echo $url->generate(array(’id’ => $id), array(’name’ => ’blog’)); ZF2 Patterns 102
  211. 211. The questions• How can I be sure I have my dependencies? ZF2 Patterns 103
  212. 212. The questions• How can I be sure I have my dependencies? • You define them explicitly. ZF2 Patterns 103
  213. 213. The questions• 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. ZF2 Patterns 103
  214. 214. The questions• 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? ZF2 Patterns 103
  215. 215. The questions• 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. ZF2 Patterns 103
  216. 216. The questions• 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 force using different dependencies? ZF2 Patterns 103
  217. 217. The questions• 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 force using different dependencies? • Calling new doesn’t use the container. In fact, nothing forces you to use one! ZF2 Patterns 103
  218. 218. Why use one?If instantiation of your object is not under yourdirect control (e.g. controllers), how do youretain control over your dependencies? ZF2 Patterns 104
  219. 219. Why use one?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 ZF2 Patterns 104
  220. 220. Why use one?If instantiation of your object is not under yourdirect control (e.g. controllers), how do youretain control over your dependencies?• Different data access based on application environment• Substituting mock/stub implementations during testing ZF2 Patterns 104
  221. 221. ZF2 Approach• Standardize on a Service Locator interface ZF2 Patterns 105
  222. 222. ZF2 Approach• Standardize on a Service Locator interface• Provide a performant DI solution, and integrate it into a Service Locator ZF2 Patterns 105
  223. 223. ZF2 Approach• 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 ZF2 Patterns 105
  224. 224. Service Locator interface namespace ZendDi; interface ServiceLocation { public function set($name, $service); public function get($name, array $params = null); } ZF2 Patterns 106
  225. 225. Dependency Injector interface namespace ZendDi; 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(); } ZF2 Patterns 107
  226. 226. Definitions namespace ZendDi; 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(); } ZF2 Patterns 108
  227. 227. References namespace ZendDi; interface DependencyReference { public function __construct($serviceName); public function getServiceName(); } ZF2 Patterns 109
  228. 228. Class Definition use ZendDiDefinition, ZendDiReference; $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’); ZF2 Patterns 110
  229. 229. Setter Injection use ZendDiDefinition, ZendDiReference; $service = new Definition(’mwopServiceResources’); $service->addMethod(’setResource’, array( new Reference(’resource’) )); $di->setDefinition(’resources’, $service); $resources = $di->get(’resources’); ZF2 Patterns 111
  230. 230. Making it faster• Specify constructor parameter maps in definitions ZF2 Patterns 112
  231. 231. Making it faster• Specify constructor parameter maps in definitions• Generate Service Locators from a DI container ZF2 Patterns 112
  232. 232. Parameter maps $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. ZF2 Patterns 113
  233. 233. Generating a Service Locator from DI use ZendDiContainerBuilder as DiBuilder; $builder = new DiBuilder($injector); $builder->setContainerClass(’AppContext’); $container = $builder->getCodeGenerator( __DIR__ . ’/../application/AppContext.php’ ); // Returns instance of ZendCodeGeneratorPhpPhpFile $container->write(); // Write to disk ZF2 Patterns 114
  234. 234. Example of a generated locator use ZendDiDependencyInjectionContainer; class AppContext extends DependencyInjectionContainer { public function get($name, array $params = array()) { switch ($name) { case ’request’: case ’ZendHttpRequest’: return $this->getZendHttpRequest(); default: return parent::get($name, $params); } } public function getZendHttpRequest() { if (isset($this->services[’ZendHttpRequest’])) { return $this->services[’ZendHttpRequest’]; } $object = new ZendHttpRequest(); $this->services[’ZendHttpRequest’] = $object; return $object; } } ZF2 Patterns 115
  235. 235. Using a generated locator $context = new AppContext(); $request = $context->get(’request’); // Same as using a Service Locator or DI Container! ZF2 Patterns 116
  236. 236. Making it simpler• Use configuration files ZF2 Patterns 117
  237. 237. Making it simpler• Use configuration files• Can use any format supported by ZendConfig ZF2 Patterns 117
  238. 238. Configuration (JSON) { "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" } } } ZF2 Patterns 118
  239. 239. What are the use cases in ZF2? One big one. ZF2 Patterns 119
  240. 240. What are the use cases in ZF2? One big one. Pulling MVC controllers from the container ZF2 Patterns 119
  241. 241. An Action Controller namespace BlogController; 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); /* ... */ } } ZF2 Patterns 120
  242. 242. The Front Controller 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); /* ... */ } } ZF2 Patterns 121
  243. 243. Benefits to using DI this way• Performance ZF2 Patterns 122
  244. 244. Benefits to using DI this way• Performance• Code de-coupling ZF2 Patterns 122
  245. 245. Benefits to using DI this way• Performance• Code de-coupling• Simplification of controller code ZF2 Patterns 122
  246. 246. More to come!• First-run compilation ZF2 Patterns 123
  247. 247. More to come!• First-run compilation• Tools for scanning classes or namespaces to build definitions ZF2 Patterns 123
  248. 248. More to come!• First-run compilation• Tools for scanning classes or namespaces to build definitions• Interface injection ZF2 Patterns 123
  249. 249. More to come!• First-run compilation• Tools for scanning classes or namespaces to build definitions• Interface injection• . . . and likely more. ZF2 Patterns 123
  250. 250. MVC Patterns
  251. 251. The Problems• How do controllers get dependencies? ZF2 Patterns 125
  252. 252. The Problems• 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? ZF2 Patterns 125
  253. 253. The Problems• 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? ZF2 Patterns 125
  254. 254. The Problems• 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? ZF2 Patterns 125
  255. 255. The Problems• 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 within the MVC? ZF2 Patterns 125
  256. 256. The Problems• 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 within the MVC?• How can we make the MVC more performant? ZF2 Patterns 125
  257. 257. The basic structure of a web application is that of aRequest/Response lifecycle ZF2 Patterns 126
  258. 258. The Dispatchable Interface namespace ZendStdlib; interface Dispatchable { public function dispatch( Request $request, Response $response = null ); } ZF2 Patterns 127
  259. 259. Request and Response• Both the Request and Response simply aggregate metadata and content ZF2 Patterns 128
  260. 260. Request and Response• Both the Request and Response simply aggregate metadata and content• The Response also has the ability to send itself ZF2 Patterns 128
  261. 261. Request and Response• Both the Request and Response simply aggregate metadata 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, and common tasks such as determining Accept and Content-Type headers ZF2 Patterns 128
  262. 262. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern ZF2 Patterns 129
  263. 263. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern• Controllers ZF2 Patterns 129
  264. 264. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern• Controllers• Servers ZF2 Patterns 129
  265. 265. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern• Controllers• Servers• Whatever you may dream of! Just implement Dispatchable! ZF2 Patterns 129
  266. 266. Simple Front Controller Prototype 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; } ZF2 Patterns 130
  267. 267. Getting Involved
  268. 268. Contribute to ZF2!• ZF2 wiki: http://bit.ly/zf2wiki• zf-contributors mailing list: zf-contributors-subscribe@lists.zend.com• IRC: #zftalk.dev on Freenode ZF2 Patterns 133
  269. 269. ZF2 Git Repository• Git guide: http://bit.ly/zf2gitguide• GitHub: http://github.com/zendframework/zf2• Official repo: git://git.zendframework.com/zf.git http://git.zendframework.com/• You still need to sign a CLA! ZF2 Patterns 134
  270. 270. References• ZF2 Dependency Injection Proposal http://bit.ly/zf2diproposal http://bit.ly/zf2diprototype• ZF2 DI/MVC prototype sandbox http://bit.ly/zf2sandbox (mobile-layout branch is latest) ZF2 Patterns 135
  271. 271. Thank You!• Feedback: http://joind.in/3339• Twitter: http://twitter.com/weierophinney• Zend Framework: http://framework.zend.com/ ZF2 Patterns 136

×