ZF2 get service from service manager with addition

2019-07-07 00:11发布

I have two examples where I would like to use the service manager to get a service and have it resolve the dependencies through configs, apart from one dependency/parameter which is variable (pseudo code because I realise 'get' only allows one argument):

in controller, to get an entity from a database:

$sm = $this->getServiceLocator();
$myObject = $sm->get('Model', $id);

in mapper (the service manager should get the corresponding adapter):

$sm = $this->getServiceLocator();
$tableGateway = $sm->get('TableGateway', $table);

What would be best practice to achieve this?

2条回答
干净又极端
2楼-- · 2019-07-07 00:39

To my knowledge this is not directly possible, but I read somewhere that intializer are meant for this type of scenario.

initializer can be any class which implement InitializerInterface, which has a method initialize(), the initialize() method is called with the object (Ex.instance of Model) and the service manager instance, you need to write condition for each of your object that need to be initialized. after building the initializer class you need to include entries in the service manager configuration(module.config.php) or getServiceConfig() method

Though not fully cover your question but may be helpful to move in the right direction

Edit

What would be best practice to achieve this?

To answer this

If your object has no dependencies you can achevie this as

$myObject = new Model();
$myObject->find($id); which would initialize the model

if your model has dependencies and also if you need to replace Model with some other object later in the stage of development you can isolate the object creation process with service factory configuration of the servicelocator, to achieve this define the service inside getServicConfig() method in Module.php (you can also define your own factory code and refer it in the configuration but in most use case simple factory definition suffice)

public function getServiceConfig(){
    return array(
        'factories' => array(
            'Model' =>  function(ServiceLocatorInterface $sm) {
                return new Model($dependency1, $dependency2...);
            },
        ),
    );
}

Then model access code will be

$myObject = $this->serviceLocator()->get('Model');
$myObject->find($id); which would initialize the model

the best practice would be define an interface which include find($id) and all other method that need to be called and implement this interface in the Model class, this way you can replace your factory code with any other object that implement the interface and you don't need to touch your usage code of the Model object.

For the use case two I assume you try to reuse or reduce repeat of code. If you have finite set of combination you can achieve it like below

define the service factory like this

public function getServiceConfig(){
    return array(
        'factories' => array(
            'Model/table1' =>  function(ServiceLocatorInterface $sm) {
                return new TableGateway('table1', $sm->get('db'));
            },
            'Model/table2' =>  function(ServiceLocatorInterface $sm) {
                return new TableGateway('table2', $sm->get('db'));
            },
        .
        .
        .
        .
        ),
    );
}    

access table1 as

$tableGateway = $this->serviceLocator()->get('Model/table1');

Note: 'Model/table1' is to namespace and avoid overwrite of config, internally '/' will be removed by service manager, and the names will be made lowercase, on both registration and get.

The Zend\ServiceManager\ServiceManager stores what it calls canonicalNames in a protected property. This is an array of namespaces mapped to the cannonical names, which are the namespace with the slashes stripped and made lowercase.

查看更多
时光不老,我们不散
3楼-- · 2019-07-07 00:57

What you're describing is not really the use-case that the ServiceManager was designed for. Like it says on the tin, it's a system to manage services. Using it to grab individual entities isn't really appropriate. Instead, use the servicemanager to grab a repository, and use that repository to grab an entity:

$entity = $this->getServiceLocator()->get('FooRepository')->find($id);

In your second example, it seems like you've got some kind of Factory that creates TableGateways. A sensible approach would be:

$gateway = $this->getServiceLocator()->get('TableGatewayFactory')->get($table);

Or, you could define individual services for each gateway:

$gateway = $this->getServiceLocator()->get('FooTableGateway');
查看更多
登录 后发表回答