1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys PackBundle package. 
   6  * (c) Raphaël Gertz <symfony@rapsys.eu> 
   8  * For the full copyright and license information, please view the LICENSE 
   9  * file that was distributed with this source code. 
  12 namespace Rapsys\PackBundle\Form
; 
  14 use Rapsys\PackBundle\Util\ImageUtil
; 
  15 use Rapsys\PackBundle\Util\SluggerUtil
; 
  17 use Symfony\Contracts\Translation\TranslatorInterface
; 
  18 use Symfony\Component\Form\AbstractType
; 
  19 use Symfony\Component\Form\Extension\Core\Type\HiddenType
; 
  20 use Symfony\Component\Form\Extension\Core\Type\IntegerType
; 
  21 use Symfony\Component\Form\FormBuilderInterface
; 
  22 use Symfony\Component\Form\FormEvents
; 
  23 use Symfony\Component\Form\FormEvent
; 
  24 use Symfony\Component\Form\FormError
; 
  27  * Captcha Type class definition 
  29  * @see https://symfony.com/doc/current/form/create_custom_field_type.html 
  31 class CaptchaType 
extends AbstractType 
{ 
  33          * @var ImageUtil $image 
  38          * @var SluggerUtil $slugger 
  43          * @var Translator instance 
  50          * @param ImageUtil $image 
  51          * @param SluggerUtil $slugger 
  52          * @param TranslatorInterface $translator The translator instance 
  54         public function __construct(ImageUtil 
$image, SluggerUtil 
$slugger, TranslatorInterface 
$translator) { 
  56                 $this->image 
= $image; 
  59                 $this->slugger 
= $slugger; 
  62                 $this->translator 
= $translator; 
  70         public function buildForm(FormBuilderInterface 
$builder, array $options): void { 
  72                 $captcha = $this->image
->getCaptcha((new \
DateTime('-1 year'))->getTimestamp()); 
  75                 $builder->add('_captcha_token', HiddenType
::class, ['data' => $captcha['token'], 'empty_data' => $captcha['token']]); 
  78                 $builder->add('captcha', IntegerType
::class, ['label_attr' => ['class' => 'captcha'], 'label' => '<img src="'.htmlentities($captcha['src']).'" alt="'.htmlentities($captcha['equation']).'" />', 'label_html' => true, 'translation_domain' => false]); 
  80                 //Add event listener on captcha 
  81                 $builder->addEventListener(FormEvents
::PRE_SUBMIT
, [$this, 'validateCaptcha']); 
  87          * @param FormEvent $event The form event 
  89         public function validateCaptcha(FormEvent 
$event): void { 
  91                 $form = $event->getForm(); 
  94                 $data = $event->getData(); 
  97                 $token = $form->get('_captcha_token')->getConfig()->getData(); 
 100                 if (empty($data['captcha'])) { 
 101                         //Add error on captcha 
 102                         $form->addError(new FormError($this->translator
->trans('Captcha is empty'))); 
 104                         //Reset captcha token 
 105                         $data['_captcha_token'] = $token; 
 108                         $event->setData($data); 
 109                 //With invalid captcha 
 110                 } elseif ($this->slugger
->hash($data['captcha']) !== $data['_captcha_token']) { 
 111                         //Add error on captcha 
 112                         $form->addError(new FormError($this->translator
->trans('Captcha is invalid'))); 
 114                         //Reset captcha token 
 115                         $data['_captcha_token'] = $token; 
 118                         $event->setData($data);