• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Zf2 phpquebec
 

Zf2 phpquebec

on

  • 2,757 views

ZF2 Modules and Service locators....

ZF2 Modules and Service locators....

Statistics

Views

Total Views
2,757
Views on SlideShare
2,757
Embed Views
0

Actions

Likes
1
Downloads
61
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Zf2 phpquebec Zf2 phpquebec Presentation Transcript

    • ZF2 Modules and Services (And DI)Maurice KherlakianZend Technologies © All rights reserved. Zend Technologies, Inc.
    • Who am I? • Zend Professional Services consultant • Worked with PHP for about 10 years • Based in Montreal Linkedin: http://ca.linkedin.com/in/mkherlakian Twitter: http://twitter.com/mkherlakian Email: maurice.k@zend.com2 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • ZF2 Modules – What are they? • Discrete blocks of code • Allow for code re-use (not only within ZF2 but with other frameworks – Sf2 anyone?) • Physically a namespaced directory • If written well, distributable and re-usable • Examples:  User module (authentication – login/logout…)  ACL module  Blog module3 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Why are they better than ZF1’s modules • ZF1 modules had serious problems • Tightly coupled with MVC • Could not be easily reused • Bootstrapping expensive • Not self-contained • No dependency management ZF2 addresses all of these problems4 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Requirements for a module – Module class • A namespaced class called Module <?php namespace Mymod; class Module {} • That’s it!5 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Requirements for a module – Directory structure • There is, of course, a recommended directory structure6 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Requirements for a module - Registration • In order for the application (Zend/Application) to run your module, it has to be registered <?php //application.config.php return array( modules => array( //Which modules are we loading? Application, Mymod, ), module_listener_options => array( config_glob_paths => array( config/autoload/{,*.}{global,local}.php, ), config_cache_enabled => false, cache_dir => data/cache, module_paths => array( //What paths are we loading modules from? ./module, //We will look for a Module.php file in subdirs ./vendor, //one level down from this dir *by default* ), ), service_manager => array( //More on that later use_defaults => true, factories => array( ), ), );7 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Optional for a module – getConfig() • Called automatically to get the module’s configuration and aggregate it with the other modules • Best is to include a config file that returns a php array (best practice in ZF2 in general) <?php namespace Mymod; use ZendModuleManagerModuleManager, ZendMvcMvcEvent; class Module { public function getConfig() { return include(__DIR__./config/module.config.php); } }8 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Optional for a module – init() • A module can have an init() method that fires upon initialization • The ModuleManager is passed to the init function as an argument <?php namespace Mymod; use ZendModuleManagerModuleManager, ZendMvcMvcEvent; class Module { public function init(ModuleManager $e) { $e->events()->attach( loadModules.post, function($e) { echo postLoad from MyMod; }, 100); $e->events()->getSharedManager()->attach( __NAMESPACE__, dispatch, function($e) { echo "Only if dispatched to Mymod"; }, 100); } }9 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Optional for a module – onBootstrap() • And if init() is too early, ModuleManager automatically registers the onBootstrap method if found in the module • An MvcEvent is passed as the argument <?php namespace Mymod; use ZendModuleManagerModuleManager, ZendMvcMvcEvent; class Module { public function onBootstrap(MvcEvent $e) { $request = $e->getRequest(); } }10 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Optional for a module – Dep solving • Thru getProvides() and getDependencies() • Off by default, can be turned on <?php namespace Blog; class Module { public function getProvides() { return array( name => Blog, version => 0.1.0, ); } public function getDependencies() { return array( php => array( required => true, version => >=5.3.1, ), ext/mongo => array( required => true, version => >=1.2.0, ), ); } }11 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • ModuleManager • It’s automatically instantiated in your ZendApplication • It fulfills 3 functions:  Aggregates enabled modules (allows you to iterate over them)  Aggregates the configuration from each module  Triggers the module initialization • There are many events for which the ModuleManager is passed as an argument • This allows you to provide listeners at practically any point in the code to get access to the manager12 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • An MVC module • In most cases that’s what you will want <?php //module.config.php return array( router => array( routes => array( Mymod => array( type => ZendMvcRouterHttpLiteral, options => array( route => /mymod, defaults => array( controller => mymod, action => index, ), ), ), ), ), controller => array( classes => array( mymod => MymodControllerIndexController, ), ), view_manager => array( template_path_stack => array( __DIR__ . /../view, ), ), );13 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • The missing link - bootstrapping – index.php <?php // /public/index.php require_once Loader/StandardAutoloader.php; use ZendLoaderStandardAutoloader, ZendServiceManagerServiceManager, ZendMvcServiceServiceManagerConfiguration; $loader = new StandardAutoloader(); $loader->registerNamespace(Application, module/Application/src/Application); $loader->registerNamespace(Mymod, module/Mymod/src/Application); spl_autoload_register(array($loader, autoload)); // Get application stack configuration chdir(dirname(__DIR__)); $configuration = include config/application.config.php; // Setup service manager $serviceManager = new ServiceManager(new ServiceManagerConfiguration($configuration[service_manager])); $serviceManager->setService(ApplicationConfiguration, $configuration); $serviceManager->get(ModuleManager)->loadModules(); // Run application $serviceManager->get(Application)->bootstrap()->run()->send();14 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • The missing link - bootstrapping – index.php • Autoloading – it is the responsibility of index.php to set up autoloading • This is because modules have to be portable between different frameworks (reusability) • Any PSR-0 autoloader should work, it does not have to be ZF2’s autoloader  For example Rob Allen’s Skeleton module uses Composer’s autoloader • The next lines are the ServiceManager’s setup (more on it later)15 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Modules distribution • Any source you can think of  Pyrus  Git  Http  Tar & send  Composer • There is already a ZF2 modules site http://modules.zendframework.com/ (We need help! Want to contribute?)16 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Modules packaging • Tar/Zip • Phar (being careful that writes occur in location external to the archive)17 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location DI - short summary • Since the presentation was originally about ZendDi it’s only fair that we talk about it! • DI is the practice of reducing coupling between classes by injecting dependent classes in the subject instead of instantiating them <?php //No DI class DbAdapter { public function __construct($host, $user, $pass, $db) { //... } } class Author { protected $_db; public function __construct($host, $user, $pass, $db) { $this->_db = new DbAdapter($host, $user, $pass, $db); } }18 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location DI - short summary <?php //DI class DbAdapter { public function __construct($host, $user, $pass, $db) { //... } } class Author { protected $_db; public function __construct($db) { $this->_db = $db; } } $db = new DbAdapter(); $author = new Author($db); • That’s all it is – Really! Makes it easy to substitute the DB class for mocking, or to change it all together for instance, and promotes decoupling and reusability. The D in SOLID.19 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location DI - short summary • Consider the case that an Author needs a DbGateway, which needs a DbAdapter, and a logging and caching class <?php $db = new DbAdapter(); $gateway = new DbGateway($db); $cache = new Cache(); $log = new Log(); $author = new Author($db, $gateway, $cache, $log); $authors = $author->fetchAll(); • 5 lines of code for initialization, but only one line for what we really need to do. Lots of boilerplate code • Enter Dependency Injection Containers, or DiC – ZendDi is one of them, so is the Symfony DiC, and a number of others20 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location DiC – ZendDiDi() <?php $config = array( instance => array( Author => array( parameters => array( gateway => DbGateway, cache => Cache, log => Log ) ), DbGateway => array( parameters => array( db => DbAdapter, ) ), DbAdapter => array( parameters => array( host => somehost, user => someuser, pass => somepass, db => ‘somedb ) ), Cache => array( ), Log => array( ) ) ); $di = new ZendDiDi(); $di->configure(new ZendDiConfiguration($config)); $author = $di->get(Author);21 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location DiC – ZendDiDi() • The last line on the previous slide: $author = $di->get(Author); Returns a fully configured Author object, following the definition we provided • DiC does instantiation and auto-wiring • ZendDi, although difficult to show here, is a complex solution for complex problems – it can easily be abused • For simpler problems, and more in line with the PHP philosophy, ServiceManager replaced it22 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location Location v/s Injection • Service manager is a ServiceLocator !== DiC • BUT DiC === Service Locator • One main difference is that the subject requiring the dependencies is:  Not aware of the DiC when using DI (the dependency is injected)  Is aware of the locator in the case of SL, and asks the locator to obtain the dependency • ServiceManager is a service locator Think back to index.php: $serviceManager->get(ModuleManager)->loadModules(); • Martin Fowler is the subject matter expert on this: http://martinfowler.com/articles/injection.html23 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location ZendServiceManagerServiceManager() • Service manager uses factories to generate its services • Factory can be a class implementing ZendServiceManagerFactoryInterface or a php closure24 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location ZendServiceManagerServiceManager() <?php class ServiceConfiguration extends Configuration { public function configureServiceManager(ServiceManager $serviceManager) { $serviceManager->setFactory(author, function(ServiceManager $sm) { $dbGateway = $sm->get(db_gateway); $cache = $sm->get(cache); $log = $sm->get(log); return new Author($dbGateway, $cache, $log); } ); $serviceManager->setShared(author, false); $serviceManager->setFactory(db_gateway, function(ServiceManager $sm){ $dbAdapter = $sm->get(db_adapter); return new DbGateway($dbAdapter); } ); $serviceManager->setFactory(db_adapter, function(ServiceManager $sm) { //Using hard-coded values for the example, but normally you would either create a factory //and inject the values from a config file //or get the configuration from the ServiceManager and read the valuees in return new DbAdapter(somehost, someuser, somepass, somedb); } ); $serviceManager->setFactory(cache, function(ServiceManager $sm) { return new Cache(); } ); $serviceManager->setFactory(log, function(ServiceManager $sm) { return new Log(); } ); } } $config = new ServiceConfiguration(); $sm = new ServiceManager(); $config->configureServiceManager($sm); $author = $sm->get(author);25 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location ZendServiceManagerServiceManager() • The example above purposely uses closures to illustrate that a full-fledged factory is not needed • But in a lot of cases, implementing a factory makes sense - rewriting DbAdapter from the above example as a factory: <?php use ZendServiceManagerFactoryInterface; //The factory class class AuthorFactory implements FactoryInterface { public function createService(ZendServiceManagerServiceLocatorInterface $sl) { $dbGateway = $sl->get(db_gateway); $cache = $sl->get(cache); $log = $sl->get(log); return new Author($dbGateway, $cache, $log); } } //And the configuration class class ServiceConfiguration extends Configuration { public function configureServiceManager(ServiceManager $serviceManager) { //... $serviceManager->setFactory(author, AuthorFactory); //... } }26 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location ZendServiceManagerServiceManager() • The example above purposely uses closures to illustrate that a full-fledged factory is not needed • But in a lot of cases, implementing a factory makes sense - rewriting DbAdapter form the above example as a factory: <?php use ZendServiceManagerFactoryInterface; //The factory class class AuthorFactory implements FactoryInterface { public function createService(ZendServiceManagerServiceLocatorInterface $sl) { $dbGateway = $sl->get(db_gateway); $cache = $sl->get(cache); $log = $sl->get(log); return new Author($dbGateway, $cache, $log); } } //And the configuration class class ServiceConfiguration extends Configuration { public function configureServiceManager(ServiceManager $serviceManager) { //... $serviceManager->setFactory(author, AuthorFactory); //... } }27 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location Setting and retrieving the locator • In most MVC components (e.g.Controllers) the ServiceManager component is composed automatically by the MVC stack • The interface ZendServiceManagerServiceLocatorAwareInterface can be implemented to ensure that a service locator is composed in the subject class • Two methods, SetServiceLocator(ServiceLocatorInterface $locator) and getServiceLocator() must be implemented • Notice that the Component is ServiceManager(), but the interface is ServiceLocatorInterface. This is to allow you to provide an alternative implementation of service locator.28 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Location, location, location Setting and retrieving the locator • Controllers implement ServiceLocatorAwareInterface therefore <?php namespace MymodController; use ZendMvcControllerActionController, ZendViewModelViewModel; class IndexController extends ActionController { public function indexAction() { $sl = $this->getServiceLocator(); $sl->get(author); return new ViewModel(); } }29 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Locating the injector or injecting the locator? • Although ServiceManager is now the goto dependency management component in ZF2, Di actually still exists as a fallback (by default) • One can specify a collection AbstractFactories to ServiceManager on which it will fall back if it does not find the target class • Therefore, ZendServiceManagerDiDiAbstractFactory is an abstract factory to which the name of the object is passed if it is not found by ServiceManager (the order can be changed) • You can also, of course, provide your own service factory (Proxy class to other frameworks maybe?)30 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • Some references • ZF2 module site: http://modules.zendframework.com/ • Rob Allen’s Skeleton: https://github.com/zendframework/ZendSkeletonApplication • Matthew’s discussion on Modules: http://mwop.net/blog/267-Getting- started-writing-ZF2-modules.html • Ralph on the decisions that drove to ServiceManager: http://zend- framework-community.634137.n4.nabble.com/Services-Instances- Dependencies-in-ZF2-td4584632.html • SOLID OO design: http://en.wikipedia.org/wiki/SOLID_(object- oriented_design)31 Zend Professional Services © All rights reserved. Zend Technologies, Inc.
    • • Download ZF2 and happy coding! http://zendframework.com/zf2 Thank You! http://twitter.com/mkherlakian32 Zend Professional Services © All rights reserved. Zend Technologies, Inc.