]> Raphaël G. Git Repositories - packbundle/blob - Form/CaptchaType.php
Generate an unique rapsys pack range string
[packbundle] / Form / CaptchaType.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys PackBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\PackBundle\Form;
13
14 use Rapsys\PackBundle\Util\ImageUtil;
15 use Rapsys\PackBundle\Util\SluggerUtil;
16
17 use Symfony\Component\Form\AbstractType;
18 use Symfony\Component\Form\Extension\Core\Type\HiddenType;
19 use Symfony\Component\Form\Extension\Core\Type\IntegerType;
20 use Symfony\Component\Form\FormBuilderInterface;
21 use Symfony\Component\Form\FormError;
22 use Symfony\Component\Form\FormEvent;
23 use Symfony\Component\Form\FormEvents;
24 use Symfony\Component\OptionsResolver\OptionsResolver;
25 use Symfony\Contracts\Translation\TranslatorInterface;
26
27 /**
28 * Captcha Type class definition
29 *
30 * @see https://symfony.com/doc/current/form/create_custom_field_type.html
31 */
32 class CaptchaType extends AbstractType {
33 /**
34 * Constructor
35 *
36 * @param ?ImageUtil $image The image instance
37 * @param ?SluggerUtil $slugger The slugger instance
38 * @param ?TranslatorInterface $translator The translator instance
39 */
40 public function __construct(protected ?ImageUtil $image = null, protected ?SluggerUtil $slugger = null, protected ?TranslatorInterface $translator = null) {
41 }
42
43 /**
44 * {@inheritdoc}
45 *
46 * Build form
47 */
48 public function buildForm(FormBuilderInterface $builder, array $options): void {
49 //With image, slugger and translator
50 if (!empty($options['captcha']) && $this->image !== null && $this->slugger !== null && $this->translator !== null) {
51 //Set captcha
52 $captcha = $this->image->getCaptcha((new \DateTime('-1 year'))->getTimestamp());
53
54 //Add captcha token
55 $builder->add('_captcha_token', HiddenType::class, ['data' => $captcha['token'], 'empty_data' => $captcha['token'], 'mapped' => false]);
56
57 //Add captcha
58 $builder->add('captcha', IntegerType::class, ['label_attr' => ['class' => 'captcha'], 'label' => '<img src="'.htmlentities($captcha['src']).'" alt="'.htmlentities($captcha['equation']).'" />', 'label_html' => true, 'mapped' => false, 'translation_domain' => false]);
59
60 //Add event listener on captcha
61 $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'validateCaptcha']);
62 }
63 }
64
65 /**
66 * {@inheritdoc}
67 */
68 public function configureOptions(OptionsResolver $resolver): void {
69 //Call parent configure options
70 parent::configureOptions($resolver);
71
72 //Set defaults
73 $resolver->setDefaults(['captcha' => false]);
74
75 //Add extra captcha option
76 $resolver->setAllowedTypes('captcha', 'boolean');
77 }
78
79 /**
80 * Validate captcha
81 *
82 * @param FormEvent $event The form event
83 */
84 public function validateCaptcha(FormEvent $event): void {
85 //Get form
86 $form = $event->getForm();
87
88 //Get event data
89 $data = $event->getData();
90
91 //Set token
92 $token = $form->get('_captcha_token')->getConfig()->getData();
93
94 //Without captcha
95 if (empty($data['captcha'])) {
96 //Add error on captcha
97 $form->addError(new FormError($this->translator->trans('Captcha is empty')));
98
99 //Reset captcha token
100 $data['_captcha_token'] = $token;
101
102 //Set event data
103 $event->setData($data);
104 //With invalid captcha
105 } elseif ($this->slugger->hash($data['captcha']) !== $data['_captcha_token']) {
106 //Add error on captcha
107 $form->addError(new FormError($this->translator->trans('Captcha is invalid')));
108
109 //Reset captcha token
110 $data['_captcha_token'] = $token;
111
112 //Set event data
113 $event->setData($data);
114 }
115 }
116 }