I added an autocomplete field to the RegistrationFormType (FOSUserBundle) by using IvoryGoogleMapBundle.
An User can have one Address => OneToOne relation
I created a Datatransformer to Transform Autocomplete field (array) to an Address entity by following the Symfony documentation but seems that I missed something :(
I have the following error: The required option "em" is missing.
sw/UserBundle/Entity/User.php
class user extends BaseUser
{
/**
* @ORM\OneToOne(targetEntity="sw\BlogBundle\Entity\Address", cascade={"persist"})
* @ORM\JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
/**
* Set address
*
* @param \sw\BlogtBundle\Entity\Address $address
* @return User
*/
public function setAddress(\sw\BlogBundle\Entity\Address $address = null)
{
$this->address = $address;
return $this;
}
/**
* Get address
*
* @return \sw\BlogBundle\Entity\Address
*/
public function getAddress()
{
return $this->address;
}
sw/BlogBundle/Entity/Address.php
class Address
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=10)
*/
private $zipcode;
/**
* @ORM\Column(type="string", length=45)
*/
private $city;
/**
* @ORM\Column(type="string", length=45)
*/
private $country;
sw/BlogBundle/Form/AutocompleteFromType.php
use Ivory\GoogleMap\Places\AutocompleteType;
use Ivory\GoogleMap\Places\AutocompleteComponentRestriction;
class MapFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('Ville','places_autocomplete', array(
'prefix' => 'js_prefix_',
'types' => array(AutocompleteType::CITIES),
'async' => false,
'language' => 'fr',
'component_restrictions' => array(
AutocompleteComponentRestriction::COUNTRY => 'FR'),
));
}
public function getName()
{
return 'sw_blog_autocomplete';
}
}
sw/UserBundle/Form/Type/RegistrationFormType.php
use sw\BlogBundle\Form\AutocompleteFormType;
use sw\BlogBundle\Form\DataTransformer\AutocompleteToAddressTransformer;
class RegistrationFormType extends AbstractType
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$entityManager = $options['em'];
$transformer = new AutocompleteToAddressTransformer($entityManager);
parent::buildForm($builder, $options);
$builder->add('username', 'text', array('label' => 'Pseudo :', 'max_length' => 10));
.........
$builder->add($builder->create('address', new MapFormType(), array('label' => 'Adresse :','required' => true))->addModelTransformer($transformer));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver
->setDefaults(array(
'data_class' => 'sw\UserBundle\Entity\User',
))
->setRequired(array(
'em',
))
->setAllowedTypes(array(
'em' => 'Doctrine\Common\Persistence\ObjectManager',
));
// ...
}
public function getName()
{
return 'sw_user_registration';
}
}
sw/BlogBundle/Form/DataTransformer/AutocompleteToAddressTransformer.php
use sw\BlogBundle\Entity\Address;
use Ivory\GoogleMap\Services\Geocoding\Geocoder as GeocoderService;
class AutocompleteToAddressTransformer implements DataTransformerInterface
{
/**
* @var ObjectManager
*/
private $om;
/**
* @param ObjectManager $om
*/
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
/**
* Transforms an array to a object (address).
*
* @param Array|null $autocomplete
* @return Address
*/
public function transform($autocomplete)
{
if (null === $autocomplete) {
return "";
}
$geocoder = new GeocoderService();
try {
$result = $geocoder->geocode($autocomplete);
var_export($result);
} catch (Exception $e) {
echo $e->getMessage();
}
$address = new Address();
$address->setCity($result->getCity());
$address->setCoutry($result->getCoutry());
$address->setZipcode($result->getZipcode());
return $address;
}
/**
* Transforms an object (Address) to an array.
*
* @param Address $address
*
* @return autocomplete|null
*
* @throws TransformationFailedException if array is not found.
*/
public function reverseTransform($address)
{
if (!$address) {
return null;
}
$autocomplete = $address->getCity. ' , ' .$address->getCountry;
return $autocomplete;
}
}
sw/UserBundle/Controller/RegistrationController.php
<?php
namespace sw\UserBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\RegistrationController as BaseController;
use Symfony\Component\HttpFoundation\Request;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use sw\UserBundle\Form\Type\RegistrationFormType;
class RegistrationController extends BaseController
{
public function registerAction(Request $request)
{
/** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->container->get('fos_user.registration.form.factory');
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
/** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->container->get('event_dispatcher');
$user = $userManager->createUser();
$user->setEnabled(true);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, new UserEvent($user, $request));
$form = $formFactory->createForm(new RegistrationFormType(), $user, array(
'em' => $this->container->get('doctrine')->getManager(),
));
$form->setData($user);
if ('POST' === $request->getMethod()) {
$form->bind($request);
if ($form->isValid()) {
$form->bind($request);
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->container->get('router')->generate('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
}
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
'form' => $form->createView(),
));
}
}
I don't know if it is the right and easiest way to save the Autocomplete field as Address entity...
Thank you for your help