2

I have some difficulties about applying validation for only one associated entity.

So I have two entities, News and NewsTranslation. A news could be translated in multiple languages. But I would like to apply validation only if locale is en.

// AppBundle/Entity/News.php
class News
{
    use ORMBehaviors\Translatable\Translatable;
    use ORMBehaviors\Timestampable\Timestampable;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     *
     * @ORM\Column(name="status", type="smallint")
     * @Assert\NotBlank
     */
    private $status;

    ...
}
// AppBundle/Entity/NewsTranslation.php
class NewsTranslation
{
    use ORMBehaviors\Translatable\Translation;

    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255, nullable=true)
     * @Assert\NotBlank
     * @Assert\Length(max = 255)
     */
    private $title;

    /**
     * @var string
     *
     * @ORM\Column(name="text", type="string", nullable=true)
     * @Assert\NotBlank
     */
    private $text;
}
# AppBundle/Resources/config/validation.yml
AppBundle\Entity\News:
    properties:
        translations:
            - Valid: ~

I tried to use a Closure for the validation_groups form option. But it looks like Symfony do validation on News entity and Valid constraint apply the same groups on NewsTranslation.

I know I could use Callback constraint but that's mean to redo NotBlank, Length and other exiting constraints by myself. And I would like to avoid it if possible.

EDIT:

I'm using Symfony 2.8.*

I try using an en validation group. But looks like the validation is launch on News entity with validation_groups. And with Valid constraint the en validation group is given to validate NewsTranlation. So even it's the en or fr translation the group change nothing in this case.

I also try using the validation medatada through an @Assert\Callback or by using loadValidatorMetadata method into NewsTranslation entity. And the problem stay similar. I can't apply an constraint for a specific entity of collection.

2 Answers 2

2

I finally found a way by creating a custom validator. Like this I could use core constraints easily.

In the translation entity, I could use my validator like this:

/**
 * @var string
 *
 * @ORM\Column(name="title", type="string", length=255, nullable=true)
 * @Assert\Length(max = 255)
 * @AppAssert\ValidTranslation(locales = {"fr"}, constraints = {
 *      @Assert\NotBlank
 * })
 */
private $title;

And the validator:

<?php

namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraints\Composite;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD", "ANNOTATION"})
 *
 * @author Nicolas Brousse
 */
class ValidTranslation extends Composite
{
    public $locales     = array();
    public $constraints = array();

    public function getCompositeOption()
    {
        return 'constraints';
    }

    public function getRequiredOptions()
    {
        return array('locales', 'constraints');
    }
}
<?php

namespace AppBundle\Validator\Constraints;

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

/**
 * @author Nicolas Brousse
 */
class ValidTranslationValidator extends ConstraintValidator
{
    /**
     * If property constraint
     * {@inheritdoc}
     */
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint instanceof ValidTranslation) {
            throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\ValidTranslation');
        }

        if (false) { // @todo check by interface or trait
            throw new UnexpectedTypeException($value, 'not a translation entity');
        }

        $context = $this->context;
        $entity  = $this->context->getObject();

        if (in_array($entity->getLocale(), $constraint->locales)) {
            $context = $this->context;

            if ($context instanceof ExecutionContextInterface) {
                $validator = $context->getValidator()->inContext($context);
                $validator->validate($value, $constraint->constraints);
            } else {
                // 2.4 API
                $context->validateValue($value, $constraint->constraints);
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

you form need to return 2 validations_groups, "Default" and the validation group corresponding to the "en" locale

1 Comment

Yes, but by creating an en group validation it will applying for all. I'm currently looking to use loadValidatorMetadata property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.