<?php
// src/Form/RegistrationType.php
namespace App\Form;
use App\Service\SynchroHubService;
use App\Entity\Contact;
use App\Entity\User;
use App\Entity\Category;
use App\Entity\TypologieStructure;
use App\Repository\TypologieStructureRepository;
use Doctrine\ORM\EntityManagerInterface;
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaTrue;
use Sulu\Bundle\CategoryBundle\Entity\CategoryRepository;
use Sulu\Bundle\ContactBundle\Entity\Address;
use Sulu\Bundle\ContactBundle\Entity\AddressType;
use Sulu\Bundle\ContactBundle\Entity\ContactAddress;
use Sulu\Bundle\SecurityBundle\Entity\Role;
use Sulu\Bundle\SecurityBundle\Entity\UserRole;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class RegistrationType extends AbstractType
{
private $emi;
private $flashbag;
private $SynchroHubService;
const BUTTON_CSS_CLASS = 'CTA center';
const LABEL_ATTR_CSS_CLASS = 'fw400 fs14 lh20';
public function __construct(
EntityManagerInterface $emi,
FlashBagInterface $flashbag,
SynchroHubService $SynchroHubService
) {
$this->emi = $emi;
$this->flashbag = $flashbag;
$this->SynchroHubService = $SynchroHubService;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('firstName', TextType::class, [
'property_path' => 'contact.firstName',
'label' => 'Prénom *',
'required' => true,
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Prénom'],
'constraints' => [
new Assert\NotBlank(['message' => 'Le prénom est requis.']),
],
]);
$builder->add('lastName', TextType::class, [
'property_path' => 'contact.lastName',
'label' => 'Nom *',
'required' => true,
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Nom'],
'constraints' => [
new Assert\NotBlank(['message' => 'Le nom est requis.']),
],
]);
$builder->add('mainEmail', EmailType::class, [
'property_path' => 'contact.mainEmail',
'label' => 'Email *',
'required' => true,
'label_attr' => ["class" => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Email'],
'constraints' => [
new Assert\NotBlank(['message' => 'L\'email est requis.']),
new Assert\Email(['message' => 'L\'email doit être au format valide.']),
],
]);
$builder->add('avatar', FileType::class, [
'mapped' => false,
'property_path' => 'contact.avatar',
'required' => false,
'label_attr' => [
'class' => self::LABEL_ATTR_CSS_CLASS,
'id' => 'filelabel',
'tabindex' => 0
]
]);
$builder->add('number', TextType::class, [
'property_path' => 'contact.mainPhone',
'required' => true,
'label' => "Téléphone *",
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Téléphone']
]);
$builder->add('socialMediaProfiles', CollectionType::class, [
'property_path' => 'contact.socialMediaProfiles',
'entry_type' => SocialMediaType::class,
'allow_add' => true,
'allow_delete' => true,
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'label' => 'Vos réseaux sociaux',
'attr' => ['class' => 'dflex jcsb mt-1em']
]);
$builder->add('note', TextareaType::class, [
'property_path' => 'contact.note',
'required' => false,
'label' => 'Décrivez ce que vous faites / votre champs d\'action ',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Description', 'class' => 'br6']
]);
$builder->add('structure', TextType::class, [
'property_path' => 'contact.structure',
'required' => true,
'label' => 'Structure *',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Structure'],
'constraints' => [
new Assert\NotBlank(['message' => 'La structure est requise.']),
],
]);
$builder->add('structureText', TextType::class, [
'mapped' => false,
'required' => true,
'label' => 'Typologie de structure *',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Typologie de structure']
]);
$builder->add('zip', TextType::class, [
'property_path' => 'contact.mainAddress.zip',
'required' => true,
'label' => 'Code postal *',
'label_attr' => ["class" => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Code postal']
]);
$builder->add('street', TextType::class, [
'property_path' => 'contact.mainAddress.street',
'required' => true,
'label' => 'Adresse *',
'label_attr' => ["class" => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Adresse']
]);
$builder->add('city', TextType::class, [
'property_path' => 'contact.mainAddress.city',
'required' => true,
'label' => 'Ville *',
'label_attr' => ["class" => self::LABEL_ATTR_CSS_CLASS],
'attr' => ['placeholder' => 'Ville']
]);
$builder->add('typologieStructure', EntityType::class, [
'property_path' => 'contact.typologieStructure',
'class' => TypologieStructure::class,
'multiple' => false,
'expanded' => true,
'required' => false,
'placeholder' => 'Aucune',
'query_builder' => function (TypologieStructureRepository $sr) {
return $sr->createQueryBuilder('sr')
->orderBy('sr.name', 'ASC');
},
'choice_label' => function ($structure) {
return $structure->getName();
},
'label' => ' ',
'attr' => ['tabIndex' => 0]
]);
$builder->add(
'thematiques',
EntityType::class,
[
'property_path' => 'contact.categories',
'class' => Category::class,
'multiple' => true,
'required' => true,
'expanded' => true,
'query_builder' => function (CategoryRepository $er) {
return $er->createQueryBuilder('c')
->leftJoin('c.parent', 'p')
->where('p.key = :key')
->setParameter('key', 'thematiques')
->orderBy('c.key', 'ASC');
},
'choice_label' => function ($category) {
return $category->findTranslationByLocale('fr')->getTranslation();
},
'label' => 'Thématiques d\'intervention et d\'intérêt*'
]
);
$builder->add(
'optins',
EntityType::class,
[
'property_path' => 'contact.optins',
'class' => Category::class,
'multiple' => true,
'required' => true,
'expanded' => true,
'query_builder' => function (CategoryRepository $er) {
return $er->createQueryBuilder('c')
->leftJoin('c.parent', 'p')
->where('p.key = :key')
->setParameter('key', 'optins')
->orderBy('c.key', 'ASC');
},
'choice_label' => function ($category) {
return $category->findTranslationByLocale('fr')->getTranslation();
},
'label' => 'Abonnement aux lettres d\'informations'
]
);
$builder->add('plainPassword', RepeatedType::class, [
'mapped' => false,
'type' => PasswordType::class,
'invalid_message' => 'Le mot de passe doit correspondre.',
'options' => ['attr' => ['class' => 'password-field']],
'required' => true,
'first_options' => [
'label' => 'Choix du mot de passe*',
'attr' => [
'placeholder' => 'Mot de passe',
'autocomplete' => 'new-password'
],
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'constraints' => [
new Assert\NotBlank(['message' => 'Le mot de passe est requis.']),
new Assert\Length([
'min' => 8,
'minMessage' => 'Le mot de passe doit comporter au moins {{ limit }} caractères.',
]),
],
],
'second_options' => [
'label' => 'Confirmez le mot de passe*',
'attr' => [
'placeholder' => 'Confirmez le mot de passe',
'autocomplete' => 'new-password'
],
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
],
]);
$builder->add('visibleAnnuaire', ChoiceType::class, [
'property_path' => 'contact.visibleAnnuaire',
'expanded' => true,
'multiple' => false,
'choices' => [
'Oui' => 1,
'Non' => 0
],
'data' => 0,
'required' => true,
'label' => 'Souhaitez-vous que votre profil soit visible sur l\'annuaire ?*',
'label_attr' => ['class' => 'mb-1em']
]);
$builder->add(
'terms',
CheckboxType::class,
[
'mapped' => false,
'required' => true,
'label' => 'J\'accepte que les données saisies soient utilisées par PQN-A',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS]
]
);
$builder->add('typologieActeurValue', ChoiceType::class, [
'label' => 'Type d\'acteur *',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'choices' => [
'Selectionner votre typologie d\'acteur *' => '',
'Equipe technique des territoires et ingénierie associée' => 'Equipe technique des territoires et ingénierie associée',
'Décideurs locaux' => 'Décideurs locaux',
'Partenaires' => 'Partenaires',
'Opérateurs' => 'Opérateurs',
'Autres' => 'Autres',
],
'choice_attr' => ['Selectionner votre typologie d\'acteur *' => ['disabled' => '']],
'required' => true,
]);
$builder->add('autresTypologieActeur', TextType::class, [
'property_path' => 'contact.autresTypologieActeur',
'required' => true,
'label' => 'Précisez :',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS, 'id' => 'autres-typologie']
]);
$builder->add('departement', EntityType::class, [
'property_path' => 'contact.departement',
'class' => Category::class,
'multiple' => false,
'expanded' => false,
'query_builder' => function (CategoryRepository $cr) {
return $cr->createQueryBuilder('c')
->leftJoin('c.parent', 'p')
->where('p.key = :key')
->setParameter('key', 'departements')
->orderBy('c.key', 'ASC');
},
'choice_label' => function ($category) {
return $category->findTranslationByLocale('fr')->getTranslation();
},
'placeholder' => 'Sélectionnez votre département *',
'required' => true,
'empty_data' => '',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS],
'label' => 'Département *'
]);
$builder->add('territoireIntervention', EntityType::class, [
'property_path' => 'contact.territoireInterv',
'class' => Category::class,
'multiple' => false,
'expanded' => false,
'query_builder' => function (CategoryRepository $cr) {
return $cr->createQueryBuilder('c')
->leftJoin('c.parent', 'p')
->orderBy('c.key', 'ASC');
},
'choice_label' => function ($category) {
return $category->findTranslationByLocale('fr')->getTranslation();
},
'required' => false,
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS]
]);
$builder->add('username', HiddenType::class);
$builder->add('email', HiddenType::class);
$builder->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => self::BUTTON_CSS_CLASS]
]);
$builder->add('submit2', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => self::BUTTON_CSS_CLASS]
]);
$builder->add('recaptcha', EWZRecaptchaType::class, [
'attr' => [
'options' => [
'theme' => 'light',
'type' => 'image',
'size' => 'normal',
],
],
'mapped' => false,
'constraints' => [
new RecaptchaTrue()
],
]);
$builder->add('submit3', SubmitType::class, [
'label' => 'S\'inscrire',
'attr' => ['class' => self::BUTTON_CSS_CLASS]
]);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$typologie = $data['typologieActeurValue'] ?? null;
if ($typologie === 'Autres') {
$form->add('autresTypologieActeur', TextType::class, [
'property_path' => 'contact.autresTypologieActeur',
'required' => true,
'label' => 'Précisez :',
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS, 'id' => 'autres-typologie']
]);
} else {
// Define the choices for fonction based on the selected typologie
$fonctionChoices = [];
if ($typologie === 'Equipe technique des territoires et ingénierie associée') {
$fonctionChoices = [
'Directeur régional/DGA/DGS' => 'Directeur régional/DGA/DGS',
'Chargé de mission' => 'Chargé de mission',
'Chef de projet' => 'Chef de projet',
'Coordinateur' => 'Coordinateur',
'Animateur' => 'Animateur',
'Assistant / Secrétaire' => 'Assistant / Secrétaire',
'Délégué du préfet' => 'Délégué du préfet',
'Directeur de services' => 'Directeur de services',
'Responsable' => 'Responsable',
'Conseiller' => 'Conseiller',
'Administrateur' => 'Administrateur',
'Médiateur' => 'Médiateur',
'Journaliste' => 'Journaliste',
'Chargé de communication' => 'Chargé de communication',
'Habitants / membres des CC ou de CD / Collectifs citoyens' => 'Habitants / membres des CC ou de CD / Collectifs citoyens',
'Opérateur' => 'Opérateur',
'Partenaire' => 'Partenaire'
// Add more fonction choices for this typologie
];
} elseif ($typologie === 'Décideurs locaux') {
$fonctionChoices = [
'Maire' => 'Maire',
'Maire-adjoint' => 'Maire-adjoint',
'Président Intercommunalité' => 'Président Intercommunalité',
'Vice-Président Intercommunalité' => 'Vice-Président Intercommunalité',
'Conseiller régional' => 'Conseiller régional',
'Conseiller départemental' => 'Conseiller départemental',
'Conseiller communautaire' => 'Conseiller communautaire',
'Conseiller municipal' => 'Conseiller municipal',
'Préfet/sous-Préfet' => 'Préfet/sous-Préfet'
// Add more fonction choices for this typologie
];
}
// Add more elseif blocks for other typologie options
$form->add('fonction', ChoiceType::class, [
'label' => 'Fonction / poste occupé *',
'choices' => $fonctionChoices,
'required' => true,
'label_attr' => ['class' => self::LABEL_ATTR_CSS_CLASS]
]);
}
if (array_key_exists('mainEmail', $data)) {
$data['username'] = $data['mainEmail'];
$data['email'] = $data['mainEmail'];
}
$event->setData($data);
}
);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
if (!isset($_POST['g-recaptcha-response'])) {
$form->addError(new FormError('Le captcha n\'est pas valide.'));
$event->stopPropagation();
return;
}
if (isset($_POST['g-recaptcha-response'])) {
$isCaptchValid = $this->isCaptchaValid($_POST['g-recaptcha-response'], $_ENV['EWZ_RECAPTCHA_SECRET']);
if (!$isCaptchValid) {
$form->addError(new FormError('Le captcha n\'est pas valide.'));
$event->stopPropagation();
}
}
if (!$form->isValid()) {
$this->addValidationErrorsToFlashBag($form, $this->flashbag);
}
if ($form->isValid()) {
$datasArray = [
'nom' => $form->get('lastName')->getData(),
'prnom' => $form->get('firstName')->getData(),
'e_mail' => $form->get('mainEmail')->getData(),
'tl__fixedirectportable_' => $this->ifValueReturnValueOrNothing($form, 'number'),
'adresse' => $this->ifValueReturnValueOrNothing($form, 'street'),
'ville' => $this->ifValueReturnValueOrNothing($form, 'city'),
'cp' => $this->ifValueReturnValueOrNothing($form, 'zip'),
'dpartement' => $this->getDepartmentValueOrNothing($form),
'fonction_dtaille__texte_libre_' => $this->ifValueReturnValueOrNothing($form, 'note'),
'fonction_type_dacteurs' => $this->ifValueReturnValueOrNothing($form, 'typologieActeurValue'),
'fonction__poste_occup' => $this->ifValueReturnValueOrNothing($form, 'fonction'),
'structure' => $this->ifValueReturnValueOrNothing($form, 'structure'),
'typologie_de_structure' => $this->ifValueReturnValueOrNothing($form, 'structureText')
];
foreach ($form->get('thematiques')->getData() as $data) {
if ($data->getKey() === "europe" || $data->getKey() === "developpement-territorial" || $data->getKey() === "participation-citoyenne") continue;
$datasArray[$data->getKey()] = '1';
}
foreach ($form->get('optins')->getData() as $data) {
$datasArray[$data->getKey()] = '1';
}
$this->SynchroHubService->createHubUser($datasArray, '', $_SERVER['SYNCHRO_HUB_DATABASE_ID']);
}
});
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$constraints = [
'recaptcha' => new RecaptchaTrue()
];
$resolver->setDefaults(
[
'constraints' => $constraints,
'data_class' => User::class,
'validation_groups' => ['registration'],
'attr' => ['id' => 'submit-form', 'class' => 'recaptcha-form'],
'empty_data' => function (FormInterface $form) {
$user = new User();
$contact = new Contact();
$address = new Address();
$address->setCity($form->get('city')->getData());
$address->setZip($form->get('zip')->getData());
$address->setStreet($form->get('street')->getData());
$addressType = $this->emi->getReference(AddressType::class, 1);
$address->setAddressType($addressType);
$mainAddress = new ContactAddress();
$mainAddress->setMain(true);
$mainAddress->setAddress($address);
$mainAddress->setContact($contact);
$contact->addContactAddress($mainAddress);
$user->setContact($contact);
/**
* peut servir pour ajouter plusieurs roles
*/
/* $roleQuery = $this->emi->createQueryBuilder()
->select('r')
->from(Role::class, 'r')
->where("r.name = 'PqnaGtEdit'");
$roleQueryResult = $roleQuery->getQuery()->execute();
if (sizeof($roleQueryResult) > 0) {
$editRole = new UserRole();
$editRole->setRole($roleQueryResult[0]);
$editRole->setLocale('["fr"]');
$editRole->setUser($user);
$this->emi->persist($editRole);
$user->addUserRole($editRole);
} */
$this->emi->persist($contact);
$this->emi->persist($user);
return $user;
},
'error_mapping' => [
'data.email' => 'form.email',
'data.mainEmail' => 'form.mainEmail'
],
'error_bubbling' => true
]
);
}
private function isCaptchaValid($response, $secret): ?bool
{
try {
$url = 'https://www.google.com/recaptcha/api/siteverify';
$data = [
'secret' => $secret,
'response' => $response,
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return json_decode($result)->success;
} catch (\Exception $e) {
return null;
}
}
private function addValidationErrorsToFlashBag(FormInterface $form, FlashBagInterface $flashBag)
{
foreach ($form->getErrors(true, false) as $error) {
$flashBag->add('error', $error->getMessage());
}
}
private function ifValueReturnValueOrNothing(FormInterface $form, string $value)
{
if ($form->has($value) && method_exists($form->get($value), 'getData'))
return !empty($form->get($value)->getData()) ? $form->get($value)->getData() : '';
return '';
}
private function getDepartmentValueOrNothing(FormInterface $form)
{
if ($form->get('departement') && method_exists($form->get('departement'), 'getData'))
return !empty($form->get('departement')->getData()) ? explode('_', $form->get('departement')->getData()->getKey())[0] : '';
return '';
}
}