如何使用ZF3设置延迟加载(从任何地方都没有ServiceLocator模式)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用ZF3设置延迟加载(从任何地方都没有ServiceLocator模式)相关的知识,希望对你有一定的参考价值。
我正在写一个新的ZF2应用程序。我注意到ZF3已经弃用了“从任何地方”调用服务的ServiceLocator使用模式。我想为ZF3编写代码。
我能够设置我的Controller在构造函数时调用所有依赖项。但这意味着在我需要之前先加载Doctrine
对象。
题
如何设置它以便仅在我需要它时立即加载? (延迟加载)。我知道ZF3将加载移动到Controller构造,这使得如何加载Just-In-Time的东西并不明显。
旧代码
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();
}
如果您没有任何有效/强大的理由来实例化自定义实体存储库,则应该更喜欢在DoctrineORMEntityRepository
等存储库中扩展CommissionRepository
。例如;
use DoctrineORMEntityRepository;
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('AppEntityCommission')
方法时,实体管理器将自动注入构造中的存储库。
我假设你的应用程序的
Commission
命名空间中已经有一个Entity
实体:
<?php
namespace AppEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity(repositoryClass="AppRepoCommissionRepository")
* @ORMTable
*/
class Commission
{
}
然后,您可以简化工厂中存储库的注入过程,例如:
// ZF2 Way
class CommissionControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $services)
{
$em = $services->getServiceLocator()->get('doctrine');
$repository = $em->getRepository('AppEntityCommission');
return new CommissionController($repository);
}
}
更新 - 随着Service Manager V3的发布,FactoryInterface已被移动到
ZendServiceManagerFactory
命名空间(1),工厂实际上是invokables(2)并且可以与任何container-interop兼容的DIC(3)一起工作更新的工厂将如下所示:
// ZF3 Way
use ZendServiceManagerFactoryFactoryInterface;
use InteropContainerContainerInterface;
use DoctrineORMEntityManager;
class CommissionControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $dic, $name, array $options = null) {
$em = $dic->get(EntityManager::class);
$repository = $em->getRepository('AppEntityCommission');
return new CommissionController($repository);
}
}
对于这个问题;从marcosh的说法来看,Lazy Services是在需要时立即创建服务的方式。 ZF3将在发布时使用zend-servicemanager 3.0组件。 (目前zend-expressive使用它)从servicemanager v3开始,您可以通过在服务配置中定义lazy_services和delegators来创建一些代理服务:
'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' => 'MyApplicationFoo',
],
// 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兼容。为了向前兼容,您可能希望在工厂中保留__invoke()
和createService()
方法以实现平滑迁移。
最后,您的ZF3兼容工厂可能如下所示:
class CommissionControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $name, array $options = null)
{
$em = $container->get('doctrine');
$repository = $em->getRepository('AppEntityCommission');
return new CommissionController($repository);
}
public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null)
{
return $this($container, $requestedName, []);
}
}
希望能帮助到你。
以上是关于如何使用ZF3设置延迟加载(从任何地方都没有ServiceLocator模式)的主要内容,如果未能解决你的问题,请参考以下文章