zf2查看助手工厂/服务定位器参数

时间:2017-11-20 22:50:02

标签: zend-framework2 zend-view

我有一个视图助手,它通过返回特定于实体的渲染器充当工厂。

我希望工厂实现FactoryInterface和MutableCreationOptionsInterface,因此我可以根据传递给它的对象类型返回不同的渲染器,例如:

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

但是,在视图中无法访问servicelocator,并且使用它的__invoke方法调用我创建的工厂视图助手。这意味着在此处进行类型检查并返回特定的渲染器而不使用服务管理器,这是不可取的。例如

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

注意这个"工厂"只是为了传递当前视图的实例而不得不扩展AbstractHelper(view)。

我的理想"会是这样的(概念验证,而不是工作代码):

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

...但是通过上面的演示,我不确定如何从视图中调用它(因为视图助手通常是从他们的__invoke方法而不是从服务管理器调用的)?

(着眼于迁移到ZF3,我不想使用ServiceLocatorAwareInterface)。

1 个答案:

答案 0 :(得分:0)

您可以在viewhelper的工厂部分声明module.config.php为:

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

然后使用以下模型:

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

就个人而言,我首先创建一个只包含必要类的特定服务管理器,这是我在课堂上录制的那个。

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

顺便说一下,这个模型在ZF3下不起作用,你需要一个构建viewhelper类的工厂类。然而,变化并不太复杂。