如何在 Zend Framework 中使用依赖注入?

2024-01-19

目前我正在尝试学习Zend Framework,因此我购买了《Zend Framework in Action》这本书。

在第 3 章中,介绍了基本模型和控制器以及它们的单元测试。基本控制器如下所示:

class IndexController extends Zend_Controller_Action 
{
    public function indexAction()
    {
        $this->view->title = 'Welcome';
        $placesFinder = new Places();
        $this->view->places = $placesFinder->fetchLatest();
    }
}

Places是从数据库中获取最新地点的模型类。这里让我烦恼的是:我应该如何测试IndexController in 隔离?作为参考Places类是“硬编码的”,我无法注入任何存根或模拟IndexController.

我更想要的是这样的:

class IndexController extends Zend_Controller_Action 
{
    private $placesFinder;

    // Here I can inject anything: mock, stub, the real instance
    public function setPlacesFinder($places)
    {
        $this->placesFinder = $places;
    }

    public function indexAction()
    {
        $this->view->title = 'Welcome';
        $this->view->places = $this->placesFinder->fetchLatest();
    }
}

我发布的第一个代码示例绝对不适合单元测试,因为IndexController不能单独测试。第二个要好得多。现在我只需要某种方法将模型实例注入到控制器对象中。

我知道 Zend Framework 本身没有用于依赖注入的组件。但是有一些不错的 PHP 框架,可以与 Zend Framework 一起使用吗?或者在 Zend Framework 中有其他方法可以做到这一点吗?


逻辑到模型

首先,值得一提的是,控制器应该只需要功能测试,尽管所有逻辑都属于模型。

我的实现

以下是我的 Action Controller 实现的摘录,它解决了以下问题:

  • 允许注入任何对操作的依赖
  • 验证操作参数,例如你不能传递数组$_GET当需要整数时

我的完整代码还允许生成基于或必需或处理的操作参数的规范 URL(用于 SEO 或用于统计的唯一页面哈希)。为此,我使用这个抽象的 Action Controller 和自定义的 Request 对象,但这不是我们在这里讨论的情况。

显然,我使用反射来自动确定操作参数和依赖对象。

这是一个巨大的优势,简化了代码,但也会对性能产生影响(对于我的应用程序和服务器来说影响很小,并不重要),但您可以实现一些缓存来加快速度。计算一下好处和坏处,然后再决定。

DocBlock 注释正在成为一个众所周知的行业标准,并且出于评估目的对其进行解析变得更加流行(例如 Doctrine 2)。我在许多应用程序中使用了这种技术,效果很好。

写这门课我的灵感来自于动作,现在带有参数! http://devzone.zend.com/article/2855 and Jani Hartikainen 的博客文章 http://codeutopia.net/blog/2009/03/16/zend_controller-actions-that-accept-parameters/.

所以,这是代码:

<?php

/**
 * Enchanced action controller
 *
 * Map request parameters to action method
 *
 * Important:
 * When you declare optional arguments with default parameters, 
 * they may not be perceded by optional arguments,
 * e.g.
 * @example
 * indexAction($username = 'tom', $pageid); // wrong
 * indexAction($pageid, $username = 'tom'); // OK
 * 
 * Each argument must have @param DocBlock
 * Order of @param DocBlocks *is* important
 * 
 * Allows to inject object dependency on actions:
 * @example
 *   * @param int $pageid
 *   * @param Default_Form_Test $form
 *   public function indexAction($pageid, Default_Form_Test $form = null)
 *
 */
abstract class Your_Controller_Action extends Zend_Controller_Action
{  
    /**
     *
     * @var array
     */
    protected $_basicTypes = array(
        'int', 'integer', 'bool', 'boolean',
        'string', 'array', 'object',
        'double', 'float'
    );

    /**
     * Detect whether dispatched action exists
     * 
     * @param string $action
     * @return bool 
     */
    protected function _hasAction($action)
    {
        if ($this->getInvokeArg('useCaseSensitiveActions')) {
            trigger_error(
                    'Using case sensitive actions without word separators' .
                    'is deprecated; please do not rely on this "feature"'
            );

            return true;
        }

        if (method_exists($this, $action)) {

            return true;
        }

        return false;
    }

