Я наткнулся на вопрос о Symfony
DataTransformer
с и о том, как правильно их использовать. Хотя я знаю, как реализовать и добавить их в свое поле формы, мне было интересно, как DataTransformer
s должны сочетаться с Constraint
s .
код показывает мой вариант использования.
Форма
<?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);
}
}
Модель
<?php
class User extends Concrete implements \Pimcore\Model\DataObject\DirtyIndicatorInterface
{
protected $accountConsent;
/**
* ...
*/
public function getAccountConsent () {
// ...
}
/**
* ...
*/
public function setAccountConsent ($accountConsent) {
// ...
}
}
Много кода было опущено ради краткость. Модель представляет собой класс Pimcore .
DataTransformer
<?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;
}
}
. Как вы можете видеть любое представленное значение (т. Е. null
, true
, false
) будет преобразован в Consent
и наоборот.
Контроллер
<?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()
передается как сущность, чтобы автоматически заполнить его отправленными значениями.
Представление
{{ form(form) }}
Проблема
Проблема Форма может быть построена очень хорошо, в конечном счете, отображая флажок с моей указанной меткой. Благодаря преобразователю состояние checked
отображается даже правильно, так как метод transform
преобразует User
s Consent
в boolean
.
Однако при отправке формы отображается ошибка, говорящая о том, что требуется согласие учетной записи. Хотя это нормально, когда дело доходит до отправки формы без согласия, это не совсем желаемый результат, когда вы соглашаетесь с остальным.
При согласии представленное значение преобразуется в Consent
, который затем будет содержать значение true
. Но поскольку преобразование выполняется до проверки отправленного значения , отображается вышеупомянутая ошибка. Это происходит потому, что поле accountConsent
, добавленное в форму, имеет набор Constraint
, а именно IsTrue
. Из-за этого IsTrueValidator
проверяет Consent
(вместо фактически переданного значения).
Очевидно, IsTrueValidator
не может знать о классе Pimcore Consent
.
Вопрос
Все это оставляет меня с вопросом: как мне правильно объединить ограничение IsTrue
с моим ConsentDataTransformer
?