php - Filtros de entrada ZF2 y Doctrine(Unique, ObjectExists) para entidades nuevas y existentes con conjuntos de campos
doctrine2 zend-framework2 (4)
Con el validador UniqueObject
debe tener el campo identificador en el contexto. ¿Entonces solo funcionará si la columna de email
es la columna de identificación de su entidad de Email
? Usted tiene una columna de id
adicional. Sería mejor usar el validador NoObjectExists
en su caso de usuario:
''email'' => array(
''validators'' => array(
array(
''name'' => ''DoctrineModule/Validator/NoObjectExists'',
''options'' => array(
''object_repository'' => $entityManager->getRepository(
''Application/Entity/Email''
),
''fields'' => ''email''
)
)
)
)
También puede encontrar este ejemplo en la documentación .
EDITAR
Sobre la separación de la lógica para la actualización y los nuevos filtros de entrada, sugeriría hacer dos carpetas. Es mejor mantenerlos estrictamente separados así, de lo contrario es muy probable que se cometan errores. Por ejemplo, podría hacer esto (pero depende totalmente de sus preferencias personales sobre cómo se organiza esto).
Application/InputFilter/Create
UserInputFilter
Y uno para actualizar recursos:
Application/InputFilter/Update
UserInputFilter
Y luego en tu controlador puedes hacer esto:
<?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
}
}
Estoy aprendiendo doctrina y tengo una forma. ZF2 y doctrina con campo "correo electrónico". Este campo debe ser único, por lo que necesito validador para él. Estoy usando fieldsets también (es importante aquí). El problema es que cuando uso:
DoctrineModule/Validator/UniqueObject
es imposible crear una nueva entidad. Este validador necesita clave primaria para comparar. Error de volcado del validador con mensaje:
Contexto esperado para contener itemId
itemId es mi clave principal.
Entonces, es obvio que necesito usar UniqueObject para la actualización y:
DoctrineModule/Validator/NoObjectExists
para nueva entidad. Y la pregunta es:
¿Cuál es la mejor manera de almacenar diferentes especificaciones de filtros de entrada para entidades existentes y nuevas?
O mejor, si es posible: cómo usar el validador único con registros nuevos y existentes con conjuntos de campos de formulario zend.
Si lo pongo en el formulario, necesito modificarlo dentro del controlador si la entidad es nueva o no. No es tan buena idea.
Creo que la mejor manera es almacenar las especificaciones del filtro de entrada. dentro del repositorio de entidades, pero ¿cómo puedo verificar si la entidad es nueva o no?
---- editar
Vi documentación, sé cómo usar un objeto único, pero tengo el error antes dicho: "Contexto esperado para contener itemId". Creo que el problema es con los conjuntos de campo (lo estoy usando). No entiendo cómo hacer esto (texto de documentos):
Si omite la opción use_context o la establece en false, debe pasar una matriz que contenga los campos y los valores de identificador en isValid (). Al usar Zend / Form, este comportamiento es necesario si está utilizando conjuntos de campos .
Ok, estoy usando conjuntos de campo, entonces, ¿qué puedo hacer? ¿Cómo puedo pasar los valores correctos a isValid cuando estoy usando formularios zend?
Lo desarrollé para mi aplicación para tratar este problema ... espero que ayude
<?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);
}
}
Luego, en su filtro de entrada adjunto a su formulario, solo agregue, en la matriz ''Validadores'':
''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)
)
)
),
Mostraré mi solución, creo que es bastante buena si alguien quiere mantener el validador dentro de la forma. En mi fieldset tengo el método getInputFilterSpecification (), que se procesa automáticamente, y allí:
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'',
)
)
)
)
);
}
Todavía no se ha probado con un validador único. Tal vez haya un problema con la clave principal también, la verificaré en unos días. Pero sigue siendo una forma simple de asignar un validador correcto basado en un nodo nuevo o existente.
Mi conclusión: el validador único no funciona con ZF2 y fieldsets.
Solo necesita tener el validador UniqueObject como el siguiente en el formulario Especificación del filtro de entrada:
''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!''
),
),
)
),
),
Puede encontrar más detalles en este enlace: https://github.com/doctrine/DoctrineModule/blob/master/docs/validator.md