Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine constraints and data transformers

I would like to do something looking like what is done in How to use Data Transformers tutorial. But I would like to add a process and I can't find any example.

In the symfony tutorial, data transformation is about changing an issue number to an Issue object. This is done in the reverseTransform() function of IssueToNumberTransformer

public function reverseTransform($number)
{
    if (!$number) {
        return null;
    }

    $issue = $this->om
        ->getRepository('AcmeTaskBundle:Issue')
        ->findOneBy(array('number' => $number))
    ;

    if (null === $issue) {
        throw new TransformationFailedException(sprintf(
            'An issue with number "%s" does not exist!',
            $number
        ));
    }

    return $issue;
}

We can see that if an invalid issue number is provided, transformation will failed and the function throw a TransformationFailedException. As a result, the form as an error with message "This value is not valid". It would be great to personalize this message.

The data transformation process is executed before any validation (with constraints applied to the field), so I can't find a way to validate the issue number before trying to transform it.

As another example of why I have to validate before transformation is I use the MongoDB Document Manager to convert the "Issue mongo id" to an Issue (the form is used by a REST API server, that's why I receive an id). So :

public function reverseTransform($id)
{
    if (!$number) {
        return null;
    }

    $issue = $this->dm
        ->getRepository('AcmeTaskBundle:Issue')
        ->find(new \MongoId($id))
    ;

    if (null === $issue) {
        throw new TransformationFailedException(sprintf(
            'An issue with number "%s" does not exist!',
            $number
        ));
    }

    return $issue;
}

Here, if the id I receive in my API form is not formated as correct MongoID, client will receive a 500. So I want to check, before transformation if received id is correct, because if it's not, transformation will throw a fatal error. And if I manage all cases in my transformation, like checking if $id is correct, it's like I'm doing validation in the transformer and it's not correct.

My question is : is there a way to apply constraints before the data transformation ? or is there a way to add a digest constraintViolation on the form when transformation failed ?

like image 261
maphe Avatar asked Jan 15 '14 14:01

maphe


1 Answers

This is like a workaround, however I suggest writing the class that represents "an invalid issue" to personalize error.

class InvalidIssue extends Issue
{
    public $message = 'This issue is invalid';

    public function __construct($message = null)
    {
        if (null !== $message) {
            $this->message = $message;
        }
    }
}

and in the transformer, if given value is invalid, return InvalidIssue object instead of throwing an exception.

public function reverseTransform($id)
{
    if (!$number) {
        return null;
    }

    $issue = $this->dm
        ->getRepository('AcmeTaskBundle:Issue')
        ->find(new \MongoId($id))
    ;

    if (null === $issue) {
        return new InvalidIssue(sprintf(
            'An issue with number "%s" does not exist!',
            $number
        ));
    }

    return $issue;
}

then, add validator onto your model.

/** Assert\Callback("callback"="validateIssueIsValid") */
class YourModel
{
    protected $issue;

    public function setIssue(Issue $issue)
    {
        $this->issue = $issue;
    }

    public function validateIssueIsValid(ExecutionContextInterface $context)
    {
        if ($this->issue instanceof InvalidIssue) {
            $context->addViolationAt('issue', $this->issue->message, array());
        }
    }
}
like image 98
denkiryokuhatsuden Avatar answered Oct 26 '22 05:10

denkiryokuhatsuden