简体   繁体   English

zf2查看帮助程序工厂/服务定位器参数

[英]zf2 view helper factory / service locator parameters

I have a view helper that acts as a factory by returning an entity-specific renderer. 我有一个视图助手,它通过返回特定于实体的渲染器充当工厂。

I would like the factory to implement the FactoryInterface and MutableCreationOptionsInterface, so i can return different renderers depending on the type of object passed to it, eg: 我希望工厂实现FactoryInterface和MutableCreationOptionsInterface,因此我可以根据传递给它的对象的类型返回不同的渲染器,例如:

$serviceLocator->get('entityRenderer', ['entity' => $user]); // returns UserRenderer
$serviceLocator->get('entityRenderer', ['entity' => $admin]); // returns AdminRenderer
$serviceLocator->get('entityRenderer'); // returns DefaultRenderer

However, there is no access to the servicelocator from within a view, and the factory view helper i have created is called using it's __invoke method. 但是,无法从视图内部访问servicelocator,并且使用它的__invoke方法调用我创建的工厂视图帮助程序。 This means the type check is occuring here and returning the specific renderer without using the service manager, which is not desirable. 这意味着此处将进行类型检查,并在不使用服务管理器的情况下返回特定的渲染器,这是不希望的。 eg 例如

class EntityRendererFactory extends AbstractHelper{
    public function __invoke(Entity $entity){
        if($entity instanceof User){
            $renderer =  new UserRenderer($entity);
            $renderer->setView($this->view);
        }

        if($entity instanceof Admin){
            $renderer = new AdminRenderer($entity);
            $renderer->setView($this->view);
        }

        if($renderer){
            return $renderer;
        }
    }
}

Note how this "factory" is having to extend AbstractHelper (view) simply just to pass on the instance of the current view. 请注意,此“工厂”如何仅为了传递当前视图的实例而必须扩展AbstractHelper(视图)。

My "ideal" would be something like this (proof of concept, not working code): 我的“理想”将是这样的(概念证明,而不是工作代码):

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
class EntityRendererFactory implements FactoryInterface, MutableCreationOptionsInterface{
        protected $options = [];
        protected $renderers = [];

        public function createService(ServiceLocatorInterface $serviceLocator){
            $this->addRenderer($serviceLocator->get('ViewHelperManager')->get('UserRenderer'), User::class);
            $this->addRenderer($serviceLocator->get('ViewHelperManager')->get('AdminRenderer'), Admin::class);
            $this->addRenderer($serviceLocator->get('ViewHelperManager')->get('DefaultRenderer'), 'default');

            if(!array_key_exists('entity', $this->options)){
                return $this->getRenderer('default');
            }

            $entity = $this->options['entity'];

            foreach($this->getRenderers() as $renderer){
                if($renderer->canRender($entity)){
                    return $renderer;
                }
            }

            //Alternatively, more specific hard-coding interface type check
            if($entity instanceof User){
                return $serviceLocator->get('ViewHelperManager')->get('UserRenderer');
            }
            //etc.
        }

        public function setCreationOptions(array $options){
            $this->options = $options;
        }
    }

...but with the above demonstration, i would be unsure how to call it from within the view (as view helpers are typically called from their __invoke method and not from the service manager)? ...但是通过上面的演示,我不确定如何从视图中调用它(因为视图助手通常是通过__invoke方法而不是从服务管理器调用的)?

(With an eye to migrating to ZF3, i do not want to use the ServiceLocatorAwareInterface). (出于迁移到ZF3的考虑,我不想使用ServiceLocatorAwareInterface)。

You can declare your viewhelper in the factories section of module.config.php as : 您可以在viewhelper的factory部分module.config.php为:

return [
    ...
    'view_helpers' => [
       'factories' => [
           'entityRenderer' => EntityRendererFactory::class 
       ]
    ],
    ...
] 

then use the following model : 然后使用以下模型:

class EntityRendererFactory extends AbstractHelper implement FactoryInterface
{
    private $sm;
    public function createService(ServiceLocatorInterface $serviceLocator){
        $this->sm = $serviceLocator;
        return $this;
    }
    public function _invoke() {
        // your code
    }
}

Personally, I start by creating a specific service manager containing only the necessary classes and it is this one that I record in the class. 就个人而言,我首先创建一个仅包含必要类的特定服务管理器,而我正是在类中记录了该类。

$this->sm = $servicelocator->getServiceLocator()->get('mySpecificSM');

Incidentally, this model does not work under ZF3 where you need a factory class that builds the viewhelper class. 顺便说一句,该模型在ZF3下不起作用,因为ZF3需要一个用于构建viewhelper类的工厂类。 A change not too complicated however. 但是,更改并不太复杂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM