ZF2 and Doctrine input filters (Unique, ObjectExists) for new and existing objects with fields

I study the doctrine, and I have a form. ZF2 and the doctrine with the email field. This field must be unique, so for this I need a validator. I also use fields (this is important here). The problem is that I use:

DoctrineModule\Validator\UniqueObject 

unable to create new object. This validator needs a primary key for comparison. Validator dump error with message:

Expected context to contain itemId

itemId is my primary key.

So, obviously, I need to use UniqueObject to update and:

 DoctrineModule\Validator\NoObjectExists 

for a new facility. And the question is:

What is the best way to store different input filter specifications for an existing and a new facility?

Or, if possible, better: using a unique validator with new and existing entries with fields of the zend form.

If I put it in a form, I need to change it inside the controller if the object is new or not. Not a good idea.

I think the best way is to keep the input filter specification. inside the entity repository, but how can I check there if the object is new or not?

---- edit

I saw the documentation, I know how to use a unique object, but I have an error, as was said earlier: "The expected context that contains the ItemId". I think the problem is with the fields (they are used). I do not understand how to do this (text from documents):

If you do not specify the use_context option or set the value to false, you must pass an array containing the values ​​of the fields and identifier to the action (). When using Zend \ Form, this behavior is necessary if you are using fields .

Ok im using fields so now what can i do? How can I pass the correct isValid values ​​when im uses zend forms?

+5
source share
4 answers

With UniqueObject validator you need to have an identifier field in context. So it will work only if the email column is the identifier column of your email object? You have an extra id column. It would be better to use the NoObjectExists validator in your user case:

 'email' => array( 'validators' => array( array( 'name' => 'DoctrineModule\Validator\NoObjectExists', 'options' => array( 'object_repository' => $entityManager->getRepository( 'Application\Entity\Email' ), 'fields' => 'email' ) ) ) ) 

You can also find this example in the documentation .

EDIT

On sharing logic for updates and new input filters, I would suggest creating two folders. It is better to keep them strictly separated like this, otherwise it is very likely that errors will occur. For example, you can do this (but it completely depends on your personal preferences, how it is organized).

 Application/InputFilter/Create UserInputFilter 

And one for updating resources:

 Application/InputFilter/Update UserInputFilter 

And then in your controller you can do the following:

 <?php namespace Application\Controller; use Application\InputFilter\Create; use Application\InputFilter\Update; class UserController{ public function updateAction() { $inputFilter = new Update\UserInputFilter(); //... etc } public function createAction() { $inputFilter = new Create\UserInputFilter(); //... etc } } 
+2
source

I developed it for my application to solve this problem. Hope this helps.

 <?php namespace Application\Validator; use Zend\Validator\AbstractValidator; class DbUniqueObject extends AbstractValidator { const INVALID = 'objectAlreadyExists'; protected $messageTemplates = array( self::INVALID => "Field value must be unique in the database (id=%id%)", ); protected $messageVariables = array( 'id' => array('options' => 'id'), ); protected $options = array( 'em', 'entity', 'field', 'exclude_id' ); public function __construct($options = null) { $this->options = $options; parent::__construct($options); } public function isValid($value) { $qb = $this->em->createQueryBuilder(); $qb->select('t') ->from($this->entity, 't') ->where('t.' . $this->field . '= :field') ->setParameter('field', $value); if (boolval($this->exclude_id)) { $qb->andWhere('t.id <> :id'); $qb->setParameter('id', $this->exclude_id); } $result = $qb->getQuery()->getResult(); if (boolval($result)) { $this->options['id'] = $result[0]->getID(); $this->error(self::INVALID); return false; } return true; } public function __get($property) { return array_key_exists($property, $this->options) ? $this->options[$property] : parent::__get($property); } } 

Anf, then in your input filter attached to your form, just add the "Validators" array:

  'validators' => array( array( 'name' => '\Application\Validator\DbUniqueObject', 'options' => array( 'em' => $em, //Entity manager 'entity' => 'Application\Entity\Customer', // Entity name 'field' => 'label', // column name 'exclude_id' => $this->customer->getID() : null, // id to exclude (useful in case of editing) ) ) ), 
+2
source

I will show my solution, I think, not bad if someone wants to keep the validator inside the form. In my fieldset, I have a getInputFilterSpecification () method, which is processed automatically, and there:

 public function getInputFilterSpecification() { // im bind object new or exist to the form, // so there is a simple way to get it: $entity = $this->getObject(); // method to check if object is new or not: // $this->_entityManager i have entitymanager passed in constructor switch ($this->_entityManager->getUnitOfWork()->getEntityState($entity)) { case \Doctrine\ORM\UnitOfWork::STATE_MANAGED: // im switch validator, unique for existing: $existValidator = 'DoctrineModule\Validator\UniqueObject'; case \Doctrine\ORM\UnitOfWork::STATE_NEW: $existValidator = 'DoctrineModule\Validator\NoObjectExists'; } // propably we can also check if object primary key is empty or not // i will test it later return array( 'elementName' => array( 'required' => true, 'validators' => array( array( 'name' => $existValidator, 'options' => array( 'object_repository' => $this->_entityManager->getRepository('My\Entity'), 'object_manager' => $this->_entityManager, 'fields' => 'fieldName', ) ) ) ) ); } 

It is still not tested with a unique validator. Maybe there will be a problem with the primary key, I will check it in a few days. But its still an easy way to assign the correct validator based on a new or existing node.

My conclusion: A unique validator does not work with ZF2 and fields.

+1
source

You only need to have a UniqueObject validator in the following form in the Input Filter Specification form:

  'email' => array( 'validators' => array( array( 'name' => 'DoctrineModule\Validator\UniqueObject', 'options' => array( 'use_context' => true, 'object_repository' => $this->objectManager->getRepository('Namespace\EntityName'), 'object_manager' => $this->objectManager, 'fields' => 'email', 'messages' => array( 'objectNotUnique' => 'Email already exists!' ), ), ) ), ), 

You can find more information at this link: https://github.com/doctrine/DoctrineModule/blob/master/docs/validator.md

0
source

Source: https://habr.com/ru/post/1234917/


All Articles