问题
I'm using Doctrine 2 in a Zend Framework application and require functionality similar to Zend_Validate_Db_RecordExists and Zend_Validate_Db_NoRecordExists.
For example, when a user enters a new item, I need to validate that a duplicate entry doesn't already exist. This is easy to accomplish with Zend_Db by adding the Db_NoRecordExists validator on my forms.
I tried implementing the custom-validator solution proposed here, but I can't figure out how they are communicating with Doctrine to retrieve entities (I suspect this approach may no longer work post-Doctrine 1.x).
The FAQ section of the Doctrine manual suggests calling contains() from the client code, but this only covers collections, and if possible I'd like to handle all of my form validation consistently from within my form models.
Can anyone suggest a way to use these Zend validators with Doctrine 2 DBAL configured as the database connection/resource?
回答1:
It's quite straightforward, really.
I have a few Zend_Validate-type validators that talk to Doctrine ORM, so I have an abstract class that they descend from.
Here's the abstract class:
<?php
namespace TimDev\Validate\Doctrine;
abstract class AbstractValidator extends \Zend_Validate_Abstract{
/**
* @var Doctrine\ORM\EntityManager
*/
private $_em;
public function __construct(\Doctrine\ORM\EntityManager $em){
$this->_em = $em;
}
public function em(){
return $this->_em;
}
}
Here's my NoEntityExists validator:
<?php
namespace TimDev\Validate\Doctrine;
class NoEntityExists extends AbstractValidator{
private $_ec = null;
private $_property = null;
private $_exclude = null;
const ERROR_ENTITY_EXISTS = 1;
protected $_messageTemplates = array(
self::ERROR_ENTITY_EXISTS => 'Another record already contains %value%'
);
public function __construct($opts){
$this->_ec = $opts['class'];
$this->_property = $opts['property'];
$this->_exclude = $opts['exclude'];
parent::__construct($opts['entityManager']);
}
public function getQuery(){
$qb = $this->em()->createQueryBuilder();
$qb->select('o')
->from($this->_ec,'o')
->where('o.' . $this->_property .'=:value');
if ($this->_exclude !== null){
if (is_array($this->_exclude)){
foreach($this->_exclude as $k=>$ex){
$qb->andWhere('o.' . $ex['property'] .' != :value'.$k);
$qb->setParameter('value'.$k,$ex['value'] ? $ex['value'] : '');
}
}
}
$query = $qb->getQuery();
return $query;
}
public function isValid($value){
$valid = true;
$this->_setValue($value);
$query = $this->getQuery();
$query->setParameter("value", $value);
$result = $query->execute();
if (count($result)){
$valid = false;
$this->_error(self::ERROR_ENTITY_EXISTS);
}
return $valid;
}
}
Used in the context of a Zend_Form (which has an em() method like the abstract class above):
/**
* Overrides superclass method to add just-in-time validation for NoEntityExists-type validators that
* rely on knowing the id of the entity in question.
* @param type $data
* @return type
*/
public function isValid($data) {
$unameUnique = new NoEntityExists(
array('entityManager' => $this->em(),
'class' => 'PMS\Entity\User',
'property' => 'username',
'exclude' => array(
array('property' => 'id', 'value' => $this->getValue('id'))
)
)
);
$unameUnique->setMessage('Another user already has username "%value%"', NoEntityExists::ERROR_ENTITY_EXISTS);
$this->getElement('username')->addValidator($unameUnique);
return parent::isValid($data);
}
回答2:
Check out the RecordExists.php and NoRecordExists.php classes in my project:-
https://github.com/andyfenna/AJF-IT/tree/master/library/AJFIT/Validate
I hope these are some use to you.
Thanks
Andrew
来源:https://stackoverflow.com/questions/7951453/zend-validate-db-recordexists-with-doctrine-2