【问题标题】:How can I replace the PhpRenderer in a ZF2 application如何在 ZF2 应用程序中替换 PhpRenderer
【发布时间】:2013-11-25 13:14:32
【问题描述】:

我在我的 ZF2 应用程序中扩展了 PhpRenderer 类,如下所示:

namespace MyLib\View\Renderer;
class PhpRenderer extends \Zend\View\Renderer\PhpRenderer
{

}

我不想添加新的渲染策略,我只是将 PhpRenderer 扩展为add some @method phpdoc for my viewhelpers

如何将标准的 PhpRenderer 替换为扩展的 PhpRenderer,以便用于渲染我的视图脚本?

【问题讨论】:

    标签: php zend-framework2


    【解决方案1】:

    php 渲染器是服务管理器中的一个服务。您可以直接覆盖此服务,也可以通过视图管理器(实例化和配置渲染器)来实现。

    覆盖服务

    在您的模块中,您定义了一个 onBootstrap() 方法。 “旧”的 php 渲染器已经注册,你必须重新定义它。

    public function onBootstrap($e)
    {
        $app = $e->getApplication();
        $sm  = $app->getServiceManager();
    
        $old = $sm->get('ViewRenderer');
        $new = new MyCustomViewRenderer;
    
        $new->setHelperPluginManager($old->getHelperPluginManager());
        $new->setResolver($old->getResolver());
    
        $sm->setAllowOverride(true);
        $sm->setService('ViewRenderer', $new);
        $sm->setAllowOverride(false);
    }
    

    覆盖视图管理器

    还有一个替代方法,您可以在其中重新定义实例化 php 渲染器的视图管理器。您必须为此重新定义视图管理器的工厂:

    在您的 application.config.php 中(注意它是 application 配置,因为模块配置在这里不起作用!)

    service_manager => array(
        'factories' => array(
            'HttpViewManager' => 'MyModule\Service\HttpViewManagerFactory',
        ),
    );
    

    然后创建您的 MyModule\Service\HttpViewManagerFactory:

    use MyModule\View\Http\ViewManager as HttpViewManager;
    
    class HttpViewManagerFactory implements FactoryInterface
    {
        /**
         * Create and return a view manager for the HTTP environment
         *
         * @param  ServiceLocatorInterface $serviceLocator
         * @return HttpViewManager
         */
        public function createService(ServiceLocatorInterface $serviceLocator)
        {
            return new HttpViewManager();
        }
    }
    

    然后你终于可以更新 php 渲染器本身的工厂了:

    use Zend\Mvc\View\Http\ViewManager as BaseViewManager;
    
    class ViewManager extends BaseViewManager
    {
        public function getRenderer()
        {
            if ($this->renderer) {
                return $this->renderer;
            }
    
            $this->renderer = new MyCustomViewPhpRenderer;
            $this->renderer->setHelperPluginManager($this->getHelperManager());
            $this->renderer->setResolver($this->getResolver());
    
            $model       = $this->getViewModel();
            $modelHelper = $this->renderer->plugin('view_model');
            $modelHelper->setRoot($model);
    
            $this->services->setService('ViewRenderer', $this->renderer);
            $this->services->setAlias('Zend\View\Renderer\PhpRenderer', 'ViewRenderer');
            $this->services->setAlias('Zend\View\Renderer\RendererInterface', 'ViewRenderer');
    
            return $this->renderer;
        }
    }
    

    结论

    第一种方法已经实例化了普通的 php 渲染器,所以你实例化了其中两个并用你自己的替换默认值。

    另一种方法是绕过默认 Zend 的 php 渲染器的实例化,但您必须在视图管理器类中执行此操作。这里的问题是您还必须为视图管理器重新定义工厂。这听起来像是绕道而行,但这是完成此任务的唯一方法。

    【讨论】:

    • 我尝试了您的第一个解决方案,但遇到了一些问题。首先,我将 $old->getResolver()` 更改为 $old->resolver(),因为在 PhpRenderer 中没有方法 getResolver()。通过调试,我注意到插件(例如 FlashMessenger)没有加载到新的 PhpRenderer 中。 PhpRenderer::__vars 也是空的。这些内部插件和变量似乎以某种方式绑定到 Zend\View\Renderer\PhpRenderer 命名空间。调试器显示*Zend\View\Renderer\PhpRenderer*__vars = null
    • 我希望 ZF2 可以更轻松地用扩展类替换像 PhpRenderer 这样的类。我觉得我必须向后弯腰才能完成这样的基本任务。
    • 我也尝试了第二种方法,但似乎永远不会调用HttpViewManagerFactory::createService() 方法。正如您在第一步中描述的那样,我确实将工厂添加到 application.config.php。
    • 我把它放在这里讨论:github.com/zendframework/zf2/issues/5573
    【解决方案2】:

    如果您的所有自定义类包含 @method 声明,那么您不需要替换 php 渲染器类。只要确保使用@var docblock,您的 IDE 就会知道该怎么做:

    在视图文件中记录 $this 变量的类型:

    <!-- in a view file -->
    <?php /* @var $this MyLib\View\Renderer\PhpRenderer */ ?>
    
    <?= $this->myCustomViewHelper() ?>
    

    记录视图助手、类等的单个变量或属性:

    class SomeHelper extends AbstractHelper
    {
        /** @var \MyLib\View\Renderer\PhpRenderer */
        protected $view;
    
        public function __invoke()
        {
            $this->view->myCustomViewHelper();
        }
    }
    

    【讨论】:

    • 这确实有效,我已经使用了@var cmets。不过,这不是我最喜欢的解决方案,因为我必须传播几十个这样的解决方案,而且它们有点误导,因为在这种情况下它们没有指示 PhpRenderer 的真实类型。你得到我的投票,但务实的解决方案:)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    • 2022-11-14
    相关资源
    最近更新 更多