Quantcast
Channel: Active questions tagged symfony4 - Stack Overflow
Viewing all articles
Browse latest Browse all 3925

Data Transformer vs.Constraints

$
0
0

I stumbled upon a question regarding Symfony's DataTransformers and how to properly use them. While I know how to implement and add them to my form field, I was wondering how DataTransformers are supposed to be combined with Constraints.

The following code shows my use case.

The Form

<?phpnamespace 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);    }}

The Model

<?phpclass User extends Concrete implements \Pimcore\Model\DataObject\DirtyIndicatorInterface{    protected $accountConsent;    /**     * ...     */    public function getAccountConsent () {        // ...    }    /**     * ...     */    public function setAccountConsent ($accountConsent) {        // ...    }}

A lot of code was omitted for the sake of brevity. The model is a Pimcore class.

The DataTransformer

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

As you can see any submitted value (i.e., null, true, false) will be converted to a Consent and vice-versa.

The Controller

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

Note how a new User() is passed as entity in order to automatically populate it with the submitted values.

The View

{{ form(form) }}

The Problem

The form can be built just fine, ultimately, displaying a checkbox with my specified label. Due to the transformer, the checked-state is even correctly displayed, as the transform method converts the Users Consent into a boolean.

However, when submitting the form, an error is displayed, saying that the account-consent is required. While this is fine when it comes to submitting the form without giving consent, it's not quite the desired outcome when acutally consenting.

When consenting, the submitted value is converted to a Consent, which will then hold the value true. But since the transformation is done before the submitted value is validated the beforementioned error is displayed. This happens, because the accountConsent field that was added in the form has a Constraint set, namely, IsTrue. Due to this, the IsTrueValidator validates the Consent (instead of the actually submitted value).

Obviously, the IsTrueValidator cannot know about Pimcore's Consent class.

The Question

All of this leaves me with the question: how do I properly combine the IsTrue-constraint with my ConsentDataTransformer?


Viewing all articles
Browse latest Browse all 3925

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>