Symfony3.4: динамическая регистрационная форма

Я немного новичок в Symfony, поэтому мне сложно работать с динамическими формами. Я пытаюсь сохранить своих пользователей в базе данных и геокодировать их адрес при отправке формы.

Это мой пользовательский объект:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

use FOS\UserBundle\Model\User as BaseUser;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 */
class User extends BaseUser
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=255)
     *
     * @Assert\NotBlank(message="Veuillez inscrire votre prénom.", groups={"Registration", "Profile"})
     * @Assert\Length(
     *     min=3,
     *     max=255,
     *     minMessage="The name is too short.",
     *     maxMessage="The name is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $firstname;

    /**
     * @var string
     *
     * @ORM\Column(name="lastname", type="string", length=255,nullable=true)
     */
    protected $lastname;

    /**
     * @var string
     *
     * @ORM\Column(name="address", type="string", length=255, nullable=true)
     */
    protected $address;

    /**
     * @var string
     *
     * @ORM\Column(name="zipcode", type="string", length=10, nullable=true)
     */
    protected $zipcode;

    /**
     * @var string
     *
     * @ORM\Column(name="city", type="string", length=255, nullable=true)
     */
    protected $city;

    /**
     * @var string
     *
     * @ORM\Column(name="country", type="string", length=255, nullable=true)
     */
    protected $country;

    /**
     * @var string
     *
     * @ORM\Column(name="latitude", type="string", length=255, nullable=true)
     */
    protected $latitude;

    /**
     * @var string
     *
     * @ORM\Column(name="longitude", type="string", length=255, nullable=true)
     */
    protected $longitude;


    public function __construct()
    {
        parent::__construct();

        $this->enabled = false;
        $this->roles = array();
        $this->inscriptiondate = new \Datetime();
    }

    /**
     * Set firstname
     *
     * @param String $firstname
     * @return User
     */
    public function setFirstName($firstname)
    {
        $this->firstname = $firstname;

        return $this;
    }

    /**
     * Get lastname
     *
     * @return String
     */
    public function getLastName()
    {
        return $this->lastname;
    }

    /**
     * Set lastname
     *
     * @param String $lastname
     * @return User
     */
    public function setLastName($lastname)
    {
        $this->lastname = $lastname;

        return $this;
    }

    /**
     * Set address
     *
     * @param string $address
     *
     * @return User
     */
    public function setAddress($address)
    {
        $this->address = $address;

        return $this;
    }

    /**
     * Get address
     *
     * @return string
     */
    public function getAddress()
    {
        return $this->address;
    }

    /**
     * Set zipcode
     *
     * @param string $zipcode
     *
     * @return User
     */
    public function setZipCode($zipcode)
    {
        $this->zipcode = $zipcode;

        return $this;
    }

    /**
     * Get zipcode
     *
     * @return integer
     */
    public function getZipCode()
    {
        return $this->zipcode;
    }

    /**
     * Set city
     *
     * @param string $city
     *
     * @return User
     */
    public function setCity($city)
    {
        $this->city = $city;

        return $this;
    }

    /**
     * Get city
     *
     * @return string
     */
    public function getCity()
    {
        return $this->city;
    }

    /**
     * Set country
     *
     * @param string $country
     *
     * @return User
     */
    public function setCountry($country)
    {
        $this->country = $country;

        return $this;
    }

    /**
     * Get country
     *
     * @return string
     */
    public function getCountry()
    {
        return $this->country;
    }

    /**
     * Set latitude
     *
     * @param string $lat
     *
     * @return User
     */
    public function setLatitude($latitude)
    {
        $this->latitude = $latitude;

        return $this;
    }

    /**
     * Get latitude
     *
     * @return string
     */
    public function getLatitude()
    {
        return $this->latitude;
    }

    /**
     * Set longitude
     *
     * @param string $longitude
     *
     * @return User
     */
    public function setLongitude($longitude)
    {
        $this->longitude = $longitude;

        return $this;
    }

    /**
     * Get longitude
     *
     * @return string
     */
    public function getLongitude()
    {
        return $this->longitude;
    }
}

Это моя регистрационная форма:

<?php
// src/AppBundle/Form/RegistrationType.php

namespace AppBundle\Form;

use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use UserBundle\Repository\GenderRepository;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

use Doctrine\ORM\EntityRepository;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class RegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);

        $builder
            ->add('firstname', TextType::class, array(
                'label' => 'First name'))
            ->add('lastname', TextType::class, array(
                'label' => 'Last name'))
            ->add('address')
            ->add('zipcode')
            ->add('city')
            ->add('country');

        $builder->addEventListener(
            FormEvents::SUBMIT,
            function (FormEvent $event) {
                $form = $event->getForm();

                $data = $event->getForm()->getData();

                $address = $data->getAddress();
                $zipcode = $data->getZipCode();
                $city = $data->getCity();
                $country = $data->getCountry();
                $fulladdress = urlencode($address)."+".$zipcode."+".$city."+".$country;
                $geocode = file_get_contents('https://maps.googleapis.com/maps/api/geocode/json?address='.$fulladdress.'&key=KEY');
                $output = json_decode($geocode);
                $latitude = $output->results[0]->geometry->location->lat;
                $longitude = $output->results[0]->geometry->location->lng;

                dump($fulladdress); // Works fine, I see full address in dump

                $form->add('latitude', HiddenType::class, array('data' => $latitude))
                     ->add('longitude', HiddenType::class, array('data' => $longitude)); // Does not save data in database
            }
        );
    } 

    public function getParent()
    {
        return 'FOS\UserBundle\Form\Type\RegistrationFormType';
    }

    public function getBlockPrefix()
    {
        return 'app_user_registration';
    }
}

