into the zf2 service manager
TRANSCRIPT
![Page 1: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/1.jpg)
Into the ZF2 Service Manager Chris Tankersley ZendCon 2015
ZendCon 2015 1
![Page 2: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/2.jpg)
Who Am I
• PHP Programmer for over 10 years • Been using ZF since ~0.5 • Daily ZF2 user • hBps://github.com/dragonmantank
ZendCon 2015 2
![Page 3: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/3.jpg)
A running joke…
• “Symfony2 is a PHP script that turns YAML into applicaNons” • “Yeah, but Zend Framework 2 is a PHP script that turns arrays into applicaNons”
ZendCon 2015 3
![Page 4: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/4.jpg)
ZendCon 2015 4
![Page 5: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/5.jpg)
It kind of is…
ZendCon 2015 5
return [ 'service_manager' => [ 'initializers' => [ 'Job\Service\JobServiceAwareInitializer' ], 'invokables' => [ 'Job\ProcessorListener' => 'Job\Processor\ProcessorListener', 'Job\ServiceAccountListener' => 'Job\Service\JobServiceListener’ ], 'factories' => [ 'Job\Service' => 'Job\Service\JobServiceFactory', 'Job\Processor' => 'Job\Processor\ProcessorFactory', ] ] ]
![Page 6: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/6.jpg)
Theater Magic
• When something awesome happens, but it’s really something mundane controlling it in the background • When it looks good from 25’
ZendCon 2015 6
![Page 7: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/7.jpg)
The Service Manager
ZendCon 2015 7
![Page 8: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/8.jpg)
Service Locator
• Container for storing objects or condiNons for building an object • Mostly it’s used to create objects • It does not do automaNc dependency injecNon • It is not global (unless you make it global)
ZendCon 2015 8
![Page 9: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/9.jpg)
What can we store in there?
• Invokables • Factories • Abstract Factories • Delegators • IniNalizers • Aliases
ZendCon 2015 9
![Page 10: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/10.jpg)
Standalone
$serviceManager = new Zend\ServiceManager\ServiceManager(); $serviceManager-‐>setService(‘MyService’, $myService); $serviceManager-‐>has(‘MyService’); $service = $serviceManager-‐>get(‘MyService’);
ZendCon 2015 10
![Page 11: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/11.jpg)
Built into ZF2 full-stack applications
• Anything that is ServiceLocatorAwareInterface can have it injected • Controllers are the most common
ZendCon 2015 11
namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; class IndexController extends AbstractActionController { public function indexAction() { $model = $this-‐>getServiceLocator()-‐>get(‘My\Model’); } }
![Page 12: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/12.jpg)
Stuff we can get from the Service Manager
ZendCon 2015 12
![Page 13: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/13.jpg)
Invokables
• Any sort of object that can be declared with ‘new’ and has no constructor parameters
ZendCon 2015 13
class MyClass { public function foo() { ... } public function bar() { ... } } class SimpleConstructor { protected $name; public function __construct() { $this-‐>name = 'baz'; } }
![Page 14: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/14.jpg)
In ZF2 return [
'service_manager' => [ 'invokables' => [ 'Job\Processor\ProcessorListener' => 'Job\Processor\ProcessorListener', 'Job\ServiceAccountListener' => 'Job\Service\JobServiceListener' ],
]
]
ZendCon 2015 14
![Page 15: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/15.jpg)
Quick Dependency Injection Tutorial
ZendCon 2015 15
![Page 16: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/16.jpg)
What is Dependency Injection?
• InjecNng dependencies into classes, instead of having the class create it • Allows for much easier tesNng • Allows for a much easier Nme swapping out code • Reduces the coupling that happens between classes
php[tek] 2015 16
![Page 17: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/17.jpg)
Method Injection class MapService { public function getLatLong(GoogleMaps $map, $street, $city, $state) {
return $map-‐>getLatLong($street . ' ' . $city . ' ' . $state); }
public function getAddress(GoogleMaps $map, $lat, $long) { return $map-‐>getAddress($lat, $long);
} }
php[tek] 2015 17
![Page 18: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/18.jpg)
Constructor Injection class MapService { protected $map; public function __construct(GoogleMaps $map) { $this-‐>map = $map; } public function getLatLong($street, $city, $state) { return $this -‐>map -‐>getLatLong($street . ' ' . $city . ' ' . $state); } }
php[tek] 2015 18
![Page 19: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/19.jpg)
Setter Injection class MapService { protected $map; public function setMap(GoogleMaps $map) { $this-‐>map = $map; } public function getMap() { return $this-‐>map; } public function getLatLong($street, $city, $state) { return $this-‐>getMap()-‐>getLatLong($street . ' ' . $city . ' ' . $state); } }
php[tek] 2015 19
![Page 20: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/20.jpg)
Back to the show
ZendCon 2015 20
![Page 21: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/21.jpg)
Factories
• A Factory is an object/method is that is used to create other objects • ZF2 Service Manager will call the factory when an object is pulled out of the Service Manager
ZendCon 2015 21
![Page 22: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/22.jpg)
Why do we need factories?
Dependencies
ZendCon 2015 22
![Page 23: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/23.jpg)
In ZF2
ZendCon 2015 23
return [ 'service_manager' => [ ’factories' => [ 'Google\AdWords\AdWordsUserBuilder' => 'Google\AdWords\GoogleAdWordsUserBuilderFactory', ], ] ]
![Page 24: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/24.jpg)
ZendCon 2015 24
namespace Google\AdWords; class GoogleAdWordsUserBuilder { public function __construct(array $config) { $this-‐>config = $config; } }
![Page 25: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/25.jpg)
ZendCon 2015 25
namespace Google\AdWords; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class GoogleAdWordsUserBuilderFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $service) { $config = $service-‐>get('Config'); return new GoogleAdWordsUserBuilder($config[‘google’]); } }
![Page 26: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/26.jpg)
Abstract Factories
• They are factories, but they allow the creaNon of a broad range of objects instead of a single object • The factory will take addiNonal configuraNon to properly create the needed object
ZendCon 2015 26
![Page 27: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/27.jpg)
ZendCon 2015 27
<?php namespace MyProject; use Zend\Db\TableGateway\TableGateway; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class ProjectsTableFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $adapter = new $serviceLocator-‐>get('Zend\Db\Adapter\Adapter'); return new TableGateway('projects', $adapter); } } class CategoriesTableFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $adapter = new $serviceLocator-‐>get('Zend\Db\Adapter\Adapter'); return new TableGateway('categories', $adapter); } }
![Page 28: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/28.jpg)
In ZF2
ZendCon 2015 28
return [ ’abstract_factories' => [ ’MyProject\TableAbstractFactory’ ] ]
![Page 29: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/29.jpg)
ZendCon 2015 29
<?php namespace MyProject; use Zend\Db\TableGateway\TableGateway; use Zend\ServiceManager\AbstractFactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class TableAbstractFactory implements AbstractFactoryInterface { public function canCreateServiceWithName(ServiceLocatorInterface $sl, $name, $requestedName) { return preg_match("/Table$/", $requestedName); } public function createServiceWithName(ServiceLocatorInterface $sl, $name, $requestedName) { $adapter = $sl-‐>get('Zend\Db\Adapter\Adapter'); $tableName = str_replace('Table', '', $requestedName); $tableName = strtolower($tableName); return new TableGateway($tableName, $adapter); } }
![Page 30: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/30.jpg)
Initializers
• Code that needs to run ajer an object is created • Really helpful for when lots of objects need addiNonal objects (like loggers) all across the applicaNon
ZendCon 2015 30
![Page 31: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/31.jpg)
In ZF2
ZendCon 2015 31
return [ ’initalizers' => [ ’Job\Service\JobServiceAwareInitializer’ ] ]
![Page 32: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/32.jpg)
ZendCon 2015 32
<?php namespace Job\Service; use Zend\ServiceManager\InitializerInterface; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorInterface; class JobServiceAwareInitializer implements InitializerInterface { public function initialize($instance, ServiceLocatorInterface $serviceLocator) { if (!$instance instanceof JobServiceAwareInterface) { return null; } /** @var \Job\Service\JobService $jobService */ $jobService = $serviceLocator-‐>get('Job\Service'); $instance-‐>setJobService($jobService); } }
![Page 33: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/33.jpg)
Delegators
• They are actually decorators for objects that don’t exist • They are like iniNalizers that only run on a specific key • Allow your applicaNon to tweak or modify 3rd party objects without having to extend them
ZendCon 2015 33
![Page 34: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/34.jpg)
In ZF2
ZendCon 2015 34
return [ ’delgators' => [ ’OtherVendor\Account\AccountService’ => [ ‘MyProject\Account\AccountServiceDelegator’, ] ] ]
![Page 35: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/35.jpg)
ZendCon 2015 35
<?php namespace MyProject; use Zend\ServiceManager\DelegatorFactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class AccountServiceDelegator implements DelegatorFactoryInterface { public function createDelegatorWithName(ServiceLocatorInterface $sl, $name, $requestedName, $callback) { $originalService = $callback(); $accountService = new MyProject\Account\AccountService($originalService); return $accountService; } }
![Page 36: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/36.jpg)
Aliases
• Just another name for some other key in the service manager
ZendCon 2015 36
![Page 37: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/37.jpg)
In ZF2
ZendCon 2015 37
return [ ’aliases' => [ ’MyProject\Account\OldAccountService’ => ‘MyProject\Account\NewAccountService’, ] ]
![Page 38: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/38.jpg)
Bad Practices
ZendCon 2015 38
![Page 39: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/39.jpg)
Lots of Initializers
• IniNalizers run ajer every object is created • 30 iniNalizers * 50 objects created at runNme = 1500 invocaNons
• Look at using Factories instead to inject things into your objects • Look at using Delegators
ZendCon 2015 39
![Page 40: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/40.jpg)
Functions as Factories
• The Factory system will actually take any invokable thing as a factory • That means you can use closures and anonymous classes
ZendCon 2015 40
![Page 41: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/41.jpg)
ZendCon 2015 41
return [ 'factories' => array( 'CategoryService' => function($sm) { $categoryService = new CategoryService(); $categoryService-‐>setCategoryTable($sm-‐>get('CategoryTable')); return $categoryService; }, 'CategoryTable' => function($sm) { $tableGateway = $sm-‐>get('CategoryTableGateway'); $table = new CategoryTable($tableGateway); return $table; }, 'CategoryTableGateway' => function($sm) { $dbAdapter = $sm-‐>get('Zend\Db\Adapter\Adapter'); $resultSetPrototype = new ResultSet(); $resultSetPrototype-‐>setArrayObjectPrototype(new Category()); return new TableGateway('category', $dbAdapter, null, $resultSetPrototype); }, ]
![Page 42: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/42.jpg)
Functions as Factories
• This makes the config uncachable, so there are performance issues
ZendCon 2015 42
![Page 43: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/43.jpg)
Questions?
ZendCon 2015 43
![Page 44: Into the ZF2 Service Manager](https://reader034.vdocuments.mx/reader034/viewer/2022050614/58aa7d171a28abbc1e8b6fe7/html5/thumbnails/44.jpg)
Thank You!
hBp://ctankersley.com [email protected]
@dragonmantank
hBp://joind.in/talk/view/15534
ZendCon 2015 44