src/Form/JobAlertType.php line 38

Open in your IDE?
  1. <?php
  2. namespace App\Form;
  3. use App\Component\Captcha\Form\CaptchaType;
  4. use App\Component\Configuration\Util\Config;
  5. use App\Entity\Company;
  6. use App\Entity\JobAlert;
  7. use App\Entity\JobAlertSetting;
  8. use App\Entity\Option;
  9. use App\Entity\OptionValue;
  10. use App\Entity\Repository\OptionValueRepository;
  11. use App\EventListener\FeatureFlagListener;
  12. use App\Form\Setting\JobAlertSettingType;
  13. use App\Service\SiteService;
  14. use App\Transformer\StringToIntegerTransformer;
  15. use App\Util\StringToEntityUtil;
  16. use Doctrine\Common\Collections\ArrayCollection;
  17. use Doctrine\Common\Collections\Collection;
  18. use Doctrine\ORM\EntityManager;
  19. use Flagception\Manager\FeatureManagerInterface;
  20. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  21. use Symfony\Component\Form\AbstractType;
  22. use Symfony\Component\Form\CallbackTransformer;
  23. use Symfony\Component\Form\Exception\TransformationFailedException;
  24. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  25. use Symfony\Component\Form\Extension\Core\Type\EmailType;
  26. use Symfony\Component\Form\Extension\Core\Type\HiddenType;
  27. use Symfony\Component\Form\Extension\Core\Type\RangeType;
  28. use Symfony\Component\Form\Extension\Core\Type\TextType;
  29. use Symfony\Component\Form\FormBuilderInterface;
  30. use Symfony\Component\OptionsResolver\OptionsResolver;
  31. use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
  32. use Symfony\Component\Validator\Constraints\LessThanOrEqual;
  33. use Symfony\Component\Validator\Constraints\NotBlank;
  34. use Symfony\Component\Validator\Constraints\NotNull;
  35. class JobAlertType extends AbstractType
  36. {
  37.     private EntityManager $em;
  38.     private SelectDecorator $optionDecorator;
  39.     /**
  40.      * @var Option[]
  41.      */
  42.     private $optionGroups;
  43.     /**
  44.      * @var bool|null
  45.      */
  46.     private $showLocationAndRadius;
  47.     /**
  48.      * @var int|null
  49.      */
  50.     private $privacyStatementStrategy;
  51.     /**
  52.      * @var string|null
  53.      */
  54.     private $privacyStatementText;
  55.     private Config $config;
  56.     private ParameterBagInterface $parameterBag;
  57.     /**
  58.      * JobAlertType constructor.
  59.      */
  60.     public function __construct(
  61.         EntityManager $entityManager,
  62.         SelectDecorator $optionDecorator,
  63.         ParameterBagInterface $parameterBag,
  64.         StringToEntityUtil $stringToEntityUtil,
  65.         SiteService $siteService,
  66.         FeatureManagerInterface $featureManager,
  67.         Config $config,
  68.         private readonly StringToIntegerTransformer $stringToIntegerTransformer,
  69.     ) {
  70.         $this->em $entityManager;
  71.         $this->config $config;
  72.         $this->parameterBag $parameterBag;
  73.         $optionGroups $this->config->get('site_jobalert_selectable_options');
  74.         if (
  75.             $featureManager->isActive(FeatureFlagListener::FEATURE_MULTI_SITE) &&
  76.             ($currentSite $siteService->getSite()) &&
  77.             $this->config->get('site_jobalert_options_different_per_site')
  78.         ) {
  79.             if (!empty($parameterBag->get('site_jobalert_selectable_options')[$currentSite->getId()])) {
  80.                 $this->optionGroups $stringToEntityUtil->stringToEntity($parameterBag->get('site_jobalert_selectable_options')[$currentSite->getId()]);
  81.                 if ($this->optionGroups instanceof Collection) {
  82.                     $this->optionGroups $this->optionGroups->toArray();
  83.                 }
  84.             }
  85.         } else {
  86.             $optionGroups $stringToEntityUtil->stringToEntity($optionGroups);
  87.             if ($optionGroups instanceof ArrayCollection) {
  88.                 $optionGroupIds $optionGroups->map(function (Option $option) {
  89.                     return $option->getId();
  90.                 });
  91.                 $this->optionGroups $this->em->getRepository(Option::class)
  92.                     ->findBy(['id' => $optionGroupIds->toArray()], ['position' => 'ASC']);
  93.             }
  94.         }
  95.         $this->optionDecorator $optionDecorator;
  96.         $this->showLocationAndRadius $this->config->get('site_jobalert_show_location_and_radius');
  97.         $this->privacyStatementStrategy $this->config->get('site_jobalert_privacy_statement_option');
  98.         $this->privacyStatementText $this->config->get('site_jobalert_privacy_statement_text');
  99.     }
  100.     /**
  101.      * {@inheritdoc}
  102.      */
  103.     public function buildForm(FormBuilderInterface $builder, array $options)
  104.     {
  105.         if (JobAlert::KEYWORD_FIELD_REQUIRED === $this->config->get('site_jobalert_show_search_field')) {
  106.             $builder->add('keyword'TextType::class, [
  107.                 'label' => 'Function or keyword',
  108.             ]);
  109.         } elseif (JobAlert::KEYWORD_FIELD_OPTIONAL === $this->config->get('site_jobalert_show_search_field')) {
  110.             $builder->add('keyword'TextType::class, [
  111.                 'label' => 'Function or keyword',
  112.                 'required' => false,
  113.             ]);
  114.         }
  115.         $builder
  116.             ->add('captcha'CaptchaType::class);
  117.         if ($this->parameterBag->get('site_jobalert_select_companies_enabled')) {
  118.             $builder->add('company'Select2EntityType::class, [
  119.                 'class' => Company::class,
  120.                 'required' => false,
  121.                 'multiple' => false,
  122.                 'label' => 'Company',
  123.             ]);
  124.         }
  125.         if ($this->parameterBag->get('site_jobalert_select_options_enabled')) {
  126.             $builder
  127.                 ->add(
  128.                     $this->optionDecorator->getFormBuilder(
  129.                         $options['is_expanded'],
  130.                         $this->optionGroups ? new ArrayCollection($this->optionGroups) : null
  131.                     )
  132.                 );
  133.             $builder->get('optionValues')
  134.                 ->addModelTransformer(new CallbackTransformer(
  135.                     function (Collection $value) use ($options) {
  136.                         $optionsMap = [];
  137.                         /** @var OptionValue $optionValue */
  138.                         foreach ($value->toArray() as $optionValue) {
  139.                             if (isset($options['data']->isFeatured) && !$options['data']->isFeatured()) {
  140.                                 $optionsMap[$optionValue->getOption()?->getSlug()] = $optionValue->getId();
  141.                                 continue;
  142.                             }
  143.                             if (!isset($optionsMap[$optionValue->getOption()?->getSlug()])) {
  144.                                 $optionsMap[$optionValue->getOption()?->getSlug()] = [];
  145.                             }
  146.                             $optionsMap[$optionValue->getOption()?->getSlug()][] = $optionValue->getId();
  147.                         }
  148.                         return $optionsMap;
  149.                     }, function ($value) {
  150.                         $optionValues = new ArrayCollection();
  151.                         if (!\is_array($value)) {
  152.                             throw new TransformationFailedException('Value is not an array');
  153.                         }
  154.                         /** @var OptionValueRepository $optionValueRepo */
  155.                         $optionValueRepo $this->em->getRepository(OptionValue::class);
  156.                         $optionValuesIdsMap array_values($value);
  157.                         $optionValuesIds = [];
  158.                         foreach ($optionValuesIdsMap as $optionValuesGroup) {
  159.                             // Array merge if field is multiple => true
  160.                             if (\is_array($optionValuesGroup)) {
  161.                                 $optionValuesIds array_merge($optionValuesIds$optionValuesGroup);
  162.                             }
  163.                             // Array push if field is multiple => false
  164.                             if (is_numeric($optionValuesGroup)) {
  165.                                 $optionValuesIds[] = $optionValuesGroup;
  166.                             }
  167.                         }
  168.                         foreach ($optionValuesIds as $id) {
  169.                             $optionValue $optionValueRepo->find($id);
  170.                             if (!$optionValue) {
  171.                                 throw new TransformationFailedException(sprintf('OptionValue with id %s does not exist'$id));
  172.                             }
  173.                             $optionValues->add($optionValue);
  174.                         }
  175.                         return $optionValues;
  176.                     }
  177.                 ));
  178.         }
  179.         if (empty($this->config->get('site_jobalert_default_interval'))) {
  180.             $builder
  181.                 ->add('frequency'ChoiceType::class, [
  182.                     'choices' => [
  183.                         'Daily' => JobAlert::FREQUENCY_DAILY,
  184.                         'Weekly' => JobAlert::FREQUENCY_WEEKLY,
  185.                         'Monthly' => JobAlert::FREQUENCY_MONTHLY,
  186.                     ],
  187.                     'label' => 'How often do you wish to receive vacancies in your mailbox?',
  188.                 ]);
  189.         }
  190.         $personalizationStrategy $this->config->get('site_jobalert_enable_personalizations');
  191.         if ($personalizationStrategy >= JobAlertSettingType::JOB_ALERT_PERSONALIZATION_YES) {
  192.             $isRequired JobAlertSettingType::JOB_ALERT_PERSONALIZATION_YES_REQUIRED === $personalizationStrategy;
  193.             $builder
  194.                 ->add('firstName'TextType::class, [
  195.                     'required' => $isRequired,
  196.                     'row_attr' => [
  197.                         'class' => 'form-group w-50',
  198.                     ],
  199.                 ])
  200.                 ->add('lastName'TextType::class, [
  201.                     'required' => $isRequired,
  202.                     'row_attr' => [
  203.                         'class' => 'form-group w-50',
  204.                     ],
  205.                 ]);
  206.         }
  207.         $builder
  208.             ->add('email'EmailType::class);
  209.         if ($this->showLocationAndRadius) {
  210.             $minRange 5;
  211.             $maxRange 100;
  212.             $builder->add('location'TextType::class, [
  213.                 'attr' => [
  214.                     'class' => 'jobalert-location',
  215.                     'id' => 'jobalertbundle_jobalert_location',
  216.                 ],
  217.             ]);
  218.             $builder->add('locationLatitude'HiddenType::class, [
  219.                 'mapped' => false,
  220.                 'attr' => [
  221.                     'data-component' => 'location[latitude]',
  222.                 ],
  223.             ]);
  224.             $builder->add('locationLongitude'HiddenType::class, [
  225.                 'mapped' => false,
  226.                 'attr' => [
  227.                     'data-component' => 'location[longitude]',
  228.                 ],
  229.             ]);
  230.             $builder->add('locationName'HiddenType::class, [
  231.                 'mapped' => false,
  232.                 'attr' => [
  233.                     'data-component' => 'location[name]',
  234.                 ],
  235.             ]);
  236.             $builder->add('range'RangeType::class, [
  237.                 'label' => 'Range',
  238.                 'attr' => [
  239.                     'min' => $minRange,
  240.                     'max' => $maxRange,
  241.                     'step' => 5,
  242.                     'data-component-source' => 'range',
  243.                 ],
  244.                 'constraints' => [
  245.                     new NotNull(),
  246.                     new GreaterThanOrEqual($minRange),
  247.                     new LessThanOrEqual($maxRange),
  248.                 ],
  249.             ]);
  250.             $builder->get('range')->addViewTransformer($this->stringToIntegerTransformer);
  251.         }
  252.         if (JobAlertSetting::PRIVACY_STATEMENT_STRATEGY_TEXT_AND_CHECKBOX === $this->privacyStatementStrategy) {
  253.             $builder->add('privacy_statement'CheckboxHtmlType::class, [
  254.                 'label' => strip_tags((string) $this->privacyStatementText, ['a''b''strong''em''i']),
  255.                 'mapped' => false,
  256.                 'required' => true,
  257.                 'constraints' => [
  258.                     new NotBlank(),
  259.                 ],
  260.             ]);
  261.         }
  262.     }
  263.     /**
  264.      * {@inheritdoc}
  265.      */
  266.     public function configureOptions(OptionsResolver $resolver)
  267.     {
  268.         $resolver
  269.             ->setDefaults([
  270.                 'data_class' => JobAlert::class,
  271.                 'attr' => ['class' => 'recaptcha-form''novalidate' => true],
  272.             ])
  273.             ->setRequired(['is_expanded']);
  274.     }
  275.     /**
  276.      * {@inheritdoc}
  277.      */
  278.     public function getBlockPrefix()
  279.     {
  280.         return 'jobalertbundle_jobalert';
  281.     }
  282. }