6

Zend Framework 1 には、親の Mapper クラスから setDbTable と getDbTable を継承するいくつかのマッパーがありました。

現在、ZF2 では、モデルにサービス マネージャーが必要であり、それを取得する方法がわからないという問題に直面しています。

    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

この線:

$sm = $this->getServiceLocator();

致命的なエラーが発生します:

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

モデルでサービス マネージャーを取得するにはどうすればよいですか? それとも、ZF2 のやり方でやっていないのでしょうか? コントローラーでサービスマネージャーを取得し、テーブルゲートウェイをマッパーに渡す方法は知っていますが、それはコードの重複が多いようです。

4

2 に答える 2

8

まず第一に、モデルではなくマッパークラスからサービスマネージャーにアクセスしたいということだと思います。後者は控えたいと思います。詳細については、Raj の回答に対する私のコメントをご覧ください。

第二に、これには多くの方法があります。この回答では、1 つのアプローチの例を示し、別のアプローチについてのみ言及します。

サービス マネージャーのドキュメント(少し下にスクロール) を見ると、デフォルトの初期化子がデフォルトとして追加されていることが示されています。このイニシャライザは、サービス マネージャから取得されているオブジェクトが を実装しているかどうかを確認しますZend\ServiceManager\ServiceLocatorAwareInterface。存在する場合は、サービス マネージャーがオブジェクトに挿入されます。したがって、マッパー クラスにインターフェイスを実装するだけで、これは自動的に発生します。抽象基本クラスを使用して、すべてのマッパー クラスでこれを書き直さないようにすることができます。下のようなものではないでしょうか。

基本マッパー クラス:

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;
    }
}

マッパークラス:

namespace User\Mapper;

use User\Mapper\AbstractMapper;

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

イニシャライザの実行時にサービス マネージャが挿入されるため、サービス マネージャからマッパーを取得する必要があります。マッパークラスに何かを注入したくない/注入する必要がない場合は、invokable で十分です。invokablesこれらは、 のキーの下にネストされているservice_managerキーの下に追加できますmodule_name/config/module.config.php。または、モジュール クラスのgetServiceConfigメソッドで構成できます。ただし、マッパー クラスには現在または将来的に何らかの依存関係が存在する可能性が高いため、代わりにファクトリを使用することをお勧めします。このようにして、たとえば、サービス マネージャーにテーブル ゲートウェイをマッパー クラスに挿入させることができます。

// 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);
        },
    ),
);

上記はgetServiceConfig、モジュールのModule.phpファイル内のメソッドに追加するか、.in のfactoriesキー内にservice_managerキーを追加できますmodule_name/config/module.config.php。データベース ゲートウェイを作成するファクトリを追加する必要があります。上記はほんの一例です。

これが私がそれについて行く方法です。もちろん、マッパー クラスにサービス マネージャー用のゲッター メソッドとセッター メソッドを用意し、コントローラーからこれらにアクセスして (コントローラーにはgetServiceLocatorメソッドがあります)、そのように注入することもできます。しかし、私自身はそのアプローチを採用しません。

于 2012-12-26T15:33:30.540 に答える
2

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');
    
于 2012-12-24T15:56:34.743 に答える