2013-12-13 48 views
0

我使用Silex和Form和Validator提供程序。Silex/Symfony表單驗證器:確保一個值是唯一的

我有一個非常簡單的登記表格:

  • 用戶名
  • 密碼
  • 密碼

的用戶名必須是唯一的確認,如何檢查?

這是我的代碼:

$form = $app['form.factory']->createBuilder('form') 
     ->add('username', 'text', array(
     'constraints' => array(
      new Assert\NotBlank(), 
      new Assert\Length(array('min' => 6, 'max' => 20))) 
     )) 
     ->add('password', 'repeated', array(
     'constraints' => array(
      new Assert\NotBlank(), 
      new Assert\Length(array('min' => 6, 'max' => 20)) 
     ) 
     )) 
     ->getForm(); 

隨着Symfony的,我知道有是UniqueEntity約束,但它與學說,我只使用Doctrine DBAL(Silex的提供商)

我想我可以使用回調約束,但我想知道是否有比使用SQL查詢寫回調更好的解決方案...或寫我自己的約束對象

謝謝

+0

[使用Symfony驗證程序驗證匹配和唯一性]的可能重複(http://stackoverflow.com/questions/12641897/validating-match-and-unique-using-symfony-validator) – Maerlyn

+0

不是重複的,我要求「最佳」方式來實現我的目標:「在字段上添加約束以檢查值是否唯一」。我在我的問題中提到了兩種方法:創建自己的約束或使用回調。哪一個是最好的 ?有其他方法嗎? –

回答

0

好吧,我決定創建自己的約束,因爲我可以重用它的電子郵件例如。 所以,這是我的實現:

UniqueEntry.php:

<?php 
/** 
* Ensure a value is unique in the database 
* 
* @author Thomas KELLER 
*/ 

use Symfony\Component\Validator\Constraint; 
use Symfony\Component\Validator\Exception\MissingOptionsException; 
use Symfony\Component\Validator\Exception\InvalidArgumentException; 

/** 
* @Annotation 
*/ 
class UniqueEntry extends Constraint { 

    public $notUniqueMessage = 'This value already exist in the database'; 
    public $dbal_connection; 
    public $table; 
    public $field; 

    public function __construct($options = null) 
    { 
    parent::__construct($options); 

    if ($this->dbal_connection === null) 
     throw new MissingOptionsException(sprintf('The option "dbal_connection" is mandatory for constraint %s', __CLASS__), array('dbal_connection')); 

    if (!$this->dbal_connection instanceof \Doctrine\DBAL\Connection) 
     throw new InvalidArgumentException(sprintf('The option "dbal_connection" must be an instance of Doctrine\DBAL\Connection for constraint %s', __CLASS__)); 

    if ($this->table === null) 
     throw new MissingOptionsException(sprintf('The option "table" is mandatory for constraint %s', __CLASS__), array('table')); 

    if (!is_string($this->table) OR $this->table == '') 
     throw new InvalidArgumentException(sprintf('The option "table" must be a valid string for constraint %s', __CLASS__)); 

    if ($this->field === null) 
     throw new MissingOptionsException(sprintf('The option "field" is mandatory for constraint %s', __CLASS__), array('field')); 

    if (!is_string($this->field) OR $this->field == '') 
     throw new InvalidArgumentException(sprintf('The option "field" must be a valid string for constraint %s', __CLASS__)); 
    } 
} 

UniqueEntryValidator.php:

<?php 
use Symfony\Component\Validator\Constraint; 
use Symfony\Component\Validator\ConstraintValidator; 

class UniqueEntryValidator extends ConstraintValidator 
{ 
    public function validate($value, Constraint $constraint) 
    { 
    $query = sprintf('SELECT `%s` FROM `%s` WHERE `%s` = ?', 
     $constraint->field, 
     $constraint->table, 
     $constraint->field); 

    $stmt = $constraint->dbal_connection->executeQuery($query, array($value)); 

    if ($stmt->fetch()) 
     $this->context->addViolation($constraint->notUniqueMessage); 
    } 
} 

我張貼我的實現有建議可以隨意評論它;)

+1

實現此目的的一個稍微簡單的方法是使用[回調約束](http://symfony.com/doc/current/reference/constraints/Callback.html),傳遞一個函數,如:'array('models \ User','validateEmailUniqueness')'。這並不是非常簡單,但我發現定義兩個新類只是爲了創建一個令人厭煩的驗證器類型的需求。 – robomc

+0

我認爲有一些優點:更容易重複使用(您不必重複所有控制器中的代碼),控制器中的代碼更少,Silex的精神(遵循其他驗證器約定) –

+0

您也可以使用[FormEvents]( http://symfony.com/doc/current/components/form/form_events.html#c-the-formevents-post-submit-event)like'POST_SUBMIT' 看看[BoltCMS](https:// github.com/bolt/bolt)soruce代碼(for [v1.6.x](https://github.com/bolt/bolt/blob/release/1.6/app/src/Bolt/Controllers/Backend.php# L985)和[v2.x](https://github.com/bolt/bolt/blob/v2.1.1/src/Controllers/Backend.php#L1397)) –