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

2024-01-30

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

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

Question

如何设置它以便仅在我立即需要时才加载? (延迟加载)。据我了解,ZF3 将加载移至控制器构造,这使得如何即时加载某些内容并不明显。

Old Code

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') method.

我假设你已经有一个Commission您的应用程序中的实体Entity命名空间:

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

UPDATE- 随着 Service Manager V3 的发布,FactoryInterface 已移至Zend\ServiceManager\Factory命名空间 (1),工厂实际上是可调用的 (2),并且可以与任何容器互操作 https://github.com/container-interop/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);
    }
}

对于这个问题;正如马科什所说,懒惰服务 https://zendframework.github.io/zend-servicemanager/lazy-services/是在需要时立即创建服务的方法。 ZF3 发布后将使用 zend-servicemanager 3.0 组件。 (目前 zend-expressive 使用它)截至服务管理器 v3 https://github.com/zendframework/zend-servicemanager/releases?after=release-2.7.2您可以通过定义创建一些代理服务惰性服务 https://github.com/zendframework/zend-servicemanager/blob/f39c95385712ea5acb264aa3299c306423d768ed/src/ConfigInterface.php#L32-L40 and 代表者 https://zendframework.github.io/zend-servicemanager/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 开始工厂 https://github.com/zendframework/zend-servicemanager/blob/master/src/Factory/FactoryInterface.php#L39兼容容器接口 https://github.com/container-interop/container-interop/。为了向前兼容,您可能需要保留两者__invoke() and 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, []);
    }
}

希望能帮助到你。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 ZF3 设置延迟加载(任何地方都没有 ServiceLocator 模式) 的相关文章

随机推荐

  • OpenCV GrabCut 算法示例不起作用

    我正在尝试使用 C 在 OpenCV 中实现抓取算法 我偶然发现这个网站 http www packtpub com article opencv segmenting images并找到了一种非常简单的方法 不幸的是 该代码似乎不适合我
  • Java GraphQL - 将字段值传递给对象的解析器

    我希望使用另一种对象类型将字段值传递给已解析的字段 另一种说法是 如果我有 客户 gt 用户 gt 配置文件 如何将客户中的 CustomerID 字段值作为参数或变量传递给配置文件 以便正确解析 有 5 种可能性 从 graphql ja
  • if 语句导致 Verilog 中的锁存推断?

    我正在编写用于合成算法的 Verilog 代码 我对哪些情况可能导致推断锁存器有点困惑 下面是这样的一段代码 虽然它在模拟中工作得很好 但我担心它可能会导致硬件问题 always b1 or b2 b1 map b2 map m1 map
  • 如何在批处理文件中增加txt文件中的值?

    我一直在尝试编写一个批处理代码 该代码将 POST后自动执行 增加一个代表 POST 数量的值 保存 显示值并重新启动 PC 我试图编写一个访问 txt 文件以获取该值的程序 但该值不会增加 echo off echo This scrip
  • 如何使用 Python 将用户移动到不同的 OU

    我一直在玩奇妙的游戏活动目录模块 http timgolden me uk python ad cookbook html来自 Tim Golden 和广泛的 python ldap 模块 虽然我看到了大量关于如何从 python 查询 修
  • LSAT 逻辑游戏部分出现什么类别的组合问题?

    EDIT See 以编程方式解决 谁拥有斑马 问题 https stackoverflow com questions 318888 solving who owns the zebra programmatically对于类似的问题 LS
  • 前台服务无通知

    我想开始一个前景不显示通知的服务 像 instagram telegram zapya 等应用程序有前台服务并且他们没有显示任何通知 我已经测试过类似答案的方法here https stackoverflow com q 10962418
  • 状态栏后面的工具栏

    我的工具栏和状态栏有问题 我将应用程序样式更改为 AppCompat 我的风格是 对于值 styles xml
  • tabula 与 Camelot 从 PDF 中提取表格

    我需要从pdf中提取表格 这些表格可以是任何类型 多个标题 垂直标题 水平标题等 我已经实现了两者的基本用例 发现 tabula 比 Camelot 做得更好一点 但仍然无法完美地检测所有表 而且我不确定它是否适用于所有类型 因此 寻求实施
  • 使一组元素水平向左移动

    在下面的代码中 我安排了几个 div 来水平对齐 我想创建 3 行 在每行中 我希望 div 以不同的速度水平向左移动 检查此 giphy 以获取视觉参考 http www giphy com gifs ME8Av6LT9hgymDnqSP
  • 我可以为 Twitter Bootstrap 崩溃指定多个数据目标吗?

    我想在单击单个触发器时定位两个 div 来展开 那可能吗 您只需添加所有以逗号分隔的 iddata target
  • 必需:play.api.mvc.Request[?] => play.api.mvc.Result

    我正在迁移到 Play 2 6 并拥有以下曾经可以使用的 API 包装函数 trait API self Controller gt def api businessLogic Request AnyContent gt Any Actio
  • Jackson JsonView 未应用

    杰克逊2 2 2 ObjectMapper mapper new ObjectMapper mapper getSerializationConfig withView Views Public class mapper configure
  • 在 Windows 上安装 Mercurial Apache XAMPP 教程

    问完这个问题后 Windows Apache 上的 XAMPP Mercurial 安装 gt HgWebDir cgi 脚本错误 https stackoverflow com questions 2675764 xampp mercur
  • C++:编译错误 - “不会创建 .eh_frame_hdr 表”

    我应该使用数据分析程序进行物理实验 但我无法编译它 该代码很旧 与我能找到的当前 GCC 版本并不真正兼容 为了让事情变得更耗时 我从一个人那里得到了代码 他修改了所有 makefile 以使其在 Mac 上编译 我没有 C 经验 但凭借手
  • C++ 命令行字符串像 Java 一样吗?

    有没有办法像 Java 一样从命令行获取 C 字符串 public static void main String args 其中 args 是 C 字符串数组 不完全是 但你可以很容易地接近 include
  • 如何保证正确捕获并重新触发表单提交事件?

    这可能不是您常见的 如何捕获表单提交事件 问题 我试图理解恰恰jQuery vanilla Javascript 和浏览器 IE FF Chrome Safari Opera 如何处理表单提交事件 以及它们之间的关系 请参阅我的另一个问题
  • unix中nice和setpriority的区别

    我正在尝试用 C 语言实现 unix 的 nice 命令的不同风格 我已经看到了 Nice 系统调用和 setpriority 调用的定义 Nice 调用仅增加 减少进程的优先级 如果我想将进程的优先级设置为特定值 我不能使用nice 调用
  • connect/expressjs 中的“签名”cookie 是什么?

    我试图弄清楚 签名cookie 到底是什么 网上没有太多 如果我尝试这个 app use express cookieParser A secret 但仍然 Cookies在浏览器上仍然是100 正常的 而且我真的不知道这里的 签名 是什么
  • 如何使用 ZF3 设置延迟加载(任何地方都没有 ServiceLocator 模式)

    我正在编写一个新的 ZF2 应用程序 我注意到 从任何地方 调用服务的 ServiceLocator 使用模式已从 ZF3 中弃用 我想为ZF3编写代码 我能够设置我的控制器在构造函数时调用所有依赖项 但这意味着加载 即Doctrine在我