将ServiceLocator注入并使用到抽象的Zend\Form基类中

PWa*_*sch 1 zend-form zend-framework2

我创建了一个名为的抽象表单类AbstractApplicationForm.我希望通过Zend\ServiceManager\ServiceLocatorAwareInterface访问转换器来将服务定位器注入其中:

namespace Application\Form;

use Zend\Form\Form;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

abstract class AbstractApplicationForm 
    extends Form 
    implements ServiceLocatorAwareInterface
{
    protected $serviceLocator;
    protected $translator;

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }       

    public function getTranslator()
    {
        if (!$this->translator) {
            $this->translator = $this->getServiceLocator()->get('translator');
        }

        return $this->translator;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的申请表扩展了这个类,如下所示:

namespace Trade\Form;

use Zend\Captcha;
use Zend\Captcha\Image;
use Zend\Form\Element;
use Application\Form\AbstractApplicationForm;

class MemberForm extends AbstractApplicationForm
{
    public function init()
    {
        $this->setAttribute('method', 'post');

        // Add the elements to the form
        $id = new Element\Hidden('id');
        $first_name = new Element\Text('first_name');
        $first_name->setLabel($this->getTranslator('First Name'))
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以使用getTranslator来翻译标签.

到现在为止还挺好.在我的控制器操作中,我创建了这样的表单:

public function joinAction()
{
    // Create and initialize the member form for join
    $formManager = $this->serviceLocator->get('FormElementManager');
    $form        = $formManager->get('Trade\Form\MemberForm');
Run Code Online (Sandbox Code Playgroud)

结果是ServiceManager异常:

Zend\ServiceManager\ServiceManager :: get无法获取或创建翻译实例

我没有其他任何定义Module.phpmodule.config.php我认为我不需要.我有这样定义的翻译module.config.php:

'translator' => array(
    'locale' => 'en_US',
    'translation_patterns' => array(
        array(
            'type'     => 'gettext',
            'base_dir' => __DIR__ . '/../language',
            'pattern'  => '%s.mo',
        ),
    ),
Run Code Online (Sandbox Code Playgroud)

当我在控制器中获取它时,哪个工作正常:

$sm               = $this->getServiceLocator();
$this->translator = $sm->get('translator');
Run Code Online (Sandbox Code Playgroud)

所以翻译配置实际上是正确的,但我无法以我的形式检索它.谁知道我做错了什么?

Ocr*_*ius 9

这实际上是你在ZF2上可以看到的同样问题,何时使用getServiceLocator()和何时不使用

FormElementManagerAbstractPluginManager,并在构造函数中AbstractPluginManager,以下服务初始化时说:

$this->addInitializer(function ($instance) use ($self) {
     if ($instance instanceof ServiceLocatorAwareInterface) {
        $instance->setServiceLocator($self);
    }
});
Run Code Online (Sandbox Code Playgroud)

事实是$self,在这种情况下,指的是插件管理器本身.这意味着任何实现Zend\ServiceManager\ServiceLocatorAwareInterface和由插件管理器(在本例中为FormElementManager)生成的服务都会自动注入插件管理器.

插件管理器不是主服务定位器(再次,请参阅ZF2何时使用getServiceLocator()以及何时不使用).

Zend\Form\FormElementManager当您调用时,实例由主服务管理器生成:

$formElementManager = $this->serviceLocator->get('FormElementManager');
Run Code Online (Sandbox Code Playgroud)

Zend\Form\FormElementManagerimplements开始Zend\ServiceManager\ServiceLocatorAwareInterface,它引用了实际的"主"服务管理器.

因此,在您的表格中:

$formElementManager = $this->getServiceLocator();

$mainServiceManager = $formElementManager->getServiceLocator();

$translator = $mainServiceManager->get('translator');
Run Code Online (Sandbox Code Playgroud)