Как использовать DoctrineModule \ Validator \ NoObjectExists в редактируемых формах – Zend Framework 2 & Doctrine 2

Каков наиболее эффективный способ использования DoctrineModule\Validator\NoObjectExists в форме Zend, которая также используется для редактирования? Поскольку, когда я использую ту же форму для сохранения отредактированных значений, это подтверждает, что форма существования объекта и флаги недействительна.

Несколько недель назад я решил ту же проблему, используя вспомогательный метод в моем настраиваемом фильтре. Я не уверен, что это правильный подход, но он работает.

  1. Напишите пользовательский входной фильтр, расширяющий Zend\InputFilter\InputFilter .
  2. Добавьте свои общие фильтры и валидаторы в метод init() фильтра.
  3. Напишите вспомогательный метод во входном фильтре, который добавляет валидатор существования доктрины к текущей цепочке валидатора, как показано ниже.
  4. Добавьте валидатор существования в экземпляр фильтра при создании нового объекта. При редактировании используйте экземпляр универсального фильтра.

Так,

 <?php /** * Baz filter */ class BazFilter extends Zend\InputFilter\InputFilter { /** * This method will be triggered automatically when you retrive baz filter via inputfiltermanager. */ public function init() { // Define your input names, types, validators and filters as arrays $this->add(array( 'name' => 'code', 'required' => true, 'validators' => array(), 'filters' => array() )); $this->add( array(...) ); $this->add( array(...) ); // ... } /** * Appends doctrine's noobjectexists validator to validator chain only when required. * * @access public * @param \Doctrine\ORM\EntityRepository $repository * @return \Zend\InputFilter\InputFilter */ public function appendExistenceValidator(\Doctrine\ORM\EntityRepository $repository) { $validatorSignature = array( 'name' => 'code', 'validators' => array( array( 'name' => 'DoctrineModule\Validator\NoObjectExists', 'options' => array( 'object_repository' => $repository, 'fields' => 'code', 'messages' => array( NoObjectExists::ERROR_OBJECT_FOUND => "This object with code already exists in database." ) ) ) ) ); $validator = $this->getFactory()->createInput( $validatorSignature ); $this->add($validator); return $this; } } 

Наконец, добавьте этот входной фильтр в свою форму при редактировании:

 // $form = your form instance // $filter = Bazfilter instance $form->setData($postData)->setInputFilter( $filter ); if( $form->isValid() === false ) { // ... } 

При создании:

 // $filter = bazfilter instance $repository = $entityManager->getRepository('Your\Entity\Name'); $filter->appendExistenceValidator( $repository ); // <-- Notice this line $form->setData($postData)->setInputFilter( $filter ); if( $form->isValid() === false ) { // ... } 

Вы не можете использовать NoObjectExists в простой форме, вы должны использовать UniqueObject:

https://github.com/doctrine/DoctrineModule/blob/ea9e6902fd24906250d01d31561454451a788f86/src/DoctrineModule/Validator/UniqueObject.php

Я попытался использовать DoctrineModule \ Validator \ NoObjectExists в форме и предотвращает обновления, которые сохраняют уникальные поля без изменений. Как упоминал @Tadej, используйте UniqueObject. Вот пример формы:

 class ExampleForm extends Form implements InputFilterProviderInterface { /** * @var EntityManager */ private $entityManager; /** * @var Repository */ private $repository; /** * ExampleForm constructor. * * @param EntityManager $entityManager * @param Repository $repository */ public function __construct(EntityManager $entityManager, Repository $repository) { $this->entityManager = $entityManager; $this->repository = $repository; $this->add( [ 'type' => Text::class, 'name' => 'name', 'options' => [ 'label' => _('Name *') ], 'attributes' => [ 'class' => 'form-control', ], ] ); } /** * @return array */ public function getInputFilterSpecification() { return [ 'name' => [ 'required' => true, 'filters' => [ ], 'validators' => [ [ 'name' => UniqueObject::class, 'options' => [ 'object_manager' => $this->entityManager, 'object_repository' => $this->repository, 'fields' => ['name'], 'use_context' => true, 'messages' => [ UniqueObject::ERROR_OBJECT_NOT_UNIQUE => "Name '%value%' is already in use", ] ] ] ] ], ]; } } 

Обратите внимание на использование опции «use_context» – она ​​должна использоваться, если поле не является первичным ключом. «сообщения» необязательны.