• Like
Zend Framework 2.0 Patterns
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Zend Framework 2.0 Patterns

  • 6,729 views
Published

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

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

Published in Technology
  • 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
6,729
On SlideShare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
206
Comments
0
Likes
15

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