Zend Framework 2.0 Patterns Tutorial

  • 70,901 views
Uploaded on

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

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

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
70,901
On Slideshare
0
From Embeds
0
Number of Embeds
27

Actions

Shares
Downloads
1,524
Comments
0
Likes
77

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. In the beginning. . .
  • 2. A Brief History of ZF ZF2 Patterns 3
  • 3. Initial Announcements and Work• October 2005: Announced the project ZF2 Patterns 4
  • 4. Initial Announcements and Work• October 2005: Announced the project• March 2006: First public preview release, 0.1.0 ZF2 Patterns 4
  • 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. 1.0.0 - July 2007• First stable release• Basic MVC system, with plugins, action helpers, automated view rendering etc. ZF2 Patterns 5
  • 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. 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. 1.5.0 - March 2008• First minor release ZF2 Patterns 6
  • 10. 1.5.0 - March 2008• First minor release• Zend_Form introduced ZF2 Patterns 6
  • 11. 1.5.0 - March 2008• First minor release• Zend_Form introduced• Zend_Layout introduced ZF2 Patterns 6
  • 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. 1.6.0 - September 2008• Dojo integration ZF2 Patterns 7
  • 14. 1.6.0 - September 2008• Dojo integration• PHPUnit scaffolding for testing controllers ZF2 Patterns 7
  • 15. 1.6.0 - September 2008• Dojo integration• PHPUnit scaffolding for testing controllers• Introduction of the ContextSwitch action helper ZF2 Patterns 7
  • 16. 1.7.0 - November 2008• AMF support ZF2 Patterns 8
  • 17. 1.7.0 - November 2008• AMF support• Performance improvements ZF2 Patterns 8
  • 18. 1.8.0 - April 2009• Introduction of Zend_Tool ZF2 Patterns 9
  • 19. 1.8.0 - April 2009• Introduction of Zend_Tool• Introduction of Zend_Application ZF2 Patterns 9
  • 20. 1.8.0 - April 2009• Introduction of Zend_Tool• Introduction of Zend_Application• First widely usable release of ZF ZF2 Patterns 9
  • 21. 1.9.0 - August 2009• Addition of Zend_Feed_Reader ZF2 Patterns 10
  • 22. 1.9.0 - August 2009• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility ZF2 Patterns 10
  • 23. 1.9.0 - August 2009• Addition of Zend_Feed_Reader• PHP 5.3 support/compatibility• Primarily community-led additions ZF2 Patterns 10
  • 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. 1.10.0 - January 2010• Integration of ControllerTestCase with Zend_Application ZF2 Patterns 11
  • 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. 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. 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. 1.11.0 November 2010• Mobile support via Zend_Http_UserAgent ZF2 Patterns 12
  • 30. 1.11.0 November 2010• Mobile support via Zend_Http_UserAgent• SimpleCloud API via Zend_Cloud ZF2 Patterns 12
  • 31. Where do we go from here?
  • 32. Zend Framework 2.0’s focusis on improving consistency and performance
  • 33. Incremental Improvements
  • 34. Baby steps• Convert code from vendor prefixes (e.g. “Zend_Foo”) to PHP 5.3 namespaces ZF2 Patterns 18
  • 35. Baby steps• Convert code from vendor prefixes (e.g. “Zend_Foo”) to PHP 5.3 namespaces• Refactor exceptions ZF2 Patterns 18
  • 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. 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. Namespaces
  • 39. The Problem• Lengthy class names • Difficult to refactor ZF2 Patterns 21
  • 40. The Problem• Lengthy class names • Difficult to refactor • Difficult to retain semantics with shorter names ZF2 Patterns 21
  • 41. Basics• Every class file declares a namespace ZF2 Patterns 22
  • 42. Basics• Every class file declares a namespace• One namespace per file ZF2 Patterns 22
  • 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. 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. Namespace Example namespace ZendEventManager; use ZendStdlibCallbackHandler; class EventManager implements EventCollection { /* ... */ } ZF2 Patterns 23
  • 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. Recommendation for Migration Use imports instead of require_once calls in your code! ZF2 Patterns 25
  • 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. Naming• All code in the project is in the “Zend” namespace ZF2 Patterns 27
  • 50. Naming• All code in the project is in the “Zend” namespace• Each component defines a unique namespace ZF2 Patterns 27
  • 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. 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. Naming Examples Zend/EventManager |-- EventCollection.php ‘-- EventManager.php ZF2 Patterns 28
  • 54. Naming Examples Zend/EventManager namespace ZendEventManager; |-- EventCollection.php class EventManager implements ‘-- EventManager.php EventCollection { } ZF2 Patterns 28
  • 55. Interfaces• Interfaces are named after nouns or adjectives, and describe what they provide ZF2 Patterns 29
  • 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. 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. Interface Examples Zend/Session |-- Storage.php ‘-- Storage |-- ArrayStorage.php ‘-- SessionStorage.php ZF2 Patterns 30
  • 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. Concrete Implementation namespace ZendSessionStorage; use ArrayObject, ZendSessionStorage, ZendSessionException; class ArrayStorage extends ArrayObject implements Storage { /* ... */ } ZF2 Patterns 31
  • 61. Exceptions
  • 62. The Problem• All exceptions derived from a common class ZF2 Patterns 33
  • 63. The Problem• All exceptions derived from a common class• Inability to extend semantic exception types offered in the SPL ZF2 Patterns 33
  • 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. 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. ZF2 Approach• We eliminated Zend_Exception entirely ZF2 Patterns 34
  • 67. ZF2 Approach• We eliminated Zend_Exception entirely• Each component defines a marker Exception interface ZF2 Patterns 34
  • 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. What the solution provides• Catch specific exception types ZF2 Patterns 35
  • 70. What the solution provides• Catch specific exception types• Catch SPL exception types ZF2 Patterns 35
  • 71. What the solution provides• Catch specific exception types• Catch SPL exception types• Catch component-level exceptions ZF2 Patterns 35
  • 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. Exception Definitions Zend/EventManager |-- Exception.php ‘-- Exception ‘-- InvalidArgumentException.php ZF2 Patterns 36
  • 74. Exception Definitions Zend/EventManager namespace ZendEventManager; |-- Exception.php ‘-- Exception interface Exception {} ‘-- InvalidArgumentException.php ZF2 Patterns 36
  • 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. 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. Autoloading
  • 78. The Problem• Performance issues • Many classes are used JIT, and shouldn’t be loaded until needed ZF2 Patterns 39
  • 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. ZF2 Approach• No more require_once calls! ZF2 Patterns 40
  • 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. ZF1-Style Autoloading require_once ’Zend/Loader/StandardAutoloader.php’; $loader = new ZendLoaderStandardAutoloader(array( ’fallback_autoloader’ => true, )); $loader->register(); ZF2 Patterns 41
  • 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. Class-Map Autoloading return array( ’MyFooBar’ => __DIR__ . ’/Foo/Bar.php’, ); ZF2 Patterns 43
  • 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. Class-Maps? Won’t those require work?• Yes, they will. But we already have a tool, bin/classmap_generator.php. ZF2 Patterns 44
  • 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. Why?• Class-Maps show a 25% improvement on the ZF1 autoloader when no acceleration is present ZF2 Patterns 45
  • 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. 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. 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. Autoloader Factory• With multiple strategies comes the need for a factory ZF2 Patterns 46
  • 93. Autoloader Factory• With multiple strategies comes the need for a factory• Choose several strategies ZF2 Patterns 46
  • 94. Autoloader Factory• With multiple strategies comes the need for a factory• Choose several strategies • Class-Map for fastest lookup ZF2 Patterns 46
  • 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. 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. 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. Start Migrating You can use the ZF2 autoloaders and class-map generation facilities today; start migrating now! ZF2 Patterns 48
  • 99. Plugin Loading
  • 100. Terminology• For our purposes, a “plugin” is any class that is determined at runtime. ZF2 Patterns 50
  • 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. The Problem• Varying approaches to dynamically discovering plugin classes ZF2 Patterns 51
  • 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. 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. 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. ZF2 Approach: Plugin Broker• Separate Plugin Location interface • Allows varying implementation of plugin lookup ZF2 Patterns 52
  • 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. Plugin Locator Interface namespace ZendLoader; interface ShortNameLocator { public function isLoaded($name); public function getClassName($name); public function load($name); } ZF2 Patterns 53
  • 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. How do I use it?• Create a default plugin loader ZF2 Patterns 55
  • 111. How do I use it?• Create a default plugin loader• Create a default plugin broker ZF2 Patterns 55
  • 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. 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. 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. 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. 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. 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. 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. Locator Precedence(From least specific to most specific)• Map defined in concrete plugin loader ZF2 Patterns 59
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. What about lazy-loading?• Often you need to configure plugins ZF2 Patterns 68
  • 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. 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. 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. Using the LazyLoadingBroker• Register “specs” with the broker ZF2 Patterns 70
  • 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. 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. 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. 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. New Components
  • 142. New Components• ZendEventManager• ZendDi ZF2 Patterns 75
  • 143. The EventManager
  • 144. The Problem• How do we introduce logging/debug points in framework code? ZF2 Patterns 77
  • 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. 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. 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. 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. 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. 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. Requirements• Reasonably easy to understand design ZF2 Patterns 79
  • 152. Requirements• Reasonably easy to understand design• Allow static or per-instance attachment of handlers, preferably both ZF2 Patterns 79
  • 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. 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. 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. 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. 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. Solution: Subject-Observer• Pros • Simple to understand ZF2 Patterns 80
  • 159. Solution: Subject-Observer• Pros • Simple to understand • SPL interfaces are well-known (but limited) ZF2 Patterns 80
  • 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. 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. 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. Solution: PubSub/Events• Pros • Subscribe to arbitrary notices ZF2 Patterns 81
  • 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. 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. 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. 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. 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. 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. 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. 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. Solution: SignalSlots• Pros • Well-known in computer science circles ZF2 Patterns 82
  • 173. Solution: SignalSlots• Pros • Well-known in computer science circles • Code emits signals, which are intercepted by slots (aka handlers) ZF2 Patterns 82
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. ZF2: EventManager Component• Cherry-picks from each of PubSub, SignalSlot, and Intercepting Filters to provide a comprehensive solution ZF2 Patterns 84
  • 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. 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. 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. 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. 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. CallbackHandler with priority $handler = $events->attach(’some-event’, function($e) use ($log) { /* same as before */ }, 100); // Prioritize! (higher numbers win) ZF2 Patterns 88
  • 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. 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. 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. 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. Connecting handlers statically use ZendEventManagerStaticEventManager; $events = StaticEventManager::getInstance(); $events->connect(’Foo’, ’some-event’, function ($e) { /* ... */ }); ZF2 Patterns 93
  • 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. 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. 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. Dependency Injection
  • 202. What is Dependency Injection?Quite simply: defining ways to passdependencies into an object. ZF2 Patterns 96
  • 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. So, why do people fear it?• They don’t. ZF2 Patterns 97
  • 205. So, why do people fear it?• They don’t.• They fear Dependency Injection Containers. ZF2 Patterns 97
  • 206. What’s a Dependency Injection Container? Put simply: an object graph for mapping dependency relations between objects. ZF2 Patterns 98
  • 207. Again, why do people fear it? It looks like magic. ZF2 Patterns 99
  • 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. Another Object with Dependencies namespace mwopMvc; class Router { public function addRoute(Route $route) { $this->routes->push($route); } } ZF2 Patterns 101
  • 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. The questions• How can I be sure I have my dependencies? ZF2 Patterns 103
  • 212. The questions• How can I be sure I have my dependencies? • You define them explicitly. ZF2 Patterns 103
  • 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. 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. 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. 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. 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. 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. 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. 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. ZF2 Approach• Standardize on a Service Locator interface ZF2 Patterns 105
  • 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. 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. Service Locator interface namespace ZendDi; interface ServiceLocation { public function set($name, $service); public function get($name, array $params = null); } ZF2 Patterns 106
  • 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. 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. References namespace ZendDi; interface DependencyReference { public function __construct($serviceName); public function getServiceName(); } ZF2 Patterns 109
  • 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. 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. Making it faster• Specify constructor parameter maps in definitions ZF2 Patterns 112
  • 231. Making it faster• Specify constructor parameter maps in definitions• Generate Service Locators from a DI container ZF2 Patterns 112
  • 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. 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. 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. Using a generated locator $context = new AppContext(); $request = $context->get(’request’); // Same as using a Service Locator or DI Container! ZF2 Patterns 116
  • 236. Making it simpler• Use configuration files ZF2 Patterns 117
  • 237. Making it simpler• Use configuration files• Can use any format supported by ZendConfig ZF2 Patterns 117
  • 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. What are the use cases in ZF2? One big one. ZF2 Patterns 119
  • 240. What are the use cases in ZF2? One big one. Pulling MVC controllers from the container ZF2 Patterns 119
  • 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. 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. Benefits to using DI this way• Performance ZF2 Patterns 122
  • 244. Benefits to using DI this way• Performance• Code de-coupling ZF2 Patterns 122
  • 245. Benefits to using DI this way• Performance• Code de-coupling• Simplification of controller code ZF2 Patterns 122
  • 246. More to come!• First-run compilation ZF2 Patterns 123
  • 247. More to come!• First-run compilation• Tools for scanning classes or namespaces to build definitions ZF2 Patterns 123
  • 248. More to come!• First-run compilation• Tools for scanning classes or namespaces to build definitions• Interface injection ZF2 Patterns 123
  • 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. MVC Patterns
  • 251. The Problems• How do controllers get dependencies? ZF2 Patterns 125
  • 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. 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. 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. 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. 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. The basic structure of a web application is that of aRequest/Response lifecycle ZF2 Patterns 126
  • 258. The Dispatchable Interface namespace ZendStdlib; interface Dispatchable { public function dispatch( Request $request, Response $response = null ); } ZF2 Patterns 127
  • 259. Request and Response• Both the Request and Response simply aggregate metadata and content ZF2 Patterns 128
  • 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. 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. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern ZF2 Patterns 129
  • 263. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern• Controllers ZF2 Patterns 129
  • 264. Anything dispatchable can attach to the MVCDispatchable is simply a formalization ofthe Command pattern• Controllers• Servers ZF2 Patterns 129
  • 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. 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. Getting Involved
  • 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. 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. 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. Thank You!• Feedback: http://joind.in/3339• Twitter: http://twitter.com/weierophinney• Zend Framework: http://framework.zend.com/ ZF2 Patterns 136