1

In my module config file, I have these lines that loads libraries and models into ServiceManager so that I can retrieve them in Controllers. You can see all my models require same dependency. May I ask, how can I inject them without these repetitive blocks of code? This looks wrong to me but I do not know how an I run the same lines of code for different libraries. Or should I be using factories at all? Thank you!

'service_manager' => array(
    'abstract_factories' => array(
        'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
        'Zend\Log\LoggerAbstractServiceFactory',
    ),
    'aliases' => array(
        'translator' => 'MvcTranslator',
    ),
    'factories' => array(
        // Models
        'Application\Model\Photo' => function($serviceLocator) {
            $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
            $io = $serviceLocator->get('Project\IO');
            $class = new Application\Model\Photo($coreLibrary, $io);
            return $class;
        },
        'Application\Model\Album' => function($serviceLocator) {
            $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
            $io = $serviceLocator->get('Project\IO');
            $class = new Application\Model\Album($coreLibrary, $io);
            return $class;
        },
        'Application\Model\Tag' => function($serviceLocator) {
            $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
            $io = $serviceLocator->get('Project\IO');
            $class = new Application\Model\Tag($coreLibrary, $io);
            return $class;
        },
        'Application\Model\User' => function($serviceLocator) {
            $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
            $io = $serviceLocator->get('Project\IO');
            $class = new Application\Model\User($coreLibrary, $io);
            return $class;
        },
        'Application\Model\Message' => function($serviceLocator) {
            $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
            $io = $serviceLocator->get('Project\IO');
            $class = new Application\Model\Message($coreLibrary, $io);
            return $class;
        },
    ),
),
Tony
  • 425
  • 1
  • 5
  • 12

2 Answers2

2

You should consider to use AbstractFactory in this case. See the code below:

namespace Application\Model;
use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AbstractModelFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        $requestedName = explode('\\', $requestedName);

        if ((!isset($requestedName[0]) || $requestedName[0] != 'Application')
            || (!isset($requestedName[1]) || $requestedName[1] != 'Model'))
        {
            return false;
        }

        $modelName = $requestedName[2];
        return class_exists('Application\Model\\'.$modelName);
    }

    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        $requestedName = explode('\\', $requestedName);
        $modelName = $requestedName[2];

        $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
        $io = $serviceLocator->get('Project\IO');
        $class = 'Application\Model\\'.$modelName;
        return new $class($coreLibrary, $io);
    }
}

Then register your factory like so:

'service_manager' => [
    'abstract_factories' => [
        'Application\Model\AbstractModelFactory'
    ]
]
Next Developer
  • 1,249
  • 1
  • 10
  • 20
1

You could also use initializers:

public function getServiceConfig(){
    return array(
        'initializers' => array(
            function ($instance, $sm) {
                if($instance instanceof Model\CoreAndIOAwareInterface){
                    $coreLibrary = $serviceLocator->get('Project\CoreLibrary');
                    $io = $serviceLocator->get('Project\IO');
                    $instance->setCoreLibrary($coreLibrary);
                    $instance->setIO($io);
                }
            },
        )
    );
}

so then You should create interface also:

interface CoreAndIOAwareInterface
{
    public function setCoreLibrary(CoreLibrary $coreLibrary);
    public function setIO(IO $io);
}

and implements this interface in your model classes. It depends on You how to do it. In my opinion the best way is to create abstract class and then extends it with concrete class.