Im learning doctrine and i have a form. ZF2 and doctrine with field "email". This field need to be unique, so i need validator for it. Im using fieldsets too (its important here). Problem is, when i use:
DoctrineModule\Validator\UniqueObject
it is impossible to create new entity. This validator need primary key to compare. Validator dump error with message:
Expected context to contain itemId
itemId is my primary key.
So its obvious, that i need to use UniqueObject for update, and:
DoctrineModule\Validator\NoObjectExists
for new entity. And question is:
What is the best way, to store different input filter specification for existing and new entity?
Or, better if possible: How to use Unique validator with new, and existing records with zend form fieldsets.
If i put it in the form, I need to modify it inside controller if entity is new or no. Not so good idea.
I think that the best way is to store input filter spec. inside entity repository, but how i can check there if entity is new or not?
---- edit
I saw documentation, i know how to use unique object but i have error like said before: "Expected context to contain itemId". I think problem is with fieldsets (im using it). I dont understand how to do this (text from docs):
If you leave out the use_context option or set it to false you have to pass an array containing the fields- and identifier-values into isValid(). When using Zend\Form this behaviour is needed if you're using fieldsets.
Ok im using fieldsets, so now what i can do? How i can pass correct values to isValid when im using zend forms?
With UniqueObject
validator you need to have the identifier field in the context. So it will only work if the email
column is the identifier column of your Email
entity? You have an additional 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.
About separating logic for update and new input filters I would suggest making two folders. It is better to keep them strictly separated like that, otherwise it is very likely that mistakes will happen. You could for example do like this (but it totally depends on you personal preference how this is organized).
Application/InputFilter/Create
UserInputFilter
And one for updating resources:
Application/InputFilter/Update
UserInputFilter
And then in your controller you could do like this:
<?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
}
}
I developed it for my application to deal with this issue..hope it will help
<?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 ,in 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)
)
)
),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With