My wish
I want a independent form type for my Location
entity which I can add everywhere I want. When it's null then it should be null and not an empty Location
.
Current problem
My problem is either that when I submit null
then the previous set location will be used or when I fixed this issue its that the location is duplicated and not unique.
Base code
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Location::class,
'by_reference' => false
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('place_id', null, ['property_path' => 'placeId'])
->add('latitude')
->add('longitude')
->add('description')
;
// [...] See below examples [...]
}
My tries
EventListener
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event)
{
// $event->setData($this->locationRepository->find(19));
// $event->getForm()->setData($this->locationRepository->find(17));
// /** @var Location $value */
$value = $event->getData();
// var_dump(1, $value, $event->getForm()->getData()->getId());
$location = null;
if ($value)
{
$location = $this->locationRepository->findOneBy(['latitude' => $value->getLatitude(), 'longitude' => $value->getLongitude()]);
// var_dump('Location found', $location->getId());
if(!$location)
{
var_dump('-------------------- NEW LOCATION ----------------------------');
$location = new Location();
$location->setLongitude($value->getLongitude());
$location->setLatitude($value->getLatitude());
$location->setDescription($value->getDescription());
$location->setPlaceId($value->getPlaceId());
}
// $event->setData($location);
// $event->getForm()->setData($location);
}
$event->setData($location);
// var_dump($location->getId());
It's working perfect - but not when I want to set it to null
, because then it's ignored and the past location will be used.
Example {}
{}
OK because the location
was not submitted so it's ignored. $clearMissing = false
-> $form->submit($request->request->all(), false);
Example {"location": {"latitude": 12.0, "longitude": 99.0}}
{"location": {
"latitude": 12.0,
"longitude": 99.0
}}
OK because its creating new entity when lat/log isn't found and it reuses the existing entity when lat/lng is found.
Example {"location": null}
{"location": {
"latitude": 12.0,
"longitude": 99.0
}}
Wrong, here I expect that the location is null and not the parent one.
ModelTransformer
class UniqueLocationTransformer implements DataTransformerInterface
{
private $locationRepository;
public function __construct(LocationRepository $locationRepository)
{
$this->locationRepository = $locationRepository;
}
public function transform($value)
{
return $value;
}
public function reverseTransform($value)
{
if ($value)
{
$location = $this->locationRepository->findOneBy(['latitude' => $value->getLatitude(), 'longitude' => $value->getLongitude()]);
if($location)
{
return $location;
}
$location = new Location();
$location->setLongitude($value->getLongitude());
$location->setLatitude($value->getLatitude());
$location->setDescription($value->getDescription());
$location->setPlaceId($value->getPlaceId());
}
return $value;
}
}
It's working fine, too but even the problem with setting null.
Example {}
{}
OK because the location
was not submitted so it's ignored. $clearMissing = false
-> $form->submit($request->request->all(), false);
Example {"location": {"latitude": 12.0, "longitude": 99.0}}
{"location": {
"latitude": 12.0,
"longitude": 99.0
}}
OK because its creating new entity when lat/log isn't found and it reuses the existing entity when lat/lng is found.
Example {"location": null}
{"location": {
"latitude": 12.0,
"longitude": 99.0
}}
Wrong, here I expect that the location is null and not the parent one.
Doctrine prePersist
listener
Here the problem is that it's not called for updates and it's not so good because its out of the type scope.
Update 17.7. 18:03 (gmt+2)
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event)
{
$value = $event->getData();
$location = null;
if (is_array($value) && array_key_exists('latitude', $value))
{
$location = $this->locationRepository->findOneBy(['latitude' => $value['latitude'], 'longitude' => @$value['longitude'] || 0]);
if(!$location)
{
$location = new Location();
$location->setLongitude(array_key_exists('longitude', $value) ? $value['longitude'] : null);
$location->setLatitude(array_key_exists('latitude', $value) ? $value['latitude'] : null);
$location->setDescription(array_key_exists('description', $value) ? $value['description'] : null);
$location->setPlaceId(array_key_exists('place_id', $value) ? $value['place_id'] : null);
}
}
var_dump($location);
$event->setData($location);
});
I changed the event listener now so that its listening on PRE_SUBMIT
and added option required
which is set to false
.
But then I'm getting an error when submitting something valid.
Request:
{"location": {"latitude": 13, "longitude": 14}}
Response:
{
"location": [
"This value is not valid."
]
}
:(