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\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\Contracts\Translation\TranslatorInterface
; 
  27  * Captcha Type class definition 
  29  * @see https://symfony.com/doc/current/form/create_custom_field_type.html 
  31 class CaptchaType 
extends AbstractType 
{ 
  35          * @param ?ImageUtil $image 
  36          * @param ?SluggerUtil $slugger 
  37          * @param ?TranslatorInterface $translator The translator instance 
  39         public function __construct(protected ?ImageUtil 
$image = null, protected ?SluggerUtil 
$slugger = null, protected ?TranslatorInterface 
$translator = null) { 
  47         public function buildForm(FormBuilderInterface 
$builder, array $options): void { 
  48                 //With image, slugger and translator 
  49                 if ($this->image 
!== null && $this->slugger 
!== null && $this->translator 
!== null) { 
  51                         $captcha = $this->image
->getCaptcha((new \
DateTime('-1 year'))->getTimestamp()); 
  54                         $builder->add('_captcha_token', HiddenType
::class, ['data' => $captcha['token'], 'empty_data' => $captcha['token'], 'mapped' => false]); 
  57                         $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                         //Add event listener on captcha 
  60                         $builder->addEventListener(FormEvents
::PRE_SUBMIT
, [$this, 'validateCaptcha']); 
  67          * @param FormEvent $event The form event 
  69         public function validateCaptcha(FormEvent 
$event): void { 
  71                 $form = $event->getForm(); 
  74                 $data = $event->getData(); 
  77                 $token = $form->get('_captcha_token')->getConfig()->getData(); 
  80                 if (empty($data['captcha'])) { 
  81                         //Add error on captcha 
  82                         $form->addError(new FormError($this->translator
->trans('Captcha is empty'))); 
  85                         $data['_captcha_token'] = $token; 
  88                         $event->setData($data); 
  89                 //With invalid captcha 
  90                 } elseif ($this->slugger
->hash($data['captcha']) !== $data['_captcha_token']) { 
  91                         //Add error on captcha 
  92                         $form->addError(new FormError($this->translator
->trans('Captcha is invalid'))); 
  95                         $data['_captcha_token'] = $token; 
  98                         $event->setData($data);