Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternatives to Zend Registry for ZF2

I have just started using ZF2 and am really enjoying it.

One thing that puzzles me a bit is the absence of a Registry component. I realise that the Service Manager makes the Registry obsolete in most cases. I rely on it heavily and its great.

But from time to time I find myself needing access to a 'global' object, and I don't have access to the Service Manager. For example, in my Domain\User object I need access to a Zend\Log.

I don't want to make the Service Manager available in my Domain objects, since they are beautiful and pristine, and unadulterated by such considerations. I could 'new' a log instance whenever required, but I do it so often I'd rather have a preconfigured instance to hand. I could wrap it in a singleton, but that seems like a backward step. I could create my own mini-registry, but if that was a good idea, I'm sure the Zend guys would have left such a component in place.

So, what other options are there?

EDIT:

So, could I use Zend DI perhaps? I see this question partially covers it, Configuring class alias for using with Zend\Di\Di

like image 894
DatsunBing Avatar asked Oct 20 '22 19:10

DatsunBing


1 Answers

You are exactly addressing the problem of dependency injection. I have blogged about this topic before, how to refactor towards dependency injection and what to do if you have soft dependencies like a Logger.

The idea is you inject the pre-configured logger. When your Domain\User object is created, the logger is injected. This makes the Domain\User object only dependent on the logger without having the knowledge how to create the logger. It's even better if you rely on a Logger interface, so you can swap to any logger implementation you want.

Example

As an example, I assume you are using Zend\Log. You have a Logger like Zend\Log\Logger with various writers attached. The logger implements Zend\Log\LoggerInterface.

Your Domain\User class:

namespace Domain;

Zend\Log\LoggerInterface;

class User
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function doSomething()
    {
        $this->logger->info('Do Something');

        //
    }
}

For Zend Framework, you should work with factories to inject this logger into your objects. The best way is to define the Logger as a service first, as you could reuse the logger for other objects as well.

Note I use the Service Manager and not Zend\Di here. Zend\Di is obsolete and replaced by the faster and more flexible Zend\ServiceManager. Both can achieve dependency injection.

The factory for you logger:

namespace MyModule\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

use Zend\Log\Logger;

class LoggerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $logger = new Logger;
        // do more with $logger here

        return $logger;
    }
}

Then register this factory to create the service "logger" for you. In your module.config.php:

'service_manager' => array(
    'factories' => array(
        'logger' => 'MyModule\Factory\LoggerFactory',
    ),
),

Now logger is available in your service manger. For your domain model, do the same. Create a factory first:

namespace MyModule\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

use Domain\User;

class UserFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $logger = $serviceLocator->get('logger');

        $user = new User($logger);
        return $user;
    }
}

Then register this one too:

'service_manager' => array(
    'factories' => array(
        'logger' => 'MyModule\Factory\LoggerFactory',
        'Domain\User' => 'MyModule\Factory\UserFactory',
    ),
),

If you have access to the service locator, you can get the Domain\User and the logger is automatically injected:

$user = $sl->get('Domain\User');
like image 106
Jurian Sluiman Avatar answered Oct 27 '22 11:10

Jurian Sluiman