首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >数据变压器vs.Constraints

数据变压器vs.Constraints
EN

Stack Overflow用户
提问于 2020-03-21 15:20:32
回答 1查看 271关注 0票数 2

我偶然发现了一个关于S以及如何正确使用它们的问题。当我知道如何实现它们并将它们添加到我的表单字段时,我想知道DataTransformers应该如何与S组合。

下面的代码显示了我的用例。

形式

代码语言:javascript
复制
<?php

namespace AppBundle\Form;

use AppBundle\Form\DataTransformer\Consent\ConsentTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\IsTrue;

class ConsentTestForm extends AbstractType
{
    /** @var ConsentTransformer $consentTransformer */
    private $consentTransformer;

    /**
     * ConsentTestForm constructor.
     * @param ConsentTransformer $consentTransformer
     */
    public function __construct(ConsentTransformer $consentTransformer)
    {
        $this->consentTransformer = $consentTransformer;
    }

    /**
     * @inheritDoc
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('accountConsent', CheckboxType::class, [
            'constraints' => [
                new IsTrue()
            ]
        ]);
        $builder->get('accountConsent')->addModelTransformer($this->consentTransformer);

        $builder->add('submit', SubmitType::class);
    }
}

模型

代码语言:javascript
复制
<?php

class User extends Concrete implements \Pimcore\Model\DataObject\DirtyIndicatorInterface
{
    protected $accountConsent;

    /**
     * ...
     */
    public function getAccountConsent () {
        // ...
    }

    /**
     * ...
     */
    public function setAccountConsent ($accountConsent) {
        // ...
    }
}

为了简洁起见,省略了许多代码。模型是一个Pimcore类

The DataTransformer

代码语言:javascript
复制
<?php

namespace Passioneight\Bundle\FormBuilderBundle\Form\DataTransformer\Consent;

use Pimcore\Model\DataObject\Data\Consent;
use Symfony\Component\Form\DataTransformerInterface;

class ConsentTransformer implements DataTransformerInterface
{
    /**
     * @inheritDoc
     * @param Consent|null $consent
     */
    public function transform($consent)
    {
        return $consent instanceof Consent && $consent->getConsent();
    }

    /**
     * @inheritDoc
     * @param bool|null $consented
     */
    public function reverseTransform($consented)
    {
        $consent = new Consent();
        $consent->setConsent($consented ?: false);
        return $consent;
    }
}

如您所见,任何提交的值(即nulltruefalse)都将转换为Consent,反之亦然。

主计长

代码语言:javascript
复制
<?php

namespace AppBundle\Controller;

use AppBundle\Form\ConsentTestForm;
use AppBundle\Model\DataObject\User;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class TestController
 * @package AppBundle\Controller
 *
 * @Route("/test")
 */
class TestController extends AbstractFrontendController
{
    /**
     * @Route("/form")
     * @param Request $request
     * @return Response
     */
    public function formAction(Request $request)
    {
        $user = new User();

        $form = $this->createForm(ConsentTestForm::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted()) {
            if ($form->isValid()) {
                p_r("VALID");
                p_r($user);
            } else {
                p_r("NOT VALID");
            }
        };

        return $this->renderTemplate(':Test:form.html.twig', [
            "form" => $form->createView()
        ]);
    }
}

注意如何将new User()作为实体传递,以便使用提交的值自动填充它。

视点

代码语言:javascript
复制
{{ form(form) }}

问题

表单可以很好地构建,最终显示带有我指定标签的复选框。由于转换器,checked-state甚至被正确显示,因为transform方法将UserConsent转换为boolean

然而,当提交表单时,会显示一个错误,说明需要帐户同意.虽然这在没有征得同意的情况下提交表单是很好的,但如果同意的话,这并不完全是理想的结果。

当同意时,提交的值将转换为Consent,后者将保存值true。但是,由于转换是在验证提交的值之前完成的,因此会显示前面提到的错误。之所以会发生这种情况,是因为表单中添加的accountConsent字段有一个Constraint集,即IsTrue。因此,IsTrueValidator验证Consent (而不是实际提交的值)。

显然,IsTrueValidator不能知道Pimcore的Consent类。

问题

所有这些都给我留下了一个问题:如何将IsTrue**-constraint与** ConsentDataTransformer**?**恰当地结合在一起?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-08 11:51:32

验证的问题在于,您试图将对象验证为布尔类型。在提交表单时,总是在尝试验证和转换时执行约束。因此,您已经转换了数据,这就是为什么IsBool验证失败的原因,因为该值的类型是同意对象,而不是布尔值。

要解决这个问题,您必须创建覆盖IsTrue的新验证约束。

代码语言:javascript
复制
<?php

namespace App\Form\Validator;

use Symfony\Component\Validator\Constraints\IsTrue;

class IsConsented extends IsTrue
{
    public $message = 'You need to consent!';
}

以及同一名称空间上的验证器;

代码语言:javascript
复制
<?php

namespace App\Form\Validator;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\IsTrueValidator;

class IsConsentedValidator extends IsTrueValidator
{
    public function validate($value, Constraint $constraint)
    {
        return parent::validate($value->getConsent(), $constraint);
    }
}

然后,您需要使用IsTrue更改IsConsented约束,如下所示;

代码语言:javascript
复制
<?php

namespace App\Form;

use App\Entity\User;
use App\Form\DataTransformer\ConsentTransformer;
use App\Form\Validator\IsConsented;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ConsentTestFormType extends AbstractType
{
    /** @var ConsentTransformer $consentTransformer */
    private $consentTransformer;

    /**
     * ConsentTestForm constructor.
     * @param ConsentTransformer $consentTransformer
     */
    public function __construct(ConsentTransformer $consentTransformer)
    {
        $this->consentTransformer = $consentTransformer;
    }

    /**
     * @inheritDoc
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('accountConsent', CheckboxType::class, [
            'constraints' => [
                new IsConsented()
            ]
        ]);
        $builder->get('accountConsent')->addModelTransformer($this->consentTransformer);

        $builder->add('submit', SubmitType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

就是这样。你的表格现在有效了。输出应该看起来像;

代码语言:javascript
复制
FormController.php on line 30:
"VALID"
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60789560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档