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;

在 Symfony2.1 Count验证器中使用 new 时有类似的东西,但它不适用于字符串,仅适用于实现 Countable 的对象数组。

谁知道如何实现那种“标记化字符串”验证器?

4

1 回答 1

0

我解决了我的问题,我只想分享我的解决方案。

一种可能的解决方案是使用回调约束。例如,按照问题中提供的标签列表示例:

/**
 * @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 回答