【问题标题】:Injecting and using ServiceLocator into an abstract Zend\Form base class在抽象 Zend\Form 基类中注入和使用 ServiceLocator
【发布时间】:2013-03-13 00:39:55
【问题描述】:

我创建了一个名为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;
    }
}

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

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'))

这样,我就可以用getTranslator翻译标签了。

到目前为止一切顺利。在我的控制器操作中,我创建了这样的表单:

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

结果是 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',
        ),
    ),

当我将它放入控制器时效果很好:

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

所以翻译器配置实际上是正确的,但我无法在我的表单中检索它。 有人知道我做错了什么吗?

【问题讨论】:

    标签: zend-form zend-framework2


    【解决方案1】:

    这实际上与您在ZF2 when to use getServiceLocator() and when not to 看到的问题相同

    FormElementManager 是一个AbstractPluginManager,在AbstractPluginManager 的构造函数中,添加了service initializer

    $this->addInitializer(function ($instance) use ($self) {
         if ($instance instanceof ServiceLocatorAwareInterface) {
            $instance->setServiceLocator($self);
        }
    });
    

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

    插件管理器不是主要的服务定位器(再次参见ZF2 when to use getServiceLocator() and when not to)。

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

    $formElementManager = $this->serviceLocator->get('FormElementManager');
    

    由于Zend\Form\FormElementManager 实现了Zend\ServiceManager\ServiceLocatorAwareInterface,它引用了实际的“主”服务管理器。

    因此,在您的表单中:

    $formElementManager = $this->getServiceLocator();
    
    $mainServiceManager = $formElementManager->getServiceLocator();
    
    $translator = $mainServiceManager->get('translator');
    

    【讨论】:

    • 感谢您的解释。现在很有意义。
    • 这在字段集中似乎不起作用,如何在那里使用翻译器?
    【解决方案2】:

    你可能不得不做getServiceLocator()->getServiceLocator()->get('translator')

    我不明白为什么有时你必须这样做,但它确实有效。

    【讨论】:

    • 可能是因为stackoverflow.com/questions/14911965/… - 表单元素管理器实际上是一个与主不同的服务管理器
    • 感谢您的回答和解释。做到了!
    • @PWansch 我并不是要降低这个答案的价值(因此我的赞成票),但我强烈建议并要求它,以使 Ocramius 在下面的回答被接受,因为这将有助于社区方式更多。
    • 同意。我接受了奥克拉米乌斯的回答。这肯定会对社区有所帮助。关于 ServiceLocator 的使用存在相当多的困惑,这会有所帮助。
    【解决方案3】:

    我有一个抽象字段集类和一个具体字段集类的相同构造。 Translator 以完全相同的方式注入,但是当我尝试在 fieldset 中“$this->getTranslator()”时,会抛出以下异常:

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

    所以 SM 找不到翻译服务。 我通过以下方式添加(配置)翻译器:

    'service_manager' => array(
        'factories' => array(
            'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
            'Navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
            'logger' => function ($sm) {
                $logger = new \Zend\Log\Logger();
                $config = $sm->get('Config');
    
                if ($config['logger']['writer'] == 'ChromePhp'):
                    $logger->addWriter(new \Application\Log\Writer\ChromePhp()); else:
                    $logger->addWriter('FirePhp');
                endif;
                return $logger;
            }
        ),
    ),
    'translator' => array(
        'locale' => 'de_DE',
        'translation_file_patterns' => array(
            array(
                'type' => 'gettext',
                'base_dir' => __DIR__ . '/../language',
                'pattern' => '%s.mo',
            ),
        ),
    ),
    

    在我看来,翻译工作完美。 所以目前我不知道下一步该尝试什么。您能告诉我您是如何将翻译服务添加到您的应用程序中的吗?

    编辑 -------------- 附加信息: 在字段集类

    $this->getServiceLocator();
    

    给我一​​个“Zend\Form\FormElementManager”类型的对象。这对于表单元素是正确的。

    $this->getServiceLocator()->getServiceLocator();
    

    但这给了我 NULL 而不是 ServiceLocator-Object...

    谢谢, 迈克尔

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多