gpt4 book ai didi

zend-framework2 - 如何使用 ZF3 设置延迟加载(任何地方都没有 ServiceLocator 模式)

转载 作者:行者123 更新时间:2023-12-05 00:56:02 25 4
gpt4 key购买 nike

我正在编写一个新的 ZF2 应用程序。我注意到 ZF3 已弃用“从任何地方”调用服务的 ServiceLocator 使用模式。我想为 ZF3 编写代码。

我能够将我的 Controller 设置为在构造函数时调用所有依赖项。但这意味着加载,即 Doctrine在我需要它之前先提出对象。

问题

如何设置它以便仅在我需要时才加载它? (延迟加载)。我知道 ZF3 将加载移至 Controller 构造,这使得如何加载即时加载内容并不明显。

旧代码

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

最佳答案

如果您没有任何有效/强有力的理由来实例化自定义实体存储库,您应该更喜欢扩展 Doctrine\ORM\EntityRepository在您的存储库中,例如 CommissionRepository .例如;

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') 时,实体管理器将在构建时自动注入(inject)到存储库中。方法。

I assume that you already have a Commission entity in your app's Entity namespace:


<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

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

然后,您可以简化工厂中存储库的注入(inject)过程,例如:
// 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);
}
}

UPDATE - With the release of Service Manager V3, FactoryInterface has been moved to Zend\ServiceManager\Factory namespace (1), factories are literally invokables (2) and works with any container-interop compatible DIC (3) Updated factory would be like below:


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

对于这个问题;正如马科什所说, 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' => '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 兼容.为了向前兼容,您可能希望同时保留 __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, []);
}
}

希望能帮助到你。

关于zend-framework2 - 如何使用 ZF3 设置延迟加载(任何地方都没有 ServiceLocator 模式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36969109/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com