Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

zf2: how to get service manager in mapper

In Zend Framework 1 I had several mappers which inherited a setDbTable and getDbTable from a parent Mapper class.

Now in ZF2 a face the problem that I need the service manager in a model and I do not have a clue as how to get it:

    class Mapper
    {
        protected $tableGateway;
        protected $module = 'application';

        public function setTableGateway($table)
            {
                if (is_string($table)) {
                    $class = $this->module . '\Model\DbTable\\' . ucfirst($table);
                    $sm = $this->getServiceLocator(); <= Fatal error: Call to undefined method Mapper::getServiceLocator()
                    $tableGateway = (class_exists($class)) ? $sm->get($class) : $sm->get(new TableGateway($table));
                } else {
                    $tableGateway = $table;
                }

                if (!$tableGateway instanceof Zend\Db\TableGateway\AbstractTableGateway) {
                    throw new \Exception('Invalid table data gateway provided');
                }
                $this->tableGateway = $tableGateway;
                return $this;
            }

        // more code

The line:

$sm = $this->getServiceLocator();

gives a fatal error:

Call to undefined method Application\Model\Mapper\Doc::getServiceLocator()

How would I get the service manager in my model? Or am I not doing things the ZF2 way? I know how to get the service manager in my controller and pass the tableGateway to the mapper but that seems like a lot of duplication of code to me.

like image 704
tihe Avatar asked Dec 24 '12 13:12

tihe


People also ask

What is a service map agent?

Service Map agents gather information about all TCP-connected processes on the server where they're installed and details about the inbound and outbound connections for each process. From the list in the left pane, you can select machines or groups that have Service Map agents to visualize their dependencies over a specified time range.

How do I use the command line interface for SAP service manager?

Use the SAP BTP command line interface for SAP Service Manager to perform various operations related to your service instances. Commands Task Run the command ... Link List all service instances associ­ ated with the current subac­ count.

How to configure SAP service manager in SAP BTP?

Using the SAP BTP cockpit or Service Manager Control (SMCTL) command-line interface, create an instance of the SAP Service Manager (technical name: service-manager) with the plan: service- operator-access. Note If you can't see the needed plan, you need to entitle your subaccount to use SAP Service Manager.

How does service map integrate with the IT service management connector?

Service Map integration with the IT Service Management Connector is automatic when both solutions are enabled and configured in your Log Analytics workspace. The integration in Service Map is labeled "Service Desk." For more information, see Centrally manage ITSM work items using IT Service Management Connector.


2 Answers

First of all, I think you mean that you want to access the service manager from a mapper class and not a model. I would refrain from doing the latter. Please see my comment to Raj's answer for more details.

Secondly, there are many ways to go about this. In this answer, I will give you an example of one approach and merely mention another.

Looking at the service manager's documentation (scroll a bit down), it states that a default initializer is added as default. This initializer checks to see if an object that is being retrieved from the service manager implements Zend\ServiceManager\ServiceLocatorAwareInterface. If it does, the service manager is injected into the object. Thus, this can happen automatically if you simply implement the interface in your mapper classes. You could use an abstract base class to avoid rewriting this for every mapper class. Perhaps something like the below.

Base mapper class:

namespace User\Mapper;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AbstractMapper implements ServiceLocatorAwareInterface {
    protected $service_manager;

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->service_manager = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->service_manager;
    }
}

Mapper class:

namespace User\Mapper;

use User\Mapper\AbstractMapper;

class UserMapper extends AbstractMapper {
    public function doSomething() {
        $sm = $this->getServiceLocator();
        $sm->get('something');
    }
}

Since the service manager is injected when the initializer is run, the mapper should be retrieved from the service manager. If you do not want/have to inject anything into your mapper class, then an invokable can suffice. They can be added under the invokables key, which is nested under the service_manager key in module_name/config/module.config.php. Or, it can be configured in the module class' getServiceConfig method. However, your mapper classes will most likely have some dependencies now or in the future, so you will probably want to use a factory instead. This way, you could for instance have the service manager inject a table gateway into the mapper classes.

// Remember to include the appropriate namespaces
return array(
    'factories' => array(
        'User\Mapper\UserMapper' => function($service_manager) {
            $table_gateway = $service_manager->get('User\Model\DbTable\UserGateway');
            return new UserMapper($table_gateway);
        },
    ),
);

The above can be added in a getServiceConfig method within the module's Module.php file - or add the factories key within the service_manager key in module_name/config/module.config.php. You will still have to add a factory that creates the database gateway; the above is just an example.

This is how I would go about it. Of course one could simply have a getter and setter method for the service manager in the mapper class and access these from the controller (the controller has a getServiceLocator method) and inject it like that. I would not go with that approach myself, though.

like image 106
ba0708 Avatar answered Oct 28 '22 14:10

ba0708


Note: As Jurian Sluiman and andy124 pointed out in their comments, never inject service manger and depend on service manager inside your domain specific model/object, which is not a good practice as this will make your domain specific object rigid and impact on portability. The solution below is more specific to the question asked

I follow the below steps to get sevicelocator(service manager) in my class, models, etc
1. create class which implement ServiceMangerAwareInterface
2. Define the entry in serviceconfig in your Module.php like this

    public function getServiceConfig(){
    return array(
        'factories' => array(
                    /* Models */
            'MyModule\MyModel' =>  function($sm) {
                return new Models\MyModel($sm);
            },
                    /* Entities */
            'MyModule\MyEntity1' =>  function($sm) {
                return new Entity\MyEntity1($sm);
            },
            'MyModule\MyEntity2' =>  function($sm) {
                return new Entity\MyEntity2($sm);
            },
        .
        .
        .
        ),
    );
`
  1. Access your model or class with service manager like below (ex. under controller)
    $model = $this->getServiceLocator()->get('MyModule\MyModel');
    
You can also do the service manager configuration in module.config.php
    'service_manager' => array(
        'factories' => array(
             'MyModel' => 'MyModule\Models\MyModel',
             'MyEntity' => 'MyModule\Entity\MyEntity',
         ),
    ),
    
4. Access your model or class with service manager like below (ex. under controller)
    $model = $this->getServiceLocator()->get('MyModel');
    
like image 22
Raj Avatar answered Oct 28 '22 14:10

Raj