0
votes

On my personal Symfony3.2 project I want to use HtmlPurifier into my UserProfile Form in order to to prvent XSS Attacks.

Therefore as described in: https://github.com/Exercise/HTMLPurifierBundle I modified the UserProfileFormType accorditly:

namespace AppUserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

class UserProfileFormType extends AbstractType
{
    private $purifierTransformer;

    public function __construct(DataTransformerInterface $purifierTransformer)
    {
        $this->purifierTransformer = $purifierTransformer;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);        

        $builder->addViewTransformer($this->purifierTransformer);
        $builder->add('name',TextType::class,array('label'=>'profile.first_name','required' => false));
        $builder->add('surname',TextType::class,array('label'=>'profile.surnname','required' => false));
        $builder->remove('username');
        $builder->add('username',TextType::class,['required' => false]);
        $builder->add('email',TextType::class,['required' => false]);
        $builder->add('description',TextareaType::class,['required' => false]);
        $builder->remove('current_password');
    }

    public function getParent()
    {
        return 'FOS\UserBundle\Form\Type\ProfileFormType';
    }

    public function getBlockPrefix()
    {
        return 'app_user_profile';
    }

    // For Symfony 2.x
    public function getName()
    {
        return $this->getBlockPrefix();
    }
}

And also used these entries in services.yml entries:

services:
  app_user.html_purifier:
    class: Exercise\HTMLPurifierBundle\Form\HTMLPurifierTransformer
    arguments: ["@exercise_html_purifier.default"]

  app_user.user_profile_form:
    class: AppUserBundle\Form\Type\UserProfileFormType
    arguments: ["@app_user.html_purifier"]
    tags:
      - { name: form.type, alias: app_user_profile }

Also I put these entries in config.yml:

fos_user:
  db_driver: orm # other valid values are 'mongodb' and 'couchdb'
  firewall_name: main
  user_class: '%user_class%'
  from_email:
    address: "[email protected]"
    sender_name: "App Mailer"
  registration:
    confirmation:
      enabled: false
  profile:
    form:
      type: AppUserBundle\Form\Type\UserProfileFormType

exercise_html_purifier:
  default:
    Cache.SerializerPath: '%kernel.cache_dir%/htmlpurifier'

With these options I get the following error message:

Type error: Argument 1 passed to AppUserBundle\Form\Type\UserProfileFormType::__construct() must be an instance of Symfony\Component\Form\DataTransformerInterface, none given, called in /home/pcmagas/Kwdikas/php/apps/symfonyAdminLTE/vendor/symfony/symfony/src/Symfony/Component/Form/FormRegistry.php on line 85

I also tried to change the following value in src/AppUserBundle/Resources/config.yml:

fos_user:
   #Some configuration
  profile:
    form:
      type: AppUserBundle\Form\Type\UserProfileFormType

With this one:

fos_user #Some configuration profile: form: type: app_user.user_profile_form

That returns the following error:

Could not load type "app_user.user_profile_form"

Do you have any Idea how I will solve this one? As long as I Understand the prob is that the FosUserBundle cannot load the proper service somehow. Do you have any idea how I will tell to load the appropriate service to the configuration?

Edit 1:

On UserProfileFormType method I replaced the:

$builder->add('description',TextareaType::class,['required' => false]);

With:

$builder->add('description',PurifiedTextAreaType::class,['required' => false]);

And I got the following error:

Type error: Argument 1 passed to AppUserBundle\Form\Type\PurifiedTextAreaType::__construct() must implement interface Symfony\Component\Form\DataTransformerInterface, none given, called in /home/pcmagas/Kwdikas/php/apps/symfonyAdminLTE/var/cache/dev/appDevDebugProjectContainer.php on line 389

Please keep in mind that I created the AppUserBundle/Form/Type/PurifiedTextAreaType.php:

namespace AppUserBundle\Form\Type;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class PurifiedTextAreaType extends AbstractType
{
    private $purifierTransformer;

    public function __construct(DataTransformerInterface $purifierTransformer)
    {
        $this->purifierTransformer = $purifierTransformer;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addViewTransformer($this->purifierTransformer);
    }

    public function getParent()
    {
        return 'textarea';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'compound' => false,
        ));
    }

    public function getName()
    {
        return 'purified_textarea';
    }
}

I also forgot to mention that I use a different bundle in order to do any sort of user management and handling named AppUserBudnle all the custom forms are in this bundle.

2
give ne your feedback - mduvernon
What kind of feedback? - Dimitrios Desyllas

2 Answers

1
votes

I think that, the best way to use this extension is as described in the tutorial, with a single Textarea which you can call in your final form as your own TextAreaType:

I see this mistake in your description, there are the namespace but "UserProfileFormType" class name is missing.

services:
  app_user.user_profile_form:
    class: AppUserBundle\Form\Type
    arguments: ["@app_user.html_purifier"]
    tags:
      - { name: form.type, alias: app_user_profile }

In this configuration

fos_user:
  db_driver: orm # other valid values are 'mongodb' and 'couchdb'
  firewall_name: main
  user_class: '%user_class%'
  from_email:
    address: "[email protected]"
    sender_name: "App Mailer"
  registration:
    confirmation:
      enabled: false
  profile:
    form:
      type: AppUserBundle\Form\Type\UserProfileFormType

You must overwrite profile form type and then call it by name instead of by class name (which may construct you form without argument) :

Have a look there: http://symfony.com/doc/current/bundles/FOSUserBundle/overriding_forms.html#overriding-a-form-type

0
votes

As Manuel DUVERNON says in the end I created this FormType that represents a HtmlPurified TextArea:

namespace AppUserBundle\Form\Type;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Exercise\HTMLPurifierBundle\Form\HTMLPurifierTransformer;
use HTMLPurifier;

class PurifiedTextAreaType extends AbstractType
{
    private $purifierTransformer;

    /**
     * I Do not Dependency Inject the HtmlPurifier because I want to Use it as
     * FormType in FosUserBundle's extended forms in the wat that is described in: 
     * https://symfony.com/doc/master/bundles/FOSUserBundle/overriding_forms.html
     * 
     * And the method described above does not favour Dependency Injection.
     */
    public function __construct()
    {
        $this->purifierTransformer = new HTMLPurifierTransformer(new \HTMLPurifier());
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addViewTransformer($this->purifierTransformer);
    }

    public function getParent()
    {
        return 'Symfony\Component\Form\Extension\Core\Type\TextareaType';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'compound' => false,
        ));
    }

    public function getName()
    {
        return 'purified_textarea';
    }
}

Please keep in mind NOT TO load the HTMLPurifierTransformer via Dependency Injection because the FosUserBundle's FormBuilder cannot load the extended form via dependency Injection. Also keep in mind to use the namespace of the FormType you are extending (in my case the Symfony\Component\Form\Extension\Core\Type\TextareaType) because FormBuilder also has a limitation into a specific interface.