Question

My app uses the data mapper pattern, so I have a number of mapper classes, which each needs an instance of the database adapter. So the factories section of my service config is filled with entries like this:

'UserMapper' => function($sm) {
    $mapper = new UserMapper();
    $adapter = $sm->get('Zend\Db\Adapter\Adapter');
    $mapper->setAdapter($adapter);

    return $mapper;
},
'GroupMapper' => function($sm) {
    $mapper = new GroupMapper();
    $adapter = $sm->get('Zend\Db\Adapter\Adapter');
    $mapper->setAdapter($adapter);

    return $mapper;
},

I would like to remove some of this boiler plate code. Is it possible for me to define a custom service locator class just for these mappers, which could instantiate any mapper class by suppliyng the DB adapter, unless a definition exists with some custom factory configuration?

Was it helpful?

Solution

There are two ways to approach this.

The first is to have your mappers implement the Zend\Db\Adapter\AdapterAwareInterface, and add an initializer to the service manager which would inject the adapter into any services implementing the interface. If you do that, all your mappers could be placed in the invokables key of service config instead of needing a factory for each.

Your mappers would then all look similar to this

<?php
namespace Foo\Mapper;

use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
// if you're using php5.4 you can also make use of the trait
// use Zend\Db\Adapter\AdapterAwareTrait;

class BarMapper implements AdapterAwareInterface;
{
    // use AdapterAwareTrait;

    // ..
    /**
     * @var Adapter
     */
    protected $adapter = null;

    /**
     * Set db adapter
     *
     * @param Adapter $adapter
     * @return mixed
     */
    public function setDbAdapter(Adapter $adapter)
    {
        $this->adapter = $adapter;

        return $this;
    }

}

In your service manager config, place your mappers under invokables, and add an initializer for AdapterAware services

return array(
   'invokables' => array(
       // ..
       'Foo/Mapper/Bar' => 'Foo/Mapper/BarMapper',
       // ..
    ),
    'initializers' => array(
        'Zend\Db\Adapter' => function($instance, $sm) {
            if ($instance instanceof \Zend\Db\Adapter\AdapterAwareInterface) {
                $instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
            }
        },
    ),
);

The alternative method is to create a MapperAbstractServiceFactory, and this answer -> ZF2 depency injection in parent describes how you might do that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top