0

Using the scenario in How to Embed a Collection of Forms, I would like to ensure that a Task always have at least 1 Tag. For my case however, the relationship of Task and Tag is 1:n rather than n:m.

I am particularly concerned on the scenario where all Tags are removed (I'd like to prevent this). How can I ensure that a Task form always have at least 1 Tag?

4

3 回答 3

2

正如m0c所指出的,该解决方案确实是利用自定义验证约束。然而,我发现 Symfony2.1 中已经存在这样的约束验证器,所以我冒昧地将它移植到 2.0(因为某些接口在 2.1 中显然发生了变化)。

以下是Bernhard Schussek 的 Count.php移植版本(适用于 2.0)和CountValidator.php用于计数集合(参见https://github.com/symfony/Validator/tree/master/Constraints)。

计数.php

namespace MyVendor\MyBundle\Validator\Constraints;

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

/**
 * @Annotation
 *
 * @api
 */
class Count extends Constraint
{
    public $minMessage = 'This collection should contain {{ limit }} elements or more.';
    public $maxMessage = 'This collection should contain {{ limit }} elements or less.';
    public $exactMessage = 'This collection should contain exactly {{ limit }} elements.';
    public $min;
    public $max;

    public function __construct($options = null)
    {
        if (null !== $options && !is_array($options)) {
            $options = array(
                'min' => $options,
                'max' => $options,
            );
        }

        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'));
        }
    }
}

CountValidator.php

namespace MyVendor\MyBundle\Validator\Constraints;

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

class CountValidator extends ConstraintValidator
{
    /**
     * {@inheritDoc}
     */
    public function isValid($value, Constraint $constraint)
    {
        if (null === $value) {
            return false;
        }

        if (!is_array($value) && !$value instanceof \Countable) {
            throw new UnexpectedTypeException($value, 'array or \Countable');
        }

        $count = count($value);

        if ($constraint->min == $constraint->max
                && $count != $constraint->min) {
            $this->setMessage($constraint->exactMessage, array(
                '{{ count }}' => $count,
                '{{ limit }}' => $constraint->min,
            ));

            return false;
        }

        if (null !== $constraint->max && $count > $constraint->max) {
            $this->setMessage($constraint->maxMessage, array(
                '{{ count }}' => $count,
                '{{ limit }}' => $constraint->min,
            ));

            return false;
        }

        if (null !== $constraint->min && $count < $constraint->min) {
            $this->setMessage($constraint->minMessage, array(
                '{{ count }}' => $count,
                '{{ limit }}' => $constraint->min,
            ));

            return false;
        }

        return true;
    }
}
于 2012-09-05T06:01:40.830 回答
1

我将创建一个自定义验证器,它检查关系商店在实体级别上映射到的属性是否在集合中具有某些元素。

验证器失败:

   public function isValid($value, Constraint $constraint)
    {
        if (count($value) <1 ) {
            //also define a message for your custom validator
            $this->setMessage($constraint->message, array('%string%' => $value));
            return false;
        }
        return true;
    }

有关如何实现此自定义验证器的说明:http: //symfony.com/doc/current/cookbook/validation/custom_constraint.html

于 2012-09-03T11:47:29.583 回答
1

您是否只想在发布时验证,是否至少有 1 个标签,

还是您希望表单在加载时实际上已经有 1 个空标签?(我假设是因为你说“我怎样才能确保任务表单总是至少有 1 个标签?”

如果你需要第二个,就

$tag1 = new Tag();
$tag1->name = 'tag1';
$task->getTags()->add($tag1);

$form = $this->createForm(new TaskType(), $task);

就像文档说的那样..

于 2012-09-04T12:12:12.610 回答