2

У меня есть форма (Zend\Form\Form) с некоторыми вложенными полями (Zend\Form\Fieldset). Конструкция довольно похожа на конструкцию в Form Collections tutorial.Как использовать службы для набора полей формы в Zend Framework 2?

Storage\Form\MyForm 
|_'Storage\Form\Fieldset\FooFieldset' 
    |_'Storage\Form\Fieldset\BarFieldset' 
|_'Storage\Form\Fieldset\BazFieldset' 
... 

MyForm

class MyForm { 
    public function __construct() 
    { 
     ... 
     $this->add(
      [ 
       'type' => 'Storage\Form\Fieldset\FooFieldset', 
       'options' => [ 
        'use_as_base_fieldset' => true 
       ] 
      ] 
     ); 
    } 
} 

FooFieldset

class FooFieldset extends Fieldset implements InputFilterProviderInterface 
{ 
    public function __construct() 
    { 
     parent::__construct('foo'); 
     $this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies! 
    } 
} 

Он работает, но класс FIELDSET имеет два зависимостей в нем. Я хочу их вводить. Для того, чтобы сделать это, я создал FooFieldsetFactory и расширил /module/MyModule/config/module.config.php по:

'service_manager' => [ 
    'factories' => [ 
     'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory', 
    ], 
], 

на заводе просто игнорируются. Я предполагаю, что локатор службы сначала пытается найти класс по пространству имен, и только если ничего не найдено, он смотрит в invokables и factories. ОК. Затем я создал псевдоним:

'service_manager' => [ 
    'factories' => [ 
     'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory', 
    ], 
], 
'aliases' => [ 
    'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\FooFieldset', 
], 

... и пытался использовать его вместо Storage\Form\Fieldset\FooFieldset в моем классе формы. Но теперь я получаю исключение:

Zend \ Form \ FormElementManager :: прибудете не удалось извлечь или создать экземпляр для хранения \ Form \ Fieldset \ Foo

Я также попытался это напрямую :

'service_manager' => [ 
    'factories' => [ 
     'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory', 
    ], 
], 

Отсутствие эффекта, та же ошибка.

И это тоже не работает (та же ошибка):

'form_elements' => [ 
    'factories' => [ 
     'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory', 
    ], 
], 

Так ссылается сервис для FIELDSET, кажется, не работает. Или я делаю что-то неправильно?

Как пользоваться услугами для полей форм?


UPDATE

С некоторыми debuggin я узнал, что мой Foo FIELDSET завод не может быть найден, потому что он не добавляется в factories списке Zend\Form\FormElementManager. Вот это место, в Zend\Form\Factory:

enter image description here

Так что мой конфиг

'form_elements' => [ 
    'factories' => [ 
     'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory', 
    ], 
], 

игнорируется. Как это исправить?


UPDATE Дополнительная информация, как я создаю мой Form объект.

/module/Foo/config/module.config.php

return [ 
    'controllers' => [ 
     'factories' => [ 
      'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory' 
     ] 
    ], 
    'service_manager' => [ 
     'factories' => [ 
      'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory', 
     ], 
    ], 
]; 

/module/Foo/src/Foo/Form/Factory/MyFormFactory.php

namespace Foo\Form\Factory; 

use ...; 

class MyFormFactory implements FactoryInterface 
{ 

    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $form = new MyForm(); 
     $form->setAttribute('method', 'post') 
      ->setHydrator(new ClassMethods()) 
      ->setInputFilter(new InputFilter()); 
     return $form; 
    } 
} 

/module/Foo/src/Foo/Controller/Factory/MyControllerFactory.php

namespace Foo\Controller\Factory; 

use ...; 

class MyControllerFactory implements FactoryInterface 
{ 

    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $fooPrototype = new Foo(); 
     $realServiceLocator = $serviceLocator->getServiceLocator(); 
     // $myForm = $realServiceLocator->get('Foo\Form\MyForm'); <-- This doesn't work correctly for this case. The FormElementManager should be used instead. 
     $formElementManager = $realServiceLocator->get('FormElementManager');       
     $myForm = $formElementManager->get('Foo\Form\MyForm'); 
     return new MyController($myForm, $fooPrototype); 
    } 
} 

ответ

4

Эта проблема связана с тем, что вы добавляете свои элементы формы в формы __construct(), а не init()as suggested in the documentation.

Вы можете использовать фабрику вместо invokable для обработки зависимостей в ваших элементах/полях/формах.

И теперь идет первый улов.

Если вы создаете свой класс формы, расширяя Zend\Form\Form, вы не должны добавить пользовательский элемент в __construct -or (как мы это делали в предыдущем примере, где мы использовали FQCN в пользовательском элементе), а скорее в init() метод:

причина является то, что завод в новой форме (которая используется для создания новых элементов с помощью add()) должен иметь форму элемент менеджер приложения injected after the form's constructor has been called Эта форма экземпляр менеджера элемента содержит все ссылки на ваши пользовательских формы элементы, зарегистрированные под кодом form_elements conf iguration.

По телефону add() в форме __constructthe form factory will lazy load a new instance of the form element manager; который сможет создавать все элементы формы по умолчанию, но не будет знать ваш пользовательский элемент формы.

+0

Благодарим вас за подробный ответ! Я переместил логику инициализации из конструктора в 'init()'. Но это не работает. Для ** 'Form' ** элементы просто не найдены, например .:' Нет элемента по имени [foo], найденного в форме'. Для ** 'FieldSet's **: та же ошибка, что и раньше:' Zend \ Form \ FormElementManager :: get не удалось получить или создать экземпляр для Order \ Form \ Fieldset \ Foo'. – automatix

+0

Я также проанализировал состояние 'FormElementManager' в' init() '. Поскольку 'init()' вызывается после конструктора, я ожидал, что найду свои собственные фабрики полей в 'MyFieldset-> factory-> formElementManager-> factory'. Но свойство содержит только стандартные фабрики Zend. – automatix

+0

@automatix Вы создаете * форму *, используя '$ formElementManager-> get ('Order \ Form \ Fieldset \ Foo');' с 'Order \ Form \ Fieldset \ Foo' зарегистрированным в' form_elements'? Вы задаете вопрос только: «Хранение \ Форма \ Полеset \ Foo». – AlexP

 Смежные вопросы

  • Нет связанных вопросов^_^