Zend Framework 2 - Applications / Modules / Service Managers - Oh My

I just started to learn Zend Framework 2 as a developer of Zend Framework 1 for a long time. I have small problems that surround new terminology.

Back in ZF1, if I wanted to create a registrar that was global for the application, I would add the configuration to the application.ini file and bootstrap would initialize it as a resource (I hope I say that correctly). So, from any of my controller modules, I could access the registrar through bootstrap resources.

Enter ZF2, the modules are a slightly different beast, they are self-sufficient, but I'm a little confused about how they interact with the application. It seems to me that this is where the ServiceManager starts. My goal is for my module (not the controller, but the module itself) to check if the application has defined the logger, and if it is, use this logger in the whole module. If the application does not determine the logger, I want the module to determine the logger for logging throughout the module.

This question also applies to databases, say, I want the application to determine the logic for connecting to the database, while I want the module to determine the logic for the required tables. How exactly will I configure this and how / where can I find out if there is a database resource defined in the application.

Note. I went through Rob Allen Quickstart (fairly detailed information and the only resource I found that does not have a dark shadow), and ZF2 (readthedocs), and already on Google. What I find is that the information is usually very obscure when it comes to where some parts of the puzzle are located.

+6
source share
2 answers

What you know from Zend Framework 1.x is the "Application Resource".

The concept of an "application resource" is replaced in Zend Framework 2 with the so-called "services" (intro here )

Another change is the modules themselves. In ZF1, the module was mainly a unit of your application that handled some requests. This no longer applies to ZF2: if your module defines a service or controller, this access is now available for the entire application. There is a nice introduction to some of the differences between ZF1 and ZF2 from Gary Hockin .

But in any case, the modules are NOT self-sufficient. They should be developed in an isolated environment and with minimal dependencies, but they provide complex features that affect your entire application.

In your particular case of the registrar, I suggest that your module always determines the registrar and consumes it. What can be done to determine the registrar conditionally:

class MyModule { public function onBootstrap($e) { // $e->getTarget() is the \Zend\Mvc\Application $sm = $e->getTarget()->getServiceManager(); if (!$sm->has('some-logger-name')) { $sm->setFactory('some-logger-name', function ($sl) { return new MyLogger($sl->get('some-db')); }); } } } 

Then you can use your "registrar name" throughout your application.

Another approach is to simply define the registration services, and override other modules or configurations later:

 class MyModule { public function getConfig() { return array( 'service_manager' => array( 'factories' => array( 'some-logger-name' => 'My\Logger\Factory\ClassName' ), ), ); } } 

The same is achieved with getServiceConfig , which is less flexible and cannot be cached, but has a higher priority than getConfig (allows overrides) and also allows you to define service plants as closures:

 class MyModule { public function getServiceConfig() { return array( 'factories' => array( 'some-logger-name' => function ($sl) { return new MyLogger($sl->get('some-db')); }, ), ); } } 

You can then determine the configuration key that should be used to determine which registrar (service name) to use.

The concept with modules and configurations is that the "last module wins", so you can define the 'some-logger-name' either in your module or in any module loaded before it.

The same concepts apply also to your database connection.

As you can see, the transition to services has already given you a certain degree of freedom.

Keep in mind that this is not that the “Application” defines something for you: the modules define your services / configs / events, etc. A launching application is a combination of all these things.

+6
source

I think, especially in the case of registration, there is perhaps even a better, of course, more encapsulated way than using the ServiceManager . ZF2 is essentially an event-driven platform and functionality that allows us to use this event-driven architecture to our advantage. A perfect example for this. Instead of defining a factory, you should attach a registration event that can be fired from anywhere in the application.

Attach a log event listener to Module.php :

 public function onBootstrap(MvcEvent $e) { //setup some $logger $sharedManager = $e->getApplication()->getEventManager()->getSharedManager(); $sharedManager->attach('*', 'log', function($e) use ($logger) { /** @var $e MvcEvent */ $target = get_class($e->getTarget()); $message = $e->getParam('message', 'No message provided'); $priority = $e->getParam('priority', Logger::INFO); $message = sprintf('%s: %s', $target, $message); $logger->log($priority, $message); }); } 

Then run it from anywhere in the application, for example, the controller:

 $this->getEventManager()->trigger('log', $this, array( 'priority' => \Zend\Log\Logger::INFO, 'message' => 'just some info to be logged' )); 
+3
source

All Articles