Symfony: динамическое изменение поля формы вызывает исключение для существующего объекта - PullRequest
0 голосов
/ 03 декабря 2018

Я пытаюсь создать форму, которая создает новое уведомление, которое может быть связано с:

  • Существующим Vecino
  • Новым Vecino
  • Нетиз вышеупомянутого

И Vecino связан с Domicilio

Также у меня есть ModeloImpresion, который зависит от поля Area (оба из Notificacion)

Что я хочучтобы сделать это форма, где я создаю Notificacion с полем Area, который изменяет поле ModeloImpresion.Итак, я выполнил шаги на https://symfony.com/doc/3.4/form/dynamic_form_modification.html#form-events-submitted-data

Если я создаю один без Vecino, он работает, если я создаю новый Vecino, он работает, но когда мне нужно создать его с существующим Vecino, AJAX завершается неудачей со следующим исключениемпри обработке запроса (у сущностей есть другие поля, не связанные с ошибкой, поэтому я их не копировал):

Type error: Argument 1 passed to Proxies\__CG__\Brown\TurnoBundle\Entity\Vecino\Domicilio::setCalle() must be of the type string, null given, called in /home/gonchi/web/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 623

Я проверял, и если я сбрасываю Notificacion, он имеет правильное Vecino с правильным Domicilioэто определил колл.

Я не знаю, где это идет не так

Схема отношений:

class Notificacion
{
    /**
     * @var null|Vecino
     *
     * @ORM\ManyToOne(targetEntity="Brown\TurnoBundle\Entity\Vecino")
     */
    private $vecino;

    /**
     * @var Area|null
     *
     * @ORM\ManyToOne(targetEntity="Brown\BrownBundle\Entity\Area")
     */
    private $area;

    /**
     * @var DatosFijos\ModeloImpresion|null
     *
     * @ORM\ManyToOne(targetEntity="Brown\BrownBundle\Entity\DatosFijos\ModeloImpresion")
     */
    private $modeloImpresion;
}

class Vecino
{
    /**
     * @var null|Domicilio
     *
     * @ORM\ManyToOne(targetEntity="Brown\TurnoBundle\Entity\Vecino\Domicilio", cascade={"persist", "remove"})
     */
    private $domicilio;
}

Вот мой контроллер:

/**
 * @param Request $request
 *
 * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
 */
public function nuevoAction(Request $request)
{
    // This comes from a search on the repository. 
    // If it finds a Vecino it returns the object.
    // If it didn't find one it returns null.
    // If this Notificacion shouldn't have a Vecino it returns false
    $vecino = $this->getSessionVariable(Constants::SESSION_VECINO);

    $notificacion = new Notificacion();

    // If there should be a Vecino but didn't find one it creates one
    if ($vecino === null) {
        $vecino = new Vecino();
        $vecino->setDni($this->getSessionVariable(Constants::SESSION_DNI_CUIL));
    }

    // If there's a Vecino (existing or new) it sets it to the Notificacion
    if ($vecino) {
        $notificacion->setVecino($vecino);
    }

    $form = $this->createForm(NuevoType::class, $notificacion);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        // A shortcut to $this->getEm()->persist()
        $this->saveToDatabase($notificacion);

        return $this->redirectToRoute('admin_notificacion_listado');
    }

    return $this->render('@Admin/Notificacion/nuevo.html.twig', [
        'form' => $form->createView(),
    ]);
}

Имоя форма:

class NuevoType extends AbstractType
{
    /**
     * @var AreaRepository|\Doctrine\ORM\EntityRepository
     */
    private $areaRepository;

    /**
     * @var \Brown\BrownBundle\Repository\DatosFijos\ModeloImpresionRepository | \Doctrine\ORM\EntityRepository
     */
    private $modeloImpresionRepository;

    public function __construct(EntityManager $entityManager)
    {
        $this->areaRepository            = $entityManager->getRepository(Area::class);
        $this->modeloImpresionRepository = $entityManager->getRepository(ModeloImpresion::class);
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Check so it only add it if there should be one
        if ($builder->getData()->getVecino()) {
            $builder->add('vecino', VecinoMinimoType::class, [
                'label' => false,
            ]);
        }


        $builder
            ->add('area', EntityType::class, [
                'class'        => Area::class,
                'choice_label' => 'nombre',
                'query_builder' => function (AreaRepository $er) {
                    return $er->createQueryBuilder('a')
                        ->orderBy('a.nombre', 'ASC');
                },
                'placeholder' => 'Seleccione el área',
                'attr' => ['class' => 'area-entity']
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Guardar',
                'attr'  => ['class' => 'btn btn-primary'],
            ])
        ;

        $formModifier = function (FormInterface $form, Area $area = null) {
            $modelosImpresion = null === $area ? [] : $this->modeloImpresionRepository->findByAreas([$area]);

            $form->add('modeloImpresion', EntityType::class, [
                    'label'   => 'Tipo de Notificación',
                    'class'   => ModeloImpresion::class,
                    'choices' => $modelosImpresion,
                    'attr' => ['class' => 'modeloImpresion-entity'],
            ]);
        };


        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) {
            /** @var Notificacion $notificacion */
            $notificacion = $event->getData();
            $form = $event->getForm();

            $formModifier($event->getForm(), $notificacion->getArea());
        });



        $builder->get('area')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                $area = $event->getForm()->getData();
                $formModifier($event->getForm()->getParent(), $area);
            }
        );

    }

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

и наконец Javascript на мой взгляд:

<script>
    var area = $('.area-entity');

    area.change(function() {
        var form = $(this).closest('form');
        var data = {};
        data[area.attr('name')] = area.val();
        $.ajax({
            url : form.attr('action'),
            type: form.attr('method'),
            data : data,
            success: function(html) {
                var modeloImpresion = $('.modeloImpresion-entity');
                modeloImpresion.replaceWith(
                    $(html).find('.modeloImpresion-entity')
                );
            },
        });
    });
</script>
...