0

値のコレクションが一意の文字列としてデータベースに格納されることがあります。この文字列は、ユーザー定義の区切り文字 ("," または "_" など) で区切られたすべての値で構成されています。

Symfony2.1 アプリケーションでは、その文字列に含まれるトークンの数をカウントすることによって文字列 (たとえば、入力テキスト フォームによって提供される) を検証する検証制約があると便利です。

考えられる例は、タグを文字列形式で保存する場合です。つまり、 のような入力フィールドから文字列を受け取りますvalue1,value2,value10,value25。4 つのトークンが渡されていることがわかりますが、その制御を行うフォーム バリデータはありません。したがって、次のようなバリデータを使用する必要があります。

/**
* @Assert\Token(
     *      delimiter=",", 
     *      min = "1",
     *      max = "5",
     *      minMessage = "You must specify at least one token",
     *      maxMessage = "You cannot specify more than 5 tokens")
*/ 
$tags;

new in Symfony2.1 Countバリデーターを使用する場合に似たようなことがありますが、これは文字列では機能せず、Countable を実装するオブジェクトの配列でのみ機能します。

そのような「トークン化された文字列」バリデーターを実装する方法を誰が知っていますか?

4

1 に答える 1

0

問題を解決しました。解決策を共有したいだけです。

考えられる解決策の 1 つは、 Callback 制約を使用することです。たとえば、質問で提供されているタグ リストの例に従います。

/**
 * @Assert\Callback(methods={"isTagStringValid"})
 */
class AFormModel{

protected $tags;

    public function isTagStringValid(ExecutionContext $context){
        $tagsExploded = explode(',', $this->tags);

        if(count($tagsExploded)==0){
            $context->addViolationAtSubPath('tags', 'Insert at least a tag', array(), null);    
        }
        if(count($tagsExploded)==1 && $tagsExploded[0]==='')
            $context->addViolationAtSubPath('tags', 'Insert at least a tag', array(), null);            
        }
        else if(count($tagsExploded)>10){
            $context->addViolationAtSubPath('tags', 'Max 10 values', array(), null);            
        }
    }

}

より洗練された方法は、「トークン」バリデーターを定義することです。次に例を示します。

namespace .....

use Symfony\Component\Validator\Constraint;

/**
  * @Annotation
*/
class Token extends Constraint {
    public $min;
    public $max;
    public $minMessage = '{{ min }} token(s) are expected';
    public $maxMessage = '{{ max }} token(s) are expected';
    public $invalidMessage = 'This value should be a string.';   
    public $delimiter = ',';
public function __construct($options = null){
    parent::__construct($options);

    if (null === $this->min && null === $this->max) {
        throw new MissingOptionsException('Either option "min" or "max" must be given for constraint ' . __CLASS__, array('min', 'max'));
    }
}    

}

バリデータクラスは次のとおりです。

namespace ...

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class TokenValidator extends ConstraintValidator {
    public function isValid($value, Constraint $constraint) {
        if ($value === null) {
            return;
        }
        if(!is_string($value)){
            $this->context->addViolation($constraint->invalidMessage, array(
                '{{ value }}' => $value,
            ));

            return;
        }

        $tokensExploded = explode($constraint->delimiter, $value);
        $tokens = count($tokensExploded);
        if($tokens==1){
            if($tokensExploded[0]==='')
                $tokens = 0;
        }

        if (null !== $constraint->max && $tokens > $constraint->max) {
            $this->context->addViolation($constraint->maxMessage, array(
                '{{ value }}' => $value,
                '{{ limit }}' => $constraint->max,
            ));

            return;
        }
        if (null !== $constraint->min && $tokens < $constraint->min) {
            $this->context->addViolation($constraint->minMessage, array(
                '{{ value }}' => $value,
                '{{ limit }}' => $constraint->min,
            ));
        }        
    }
}

このようにして、ユーザー定義のバリデーターをインポートし、質問で提案したようにどこでも使用できます。

于 2012-11-14T19:13:24.203 に答える