    /**
     *
     * @param string $action
     * @return array of Zend_Reflection_Parameter objects
     */
    protected function _actionReflectionParams($action)
    {
        $reflMethod = new Zend_Reflection_Method($this, $action);
        $parameters = $reflMethod->getParameters();

        return $parameters;
    }

    /**
     *
     * @param Zend_Reflection_Parameter $parameter
     * @return string
     * @throws Your_Controller_Action_Exception when required @param is missing
     */
    protected function _getParameterType(Zend_Reflection_Parameter $parameter)
    {
        // get parameter type
        $reflClass = $parameter->getClass();

        if ($reflClass instanceof Zend_Reflection_Class) {
            $type = $reflClass->getName();
        } else if ($parameter->isArray()) {
            $type = 'array';
        } else {
            $type = $parameter->getType();
        }

        if (null === $type) {
            throw new Your_Controller_Action_Exception(
                    sprintf(
                            "Required @param DocBlock not found for '%s'", $parameter->getName()
                    )
            );
        }

        return $type;
    }

    /**
     *
     * @param Zend_Reflection_Parameter $parameter 
     * @return mixed
     * @throws Your_Controller_Action_Exception when required argument is missing
     */
    protected function _getParameterValue(Zend_Reflection_Parameter $parameter)
    {
        $name = $parameter->getName();
        $requestValue = $this->getRequest()->getParam($name);

        if (null !== $requestValue) {
            $value = $requestValue;
        } else if ($parameter->isDefaultValueAvailable()) {
            $value = $parameter->getDefaultValue();
        } else {
            if (!$parameter->isOptional()) {
                throw new Your_Controller_Action_Exception(
                        sprintf("Missing required value for argument: '%s'", $name));
            }

            $value = null;
        }

        return $value;
    }

    /**
     *
     * @param mixed $value 
     */
    protected function _fixValueType($value, $type)
    {
        if (in_array($type, $this->_basicTypes)) {
            settype($value, $type);
        }

        return $value;
    }

    /**
     * Dispatch the requested action
     *
     * @param   string $action Method name of action
     * @return  void
     */
    public function dispatch($action)
    {
        $request = $this->getRequest();

        // Notify helpers of action preDispatch state
        $this->_helper->notifyPreDispatch();

        $this->preDispatch();
        if ($request->isDispatched()) {
            // preDispatch() didn't change the action, so we can continue
            if ($this->_hasAction($action)) {

                $requestArgs = array();
                $dependencyObjects = array();
                $requiredArgs = array();

                foreach ($this->_actionReflectionParams($action) as $parameter) {
                    $type = $this->_getParameterType($parameter);
                    $name = $parameter->getName();
                    $value = $this->_getParameterValue($parameter);

                    if (!in_array($type, $this->_basicTypes)) {
                        if (!is_object($value)) {
                            $value = new $type($value);
                        }
                        $dependencyObjects[$name] = $value;
                    } else {
                        $value = $this->_fixValueType($value, $type);
                        $requestArgs[$name] = $value;
                    }

                    if (!$parameter->isOptional()) {
                        $requiredArgs[$name] = $value;
                    }
                }

                // handle canonical URLs here

                $allArgs = array_merge($requestArgs, $dependencyObjects);
                // dispatch the action with arguments
                call_user_func_array(array($this, $action), $allArgs);
            } else {
                $this->__call($action, array());
            }
            $this->postDispatch();
        }

        $this->_helper->notifyPostDispatch();
    }

}

要使用它,只需:

Your_FineController extends Your_Controller_Action {}

并像往常一样为操作提供注释(至少您已经应该这样做了;)。

e.g.

/**
 * @param int $id Mandatory parameter
 * @param string $sorting Not required parameter
 * @param Your_Model_Name $model Optional dependency object 
 */
