结合约束条件和数据转换器

12

我希望能够做出类似于Symfony教程中使用数据转换器的方法,但我想添加一个步骤,但找不到任何示例。

在Symfony教程中,数据转换是将问题编号更改为Issue对象,这是在IssueToNumberTransformerreverseTransform()函数中完成的。

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。因此,表单会显示错误消息"This value is not valid"。个性化此消息将是很好的。

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

另一个需要在转换之前进行验证的例子是,我使用MongoDB文档管理器将"Issue mongo id"转换为一个Issue(该表单由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是否正确,那么就好像我在转换器中进行了验证,但这是不正确的。

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


你尝试过在执行$form->handleRequest时,用try/catch块包围它吗? - saamorim
由于表单组件会吞噬任何DataTransformer错误,因此try/catch将无法工作。请检查代码。事实上,转换是用于转换而不是验证。因此,在转换操作期间不要尝试进行验证。您需要在验证中检查空问题。 - Cerad
我之前说我的响应是500是错误的。我有一个表单错误,只提示“该值无效”。你说的“您需要检查验证中的空问题”是什么意思? - maphe
我编辑了问题,并添加了第二个示例,以展示为什么我必须在转换之前验证数据。 - maphe
1个回答

10

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

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

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

在变压器中,如果给定的值无效,则返回InvalidIssue对象而不是抛出异常。

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

我验证了答案,这是一个非常好的想法... 希望Symfony有一天能够升级其验证系统以支持这种情况。谢谢。 - maphe
不错的解决方案!我不明白为什么Symfony会忽视这个。 - shapeshifter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接