Для первых тестов я прописал статический адрес в $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event), все заработало нормально, геокод снова выглядит хорошо.

Когда я попытался получить адрес динамически из входных данных формы и отобразить форму, я получил: Ошибка: вызов функции-члена getAddress() при нулевом значении

Похоже, что $address = $data->getAddress(); возвращает NULL, поскольку форма не была отправлена, когда мы смотрим на FormEvents::PRE_SET_DATA. Я пытался играть с другими событиями, но не могу заставить его работать.

Когда я пытаюсь поместить его в FormEvents::PRE_SUBMIT, форма отображается нормально, но при отправке я получаю: Ошибка: вызов функции-члена getAddress() в массиве

Когда я пытаюсь поместить его в FormEvents::SUBMIT, форма отображается нормально, отправка в порядке, ошибок нет, но столбцы широты и долготы в базе данных имеют значение NULL.

Я также попробовал $address = $data['address']; вместо $address = $data->getAddress();, но не лучше.

Это всего лишь мой второй проект на Symfony, так что совсем не специалист. Что мне не хватает? Любая помощь будет действительно оценена.


person David    schedule 05.03.2018    source источник


Ответы (1)


Проблема есть:

            $form = $event->getForm();
            $data = $form ->getData();

Вы должны загрузить данные из формы.

Ошибка, которую вы получили для адреса, не означает, что GetAddress() вернуло null, но что $data является null, и вы не можете получить доступ к членам переменной null.

Изменить:

По той же ссылке, что и в комментарии:

            // It's important here to fetch $event->getForm()->getData(), as
            // $event->getData() will get you the client data (that is, the ID)
            $sport = $event->getForm()->getData();
person Alex Dupuis    schedule 05.03.2018
comment
Спасибо за вклад, я лучше посмотрю на это. К сожалению, я взял эти 2 строки из документации Symfony, поэтому я думаю, что мне будет довольно трудно понять, где я ошибаюсь. Я также немного потерялся, над каким FormEvent я должен работать. - person David; 05.03.2018
comment
Действительно, спасибо, но я попытался изменить $data = $form -›getData(); на $data = $event-›getForm()-›getData() ; или вызовите напрямую $address = $event-›getForm()-›getData()-›getAddress();, но это все еще NULL, думаю, мне придется прочитать все doc опять совсем не вникал. - person David; 05.03.2018
comment
Похоже, $form-›add(.. не работает в FormEvents::SUBMIT, так как скрипт возвращает NULL со статическим адресом, который работал в FormEvents ::PRE_SET_DATA. - person David; 05.03.2018
comment
В данный момент у меня нет доступа к моим проектам Symfony, чтобы помочь вам больше, но проблема в этой строке, по какой-то причине getData() возвращает null. - person Alex Dupuis; 05.03.2018
comment
Я понимаю, спасибо за ваши усилия. Может быть, мне следует попробовать что-то вроде setData() вместо $form-›add(.. .. - person David; 05.03.2018
comment
Я не могу понять, что здесь не так, благодаря вашей помощи я вижу, что использование $data = $event-›getForm()-›getData(); в FormEvents::SUBMIT показывает правильную информацию, если я dump($fulladdress);. Но он все еще не хранится в базе данных. Я обновляю свой код в первом вопросе. - person David; 05.03.2018
comment
Если я прочитаю документацию, Я не могу добавить поля в SUBMIT, уже слишком поздно. Но данные NULL до SUBMIT, вот почему я застрял. Снова чтение всего этого приводит меня к тому, что в PRE_SUBMIT данные еще не формализованы, поэтому $address = $data-›getAddress();< /b> не может работать, я прав? - person David; 05.03.2018
comment
Извините за беспокойство, но это сводит меня с ума. Выполнив некоторые тесты, последняя точка, на которой я могу добавить поля, — это FormEvents::POST_SET_DATA, а самая ранняя стадия, на которой я могу получить свои динамические данные, — FormEvents::SUBMIT. - person David; 05.03.2018
comment
ОК, я наконец получил это !! Я остался в FormEvents::SUBMIT и заменил $form-›add('latitude', HiddenType::class, array('data' =› $latitude)); с помощью $data-›setLatitude($latitude);. Не знаю, лучший ли это способ, но он работает, еще раз спасибо за вашу помощь. - person David; 05.03.2018