3

新しいZF2アプリケーションを作成しています。私は、どこからでも呼び出しサービスのServiceLocator使用パターンがZF3から推奨されなくなったことに気付きました。 ZF3のコードを覚えておきたい。ZF3でLazy Loadingをセットアップするにはどうすればいいですか(どこからでもServiceLocatorパターンはありません)

コンストラクタ時にすべての依存関係を呼び出すようにコントローラを設定することができました。しかし、それはつまり、私が必要とする前に、先にDoctrineオブジェクトを先に読み込むことを意味します。

質問

私はすぐにそれを必要とするとき、それが唯一ロードされるように、私はそれを設定するにはどうすればよいですか? (遅延読み込み)。私は、ZF3がコントローラの構築にロードを移すことを理解しています。そのため、ジャストインタイムをロードする方法は明らかになりません。

古いコード

class CommissionRepository 
{ 

    protected $em; 

    function getRepository() 
    { 
     //Initialize Doctrine ONLY when getRepository is called 
     //it is not always called, and Doctrine is not always set up 
     if (! $this->em) 
      $this->em = $this->serviceLocator->get('doctrine'); 
     return $this->em; 
    } 
} 

現在のコードのServiceLocatorパターンのリファクタリング後

class CommissionRepository 
{ 

    protected $em; 

    function getRepository() 
    { 
     return $this->em; 
    } 

    function setRepository($em) 
    { 
     $this->em = $em; 
    } 

    function useRepository($id) 
    { 
     return $this->em->find($id); 
    } 
} 


class CommissionControllerFactory implements FactoryInterface 
{ 

    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $parentLocator = $controllerManager->getServiceLocator(); 

     // set up repository 
     $repository = new CommissionRepository(); 
     $repository->setRepository($parentLocator->get('doctrine')); 

     // set up controller 
     $controller = new CommissionController($repository); 
     $controller->setRepository(); 

     return $controller; 
    } 
} 

class CommissionController extends AbstractActionController 
{ 

    protected $repository; 

    public function setRepository(CommissionRepository $repository) 
    { 
     $this->repository = $repository; 
    } 

    public function indexAction() 
    { 
     //$this->repository already contains Doctrine but it should not 
     //I want it to be initialized upon use. How? 
     //Recall that it has been set up during Repository construction time 
     //and I cannot call it from "anywhere" any more in ZF3 
     //is there a lazy loading solution to this? 
     $this->repository->useRepository(); 
    } 
+2

私はあなたが怠惰なセリフを探していると思います:http://framework.zend.com/manual/current/en/modules/zend.service-manager.lazy-services.html – marcosh

+0

マニュアルに加えて、それは価値がありますZF3サービスマネージャ移行ガイドを読む - > http://zend-servicemanager.readthedocs.io/en/latest/migration/#lazy-services – Crisp

答えて

4

カスタムエンティティリポジトリをインスタンス化するために任意の有効な/強い理由がない場合は、 CommissionRepositoryのようにリポジトリ内でDoctrine\ORM\EntityRepositoryの拡張を優先する必要があります。例えば;このところで

use Doctrine\ORM\EntityRepository; 

class CommissionRepository extends EntityRepository 
{ 
    // No need to think about $em here. It will be automatically 
    // injected by doctrine when you call getRepository(). 
    // 
    function fetchCommissionById($id) 
    { 
     // You can easily get the object manager directly (_em) or 
     // using getEntityManager() accessor method in a repository 
     return $this->_em->find($id); 
    } 
} 

あなたが$em->getRepository('App\Entity\Commission')メソッドを呼び出すときに、エンティティマネージャが自動的に建設上のリポジトリに注入されます。

<?php 
namespace App\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity(repositoryClass="App\Repo\CommissionRepository") 
* @ORM\Table 
*/ 
class Commission 
{ 
} 

次に、あなたがあなたの工場でのようなものリポジトリの注入プロセスを簡素化することができます:

// ZF2 Way 
class CommissionControllerFactory implements FactoryInterface 
{ 

    public function createService(ServiceLocatorInterface $services) 
    { 
     $em = $services->getServiceLocator()->get('doctrine'); 
     $repository = $em->getRepository('App\Entity\Commission'); 

     return new CommissionController($repository); 
    } 
} 
を私はすでに、アプリの Entity名前空間に Commission実体を持っていることを前提とし

更新 - Service ManagerのV3のリリースに伴い、FactoryInterfaceはZend\ServiceManager\Factory名前空間に移動されている(1)、工場は文字通り(2)invokables及び任意のcontainer-interop互換性DICで動作している(3)更新の工場は、以下のようになります:

// ZF3 Way 
use Zend\ServiceManager\Factory\FactoryInterface; 
use Interop\Container\ContainerInterface; 
use Doctrine\ORM\EntityManager; 

class CommissionControllerFactory implements FactoryInterface 
{ 

    public function __invoke(ContainerInterface $dic, $name, array $options = null) { 
     $em = $dic()->get(EntityManager::class); 
     $repository = $em->getRepository('App\Entity\Commission'); 

     return new CommissionController($repository); 
    } 
} 

質問のため、 marcoshさんの言ったように、Lazy Servicesはすぐに必要なときにサービスを作成する方法です。 ZF3はリリース時にzend-servicemanager 3.0コンポーネントを使用します。

'factories' => [], 
'invokables' => [], 
'delegators' => [ 
    FooService::class => [ 
     FooServiceDelegatorFactory::class, 
    ], 
], 
'lazy_services' => [ 
    // map of service names and their relative class names - this 
    // is required since the service manager cannot know the 
    // class name of defined services up front 
    'class_map' => [ 
     // 'foo' => 'MyApplication\Foo', 
    ], 

    // directory where proxy classes will be written - default to system_get_tmp_dir() 
    'proxies_target_dir' => null, 

    // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy" 
    'proxies_namespace' => null, 

    // whether the generated proxy classes should be written to disk or generated on-the-fly 
    'write_proxy_files' => false, 
]; 

はまた、サービスマネージャV3 factoriesで始まるContainerInterfaceと互換性があります:あなたはあなたのサービスの設定でlazy_servicesdelegatorsを定義することで、いくつかのプロキシサービスを作成することができますservicemanager v3の通り(現在のZend-表現力、それを使用しています)。順互換性を保つために、スムーズな移行のために工場に__invoke()createService()の両方のメソッドを保持することをお勧めします。最後に

、あなたのZF3互換工場は次のようになります。

class CommissionControllerFactory implements FactoryInterface 
{ 
    public function __invoke(ContainerInterface $container, $name, array $options = null) 
    { 
     $em = $container->get('doctrine'); 
     $repository = $em->getRepository('App\Entity\Commission'); 

     return new CommissionController($repository); 
    } 

    public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null) 
    { 
     return $this($container, $requestedName, []); 
    } 
} 

はそれがお役に立てば幸いです。

関連する問題