How can I use getServiceLocator() to get an adapter in a Model?

916 Views Asked by At

I am learning ZF2.

Can I use getServiceLocator() to get a adapter in a Model?

/config/autoload/global.php

return array(
    'db' => array(
        'driver'         => 'Pdo',
        'dsn'            => 'mysql:dbname=zf2tutorial;host=localhost',
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),
    ),
    'service_manager' => array(
        'factories' => array(
            'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
        ),
        'aliases' => array(
            'db' => 'Zend\Db\Adapter\Adapter',
        ),
    ),
);

/config/autoload/local.php

return array(
    'db' => array(
        'username' => 'YOUR USERNAME HERE',
        'password' => 'YOUR PASSWORD HERE',
    ),
);

So, how can I use:

$sm = $this->getServiceLocator();
$this->dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');

to get a adapter in a Model?

2

There are 2 best solutions below

0
On

You will need to inject the adapter into your model when it's created, for example using a factory.

for example in your config:

'service_manager' => array(
    'factories' => array( 
        'Application\Some\Model' => '\Application\Some\ModelFactory'
     )
)

You would then create the factory which will inject the adapter into your model:

<?php
namespace Application\Some;

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

class ModelFactory implements FactoryInterface
{
   /**
     * Create service
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return mixed
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
         $adapter = $serviceLocator->get('Zend\Db\Adapter\Adapter');

         return new Model($adapter);
    }
}

You would then obviously need to make your model accept the adapter in it's constructor in this case.

Now where ever you need to get an instance of your model with the adapter injected you'd call:

$serviceLocator->get('Application\Some\Model');

This will call the factory and bring back the model complete with adapter.

You would then use the same kind of approach to inject your model into any controllers or service classes where it's needed. As said in a previous post try and avoid injecting the service locator/Service manager directly into your objects, but rather use it to add the items you need (adapters/mappers etc) from inside Factory classes etc.

0
On

If you are using the latest Zend Framework version you cannot use the getServiceLocator method in your controller classes since both the ServiceLocatorAwareInterface and the ServiceManagerAwareInterface were removed.

So this line:

$sm = $this->getServiceLocator();

Won't work as you maybe expected in your controller class.


You can also read more on this change in the migration guide:

The following interfaces, traits, and classes were removed:

  • ...
  • Zend\ServiceManager\ServiceLocatorAwareInterface
  • Zend\ServiceManager\ServiceLocatorAwareTrait
  • Zend\ServiceManager\ServiceManagerAwareInterface

The ServiceLocatorAware and ServiceManagerAware interfaces and traits were too often abused under v2, and represent the antithesis of the purpose of the Service Manager component; dependencies should be directly injected, and the container should never be composed by objects.

You will need to refactor your service and probably the best way to do that is to create a service factory where you inject your dependencies.

Check also this blog post (chapter Factories) on more details on how to build a factory.