<?php
namespace App\Form\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use App\Entity\Country;
use App\Entity\County;
use GeoNames\Client as GeoNamesClient;
use Symfony\Component\HttpKernel\KernelInterface;
use App\Service\ConfigDataService;
use GuzzleHttp\Exception\ClientException;
class DynamicFieldsSubscriber implements EventSubscriberInterface
{
/** KernelInterface $appKernel */
private $appKernel;
private $configDataService;
public function __construct(KernelInterface $appKernel, ConfigDataService $configDataService)
{
$this->appKernel = $appKernel;
$this->configDataService = $configDataService;
}
public static function getSubscribedEvents(): array
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmitData',
];
}
/**
* Handling form fields before form renders.
* @param FormEvent $event
*/
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
//dd($data);
$country = null;
if($data != null) {
$country = $data->getCountry();
//dd($data->getCountry());
}
$this->addCountyData($form, $country);
}
/**
* Handling form fields before form renders.
* @param FormEvent $event
*/
public function preSubmitData(FormEvent $event)
{
$location['country'] = $event->getData();
//dd($event->getData());
if(!empty($location['country'] && array_key_exists('country', $location['country']))) {
//dd($location);
$countryObj = new Country();
$countryObj->setName($location['country']['country']);
//dd($country);
$this->addCountyData($event->getForm(), $countryObj);
} else if (!empty($location['country']['county'])) {
$country = null;
$countyGeoId = $location['country']['county'];
//dd($countyGeoId);
$this->addCityData($event->getForm(), $countyGeoId);
}
}
/**
* Method to Add State Field. (first dynamic field.)
* @param FormInterface $form
* @param type $county
*/
private function addCountyData(FormInterface $form, Country $country = null) {
$countiesArray = [];
if($country != null && $country->getName() != 'RO') {
$geoNameUser = $this->configDataService->get('geonames');
$geoNamesClient = new GeoNamesClient($geoNameUser);
try {
[$countryGeoNames] = $geoNamesClient->countryInfo([
'country' => $country->getName(),
]);
if($countryGeoNames) {
$countryName = $countryGeoNames->geonameId;
$countiesJson = $geoNamesClient->children(['geonameId' => $countryName]);
foreach($countiesJson as $countyJson) {
$countiesArray[$countyJson->toponymName] = $countyJson->geonameId;
}
}
}
catch (ClientException $e) {
if($e->getCode() == '401') {
//dd($e->getMessage());
};
// Throw a custom exception here and handle this in your controller,
// to show an error message to the user
// throw new Exception(sprintf('Cannot change the state of the event, because %s', $e->getMessage()), 0, $e);
}
} else if($country != null && $country->getName() == 'RO') {
$regions = json_decode(file_get_contents($this->appKernel->getProjectDir() . '/assets/json/ro_regions.json'));
foreach ($regions as $key=>$regionName) {
$keyLower = mb_strtolower($key, 'UTF-8');
$keyLowerUpper = ucfirst($keyLower);
$countiesArray[$keyLowerUpper] = $keyLowerUpper;
}
}
$counties = null === $countiesArray ? [] : $countiesArray;
$form->add('county', ChoiceType::class, [
'placeholder' => 'Choose an option',
'mapped' => false,
'label' => false,
//'required' => false,
'attr' => [
'class' => 'form-control mb-3'
],
'choices' => $counties,
// 'constraints' => [
// new NotBlank([
// 'message' => 'not null',
// ]),
// ],
// 'data' => 'Tirana',
]);
}
/**
* Method to Add State Field. (first dynamic field.)
* @param FormInterface $form
* @param type $city
*/
private function addCityData(FormInterface $form, $county = null) {
$citiesArray = [];
$county_number = preg_match('/\d/', $county);
if($county != null && $county_number == 1 ) {
$geoNameUser = $this->configDataService->get('geonames');
$geoNamesClient = new GeoNamesClient($geoNameUser);
$citiesJson = $geoNamesClient->children(['geonameId' => $county]);
foreach($citiesJson as $cityJson) {
$citiesArray[$cityJson->toponymName] = $cityJson->toponymName;
}
} else if($county != null && $county_number == 0) {
$regions = json_decode(file_get_contents($this->appKernel->getProjectDir() . '/assets/json/ro_regions.json'));
$citiesArray = [];
foreach ($regions as $key=>$cities2) {
$countyUp = mb_strtoupper($county, 'UTF-8');
if($key == $countyUp) {
foreach($cities2 as $city) {
$cityLower = strtolower($city->name);
$cityFirst = ucwords($cityLower);
//dd($cityFirst);
$citiesArray[$cityFirst] = $cityFirst;
}
}
}
}
$cities = null === $citiesArray ? [] : $citiesArray;
$form->add('city', ChoiceType::class, [
'placeholder' => 'Choose an option',
'mapped' => false,
'attr' => [
'class' => 'form-control'
],
'choices' => $cities,
'constraints' => [
new NotBlank([
'message' => 'not null',
]),
],
]);
}
}