zf2 - 将依赖项注入控制器

时间:2016-03-16 21:10:20

标签: php dependency-injection zend-framework2

由于逐步淘汰ServiceLocatorAwareInterface,zend-mvc的最新更新导致兼容性中断。我在控制器中使用servicelocator动态加载依赖项,例如:

class IndexController extends AbstractActionController
/**
 *
 * @return \UserManagement\Form\User\Details
 */
protected function getUserDetailsForm(){
    return $this->getFormManager()->get('User\Details');
}

/**
 *
 * @return FormElementManager
 */
protected function getFormManager(){
    return $this->getServiceLocator()->get('FormElementManager');
}
}

现在提出异常(E_USER_DEPRECEATED),并显示以下消息:

  

您正在从班级中检索服务定位器   用户\控制器\的IndexController。请注意   不推荐使用ServiceLocatorAwareInterface,将其删除   版本3.0,以及ServiceLocatorAwareInitializer。你会   需要更新您的类以接受创建时的所有依赖项,   通过构造函数参数或setter,并使用工厂   进行注射。

我的问题是,将表单放入控制器的最佳方法是什么?我的服务层和其他特定于控制器的依赖项被注入到构造函数中,但我真的不想用控制器可能需要的所有表单来污染构造函数,我也不想要开销创建不会使用的表单对象。表单不能在控制器中创建,即$ form = new Form(),因为它们也是动态创建的,例如: Module.php

public function getFormElementConfig ()
{
    return array(
            'factories' => array(
                    'User\Details' => function($sm){
                        $userMapper = $sm->getServiceLocator()->get('Model\User\Mapper');
                        $form = new \User\Form\Details($userMapper);
                        return $form;               
                    }
                )
            );
}

3 个答案:

答案 0 :(得分:0)

拥有越来越多的特定控制器。

通过这种方式,您可以实例化一个控制器,然后必须完全注入执行您可能需要的任何任务所需的所有对象。

如果所有共享的操作都是公共URL路径片段,则无法将操作组合到一个控制器类中。从软件设计的角度来看,一个在不同方法中做很多独立事物的类只是做得太多了。并且做得太多反映在你必须注入的依赖数量上。

答案 1 :(得分:0)

解决方案很少。

  • 使控制器更小。方法少,依赖性少。但是,更多的工厂。

  • 使用ZF2 proxy manager。它实质上取代了代理对象的昂贵对象实例化。

  • 另一种选择是添加一个通过表单元素管理器延迟加载表单的包装器或容器。然后,您可以将此容器注入控制器或服务层。以这种方式使用服务定位器并不是理想的"当您松开明确定义的类依赖项时。

我有一个FormElementLazyProvider课程及其associated factory,可能值得一试。

例如。

$elementConfig = [
    'create' => 'MyModule\Form\CreateForm',
    'edit'   => 'MyModule\Form\EditForm',
    'delete' => 'MyModule\Form\DeleteForm',
];

$factory = function($serviceName, $elementName) use ($formElementManager) {
    if ($formElementManager->has($serviceName)) {
        return $formElementManager->get($serviceName);
    }
    return false;
};

$provider = new \ArpForm\Service\FormElementLazyProvider($factory, $elementConfig);

$provider->hasElement('create'); // true
$provider->getElement('edit');   // Callback executed and form object return

答案 2 :(得分:0)

问题的关键是服务定位器隐藏控制器类的依赖关系。

Zend框架指示您远离ServiceRepository模式,并使用DI容器或使用构造函数注入或setter注入来使用正确的依赖注入。您也可以使用工厂注入依赖项。

请阅读有关服务存储库的信息,许多人将其视为反模式。