问题 结合约束和数据转换器


我想做一些看起来像做的事情 如何使用数据变形金刚 教程。但我想添加一个过程,我找不到任何例子。

在symfony教程中,数据转换是关于将问题编号更改为 Issue 目的。这是在 reverseTransform() 的功能 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;
}

我们可以看到,如果提供了无效的问题编号,转换将失败并且函数抛出一个 TransformationFailedException。因此,表单作为错误消息“此值无效”。个性化这个消息会很棒。

数据转换过程在任何验证之前执行(使用约束应用于字段),因此在尝试转换之前,我找不到验证问题编号的方法。

作为我必须在转换之前验证的另一个例子,我使用MongoDB文档管理器将“问题mongo id”转换为问题(表单由REST API服务器使用,这就是我收到id的原因)。所以:

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

在这里,如果我在API表单中收到的id未被格式化为正确的MongoID,则客户端将收到500.所以我想检查,在转换之前如果收到的id是正确的,因为如果不是,转换将引发致命错误。如果我在转换中管理所有情况,比如检查$ id是否正确,就像我在变换器中进行验证并且它不正确。

我的问题是:有没有办法在数据转换之前应用约束?或者有没有办法在转换失败时在表单上添加摘要约束?


2980
2018-01-15 14:35


起源

你有没有尝试用try / catch块进行周围环境 $form->handleRequest ? - saamorim
try / catch将不起作用,因为表单组件将吞下任何DataTransformer错误。检查代码。问题是,转换是为了转换而不是验证。所以不要在转换操作期间尝试验证。您需要在验证中检查空问题。 - Cerad
我错误地说我的回答是500.我有一个表单错误只是告诉“这个值无效”。你是什​​么意思“你需要检查验证中的空问题”? - maphe
我编辑了这个问题,添加了第二个例子来说明为什么我必须在转换之前验证数据 - maphe


答案:


这就像一个解决方法,但我建议编写代表“无效问题”的类来个性化错误。

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

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

并且在变换器中,如果给定的值无效,则返回InvalidIssue Object而不是抛出异常。

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

然后,在您的模型上添加验证器。

/** 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());
        }
    }
}

9
2018-01-28 09:14



我验证了答案,这是一个非常好的主意...希望symfony有一天会升级其验证系统以支持这种情况。谢谢 - maphe
好的解决方案我不明白symfony如何忽视这一点。 - shapeshifter