public function indexAction($id, $sorting = null, Your_Model_Name $model = null) 
{
    // model has been already automatically instantiated if null
    $entry = $model->getOneById($id, $sorting);
}

(DocBlock 是必需的,但是我使用 Netbeans IDE,因此 DocBlock 是根据操作参数自动生成的)

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

如何在 Zend Framework 中使用依赖注入? 的相关文章

  • SQL 大表中的随机行(使用 where 子句)

    我有一个网站 人们可以在其中对汽车进行投票 向用户展示 4 辆汽车 他 她可以投票选出他们最喜欢的汽车 桌子cars有重要的列 car id int 10 not auto increment so has gaps views int 7
  • 使用 strtotime() 计算时间差(以小时和分钟为单位)[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions time1
  • 如何将自定义类型数组传递给 Postgres 函数

    我有一个自定义类型 CREATE TYPE mytype as id uuid amount numeric 13 4 我想将它传递给具有以下签名的函数 CREATE FUNCTION myschema myfunction id uuid
  • 通过jquery传递搜索参数

    我有一个表单 如果用户输入搜索查询 其参数应通过 jquery 传递 并在获取结果后将结果加载到 div 容器中 由于我不太熟悉 jquery 我该怎么做 html currently the data is being displayed
  • 我如何知道请求是否来自 flash swf?

    我有一个用 flash 开发的应用程序 我需要访问一些 php 文件 因此 如果访问来自 swf 则 php 文件会返回一些数据 如何判断请求是否来自Flash 无需将 get post 变量传递给 php 可能是用户代理 推荐人 请记住
  • Ubuntu 18.04升级后php7.2-curl无法安装

    今天从 16 04 升级到 18 04do release upgrade d 在升级过程中 我被告知一些软件包将被删除 其中包括 删除 libperl5 22 lxc common perl modules 5 22 php imagic
  • $_POST、$_GET 和 $_REQUEST 之间有什么区别?

    我对这些超级全局变量有点困惑 POST GET and REQUEST 在 PHP 中 在 PHP 中哪些场景需要使用这些变量 这三个变量的主要区别是什么 POST是在使用 application x www form urlencoded
  • 如何读取 XML 文件并从中获取值以在 PHP 编码的 HTML 页面中显示

    我有一个 XML 文件 其中有一些重复的标签 其中包含不同的值 我需要获取这些值并显示在我的网页中 请帮助我得到这个 如果您使用 PHP5 可以查看 SimpleXML 您可以在这里找到介绍教程 http www w3schools com
  • .Net 6 控制台应用程序:WebApplication.CreateBuilder 与 Host.CreateDefaultBuilder

    我正在研究 NET 6 并希望构建一个简单的控制台应用程序 并进行一些依赖项注入 据我所知 为了使启动 现在只是程序 文件更具可读性 已经做了很多工作 让我有点困惑的是 所有改进似乎都是针对 API 项目中使用的 WebApplicatio
  • 通过 AJAX 发送 XML

    我在 jQuery 中创建了一个 xml 文档 如下所示 var xmlDocument
  • 从 PDO 准备好的语句中获取原始 SQL 查询字符串

    在准备好的语句上调用 PDOStatement execute 时 有没有办法让原始 SQL 字符串执行 出于调试目的 这将非常有用 我假设您的意思是您想要最终的 SQL 查询 并将参数值插入其中 我知道这对于调试很有用 但这不是准备好的语
  • 访客客户检查 Woocommerce 订单账单电子邮件时可享受首单折扣

    通过对照正在处理和已完成的订单检查来宾客户的电子邮件地址 如果电子邮件没有订单 我想给来宾 首单折扣 如果这能在客人输入电子邮件时发生 那就太好了 我想我已经成功制作了折扣代码 现在我请求帮助合并这两个代码 使其一切正常 这是折扣代码 ad
  • Opencart最低下单价不包括一类

    我正在使用 opencart 并成功为所有交易添加了最低订单价格 这是我使用的代码 div div div class warning Minimum 10 Euro to checkout div 现在我想从中排除一个类别 以便可以购买该
  • Twig:选择某些块并渲染它们

    我正在将 twig 模板引擎集成到 PHP 应用程序中 特别是 我想使用 twig 引擎来渲染表单 了解了 symfony2 如何使用 twig 渲染表单小部件后 他们有一个巨大的模板文件 其中包含所有小部件 如下所示 block pass
  • 在 Apache 服务器上将特定的 .htm 页面处理为 .php [重复]

    这个问题在这里已经有答案了 我正在为 Apache 服务器编程 并且只需要将一个特定的 html 页面 例如 first htm 作为 PHP 脚本进行处理 可以设置吗 SetHandler http httpd apache org do
  • 从数据库 MYSQL 和 Codeigniter 获取信息

    如果你们需要其他信息 上一个问题就在这里 从数据库中获取信息 https stackoverflow com questions 13336744 fetching information from the database 另一个更新 尽
  • 与 array_intersect 相反?

    是否有一个内置函数可以获取数组 1 中不存在于数组 2 中的所有成员 我知道如何以编程方式执行此操作 只是想知道是否有一个内置函数可以执行相同的操作 所以请不要提供代码示例 这听起来像是一份工作array diff http www php
  • 图像创建从jpeg() PHP

    我正在使用 imagecreatefromjpeg 函数合并两张图片 现在我面临的问题是 当我使用服务器中的图片时 它工作正常 而当我使用其他网站的图片时 它不起作用 例如 当我使用这个 PHP 文件时http coolfbapps in
  • PHP简单的html dom解析器与wordpress冲突吗?

    PHP简单的html dom解析器与wordpress冲突吗 因为每当我尝试将其与此代码一起包含在我的标头中时 一切都变成空白 感谢您提前提供任何帮助 当我尝试在 HTML 文档中使用 PHP 包含时 我遇到了同样的问题 但当我使用func
  • 如何移动 Zend_Layout 的“视图”

    通常它会是这样的结构 application modules somemodule views scripts index index phtml 我如何将其移动到 application templates somemodule temp

随机推荐

  • 在动画中切换位置属性上的 CABasicAnimation 会导致闪烁

    我有一些代码使用 CALayers 使气泡从下到上流动 如果用户触摸屏幕 我会编写一些代码 将当前正在运行的动画替换为具有手指触摸的 toPoint 的动画 当动画切换时 它会导致设备上 而不是模拟器上 闪烁 任何有关消除闪烁的提示将不胜感
  • 获取html文件的最后修改日期

    在导入到我的网络应用程序中时 如何找出 html 文件的最后修改日期 html 文件位于另一台服务器上 不同的用户可以进行更新 当我检索页面时 我希望能够看到它的上次更新时间 以便我可以在主页上标记更新日期 我 我假设您正在使用 HTTP
  • “定义”数组元素的计数

    给定以下数组 var arr undefined undefined 2 5 undefined undefined 我想得到元素的数量are定义 即 那些是not undefined 除了循环遍历数组之外 还有什么好的方法吗 在最近的浏览
  • 为 Mac 版 docker 指定 IP 地址

    我在用着Mac 版 Docker 测试版它远离聚光灯 有什么方法可以从控制台运行它或强制使用任何配置文件来指定 docker 主机的 IP 地址 现在它从 192 168 64 3 更改为 192 168 64 5 每次启动 docker
  • 模型视图控制器设计模式代码示例

    我正在研究模型 视图 控制器设计模式 并且从理论上理解了该模式背后的概念 但我想了解一下人们如何实际将其付诸实践 维基百科提到了 Wt Web 工具包 CppCMS 和其他一些使用该模式的标准实现 但是我对这些并不熟悉 我只是希望和 如果有
  • 非交换的 symify(或简化)

    我希望能够简化 Python 中字符串的数学表达式 有几种 可交换 的方法可以做到这一点 是否有一个不可交换的函数 我知道sympify from sympy可以做一些非交换工作 这里有一个例子 from sympy import x Sy
  • 如何从magento中的愿望清单集合中删除项目

    在 Magento 中 我想删除或删除当前登录用户的愿望清单项目 目前 我通过启用复选框来选择愿望清单项目 然后使用 Mage getModel wishlist item gt load id gt delete 删除它们 我使用的代码片
  • 带类型参数的 PetaPoco 查询

    使用 PetaPoco 如何调用带有类型参数的存储过程 在 C 中我这样做 cmd Parameters Add email SqlDbType NVarChar Value email 查看文档 http www toptensoftwa
  • 有什么理由不使用 OrderedDict 吗?

    我指的是有序字典 http docs python org 2 library collections html collections OrderedDict来自collections模块 这是一个有序字典 如果它具有可订购的附加功能 我
  • 在 ag-grid 中显示嵌套 json

    我正在使用 Angular Grid ag grid 来显示数据 我正在尝试在我的角度网格中显示嵌套的 json 数据 但我没有成功 下面是示例 json 数据和 colDefs 请建议为什么点运算符不像 jqgrid 那样工作 无法使用嵌
  • 如何为 JTable 列添加 JXDatepicker

    我正在使用 JTable 我有一个日期列 当我单击一个单元格时 我需要在其中显示一个 JXDatePicker 以便我可以从中选择一个日期 有人可以告诉我该怎么做吗 谢谢 等待一个答复 你可能应该使用DatePickerCellEditor
  • 使用弧线和动态属性覆盖设置器

    我需要在 setter 方法中做一些额外的事情 但这样做时我遇到了无限循环 我有一个核心数据对象 interface Transaction NSManagedObject property nonatomic retain NSDate
  • 以纯文本形式将用户 ID 发送到前端是否安全?

    我有一个带有 MongoDB 的 Express 应用程序 它为每个用户文档创建一个用户 ID 该用户 ID 也以 jwt 进行编码 这给新开发人员造成了一种错觉 即用户 ID 不能以纯文本形式发送到前端 有人可以解释一下将用户 ID 发送
  • 将 mongoengine 与多处理结合使用 - 如何关闭 mongoengine 连接?

    无论我尝试什么 当尝试在 mongoengine 数据库上使用多处理时 我都会遇到有关不分叉活动 mongo 连接的 MongoClient 在 fork 之前打开 警告 这标准蒙戈建议 http api mongodb com pytho
  • 为什么类模板构造函数参数不自动确定? [复制]

    这个问题在这里已经有答案了 考虑下面的类 template
  • 调整 mat-form-field Angular Material 的高度

    我遇到了一个简单调整保存自动完成输入的 mat form field 的问题 从图像中您可以看到它是否超出了垫子工具栏的高度 但我还没有找到一种简单的方法来调整整个输入的高度 以便它可以保留在工具栏区域内 宽度效果很好 身高没有 在工具栏外
  • 使用 django-rest-framework 获取模型的随机对象

    在我的 Django 项目中 我需要提供一个视图以使用 django rest framework 从模型中获取随机对象 我有这个 ListAPIView class RandomObject generics ListAPIView qu
  • 如何选择具有与给定值列表完全匹配的外键的主键?

    例如 pk ref fk 1 a 1 b 1 c 2 a 2 b 2 d 如何执行类似 伪 查询的查询 select distinc pk ref where fk in all a c 返回的查询结果必须与列表中外键的所有给定值匹配 结果
  • 如何授予 ASP.NET MVC 应用程序对注册表项的读取访问权限?

    我读过其他关于如何实现此目标的帖子 但无济于事 当我将应用程序部署到服务器 2008 时 我在运行时遇到以下异常 Access to the registry key HKEY CURRENT USER Software Microsoft
  • 如何在 Zend Framework 中使用依赖注入?

    目前我正在尝试学习Zend Framework 因此我购买了 Zend Framework in Action 这本书 在第 3 章中 介绍了基本模型和控制器以及它们的单元测试 基本控制器如下所示 class IndexController