How to override the UserAdmin form from SonataUserBundle - symfony

Here is the thing.
I started a SonataProject with SonataAdminBundle (v4.22) and SonataUserBundle (v5.4) to manage user.
I would like to override the configureFormFields from the UserAdmin class.
I need to add a new bool field, but it isn't displayed.
I did not use FosUserBundle.
To do that, I have started to create my own AdminClass UserAdmin, which it extends UserAdmin class from SonataUserBundle.
I tried to configure field with configureFormFields.
Here is my function :
<?php
namespace App\Admin;
use Sonata\AdminBundle\Form\FormMapper;
class UserAdmin extends \Sonata\UserBundle\Admin\Model\UserAdmin
{
protected function configureFormFields(FormMapper $form): void
{
parent::configureFormFields($form);
$form
->with('general', ['class' => 'col-md-4'])
->add('notification')
->end();
}
}
How to make this override applied ?
Thanks.

Related

Symfony: How to get the current User Role in a Formtype or security.authorization_checker

I have a Formtype and I need to get access to the current Useres ROLE because I want to decide, which fields are beeing shown.
Is it possible to get access to the security.authorization_checker for example so that I can make an if clause:
if (!$this->get('security.authorization_checker')->isGranted('IS_ADMIN')) { ....
You can register your form as service and then pass security.authorization_checker as arguments, Check below sample code.
form.service.id:
class: YourFormClass
arguments: ['#security.authorization_checker']
tags:
- { name: form.type }
Then in your form class create __construct(AuthorizationChecker $authorizationChecker) method and then use AuthorizationChecker to check ROLE
As mentioned above you can create your onw form based on this snipper of code I used in order to render a field at any NON-admin user:
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Validator\Constraints\IsTrue as TrueConstraint;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
class RegistrationType extends AbstractType
{
/**
* #var AuthorizationChecker
*/
private $authorizationChecker=null;
public function __construct(AuthorizationChecker $authorizationChecker)
{
$this->authorizationChecker=$authorizationChecker;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name',TextType::class,["label"=>"register.name","required"=>true,'translation_domain' => 'FOSUserBundle'])
->add('surname',TextType::class,["label"=>"register.surname","required"=>true,'translation_domain' => 'FOSUserBundle']);
if(!$this->authorizationChecker->isGranted('ROLE_ADMIN'))
{
$builder->add('accept_terms',CheckboxType::class,["label"=>"register.acceptTerms","required"=>true,'translation_domain' => 'FOSUserBundle',
'mapped' => false,'constraints' => new TrueConstraint(array('message' => 'Your Confirmation Message','groups' => 'Registration'))]);
}
}
// Extra stuff ommited for convenience
}
So as you can see I use if a user is admin via $this->authorizationChecker->isGranted('ROLE_ADMIN') piece of code.
SO you just have to put the '#security.authorization_checker' as service argument.

Symfony2 FOSUserBundle relates to another Entity automatically

I recently implemented the FOSUserBundle in my website as the login procedure. I want it to expand the Author class. So whenever a new user is registered via the FOSUSerBundle a new entry is created in the Author class. Inside the Author class I set slug, createdAt and other useful parameters. The field I want to pass to Authot entity from FOSUserBundle is the "Name" field. Then I want to cascade the FOSUser entity and if its deleted, delete also the Author entity.
So schematically FOSUserBundle.username => Author.name
I do not know how to implement this code except that it has a #ORM/OneToOne relationship. Any ideas please?
You'll have to insert the Author manually after your user registration is completed. The FOSUserBundle provides a way to hook into events like post registration completion. You can create a listener to the FOSUserEvents::REGISTRATION_COMPLETED event and create your Author entity there.
See documentation here: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/controller_events.md
For example:
services.yml:
services:
my_user_registration_service:
class: MyBundle\EventListener\MyUserRegistrationListener
arguments: [#doctrine.orm.entity_manager]
tags:
- { name: kernel.event_subscriber }
MyUserRegistrationListener:
namespace MyBundle\EventListener;
use Doctrine\ORM\EntityManager;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use MyBundle\Entity\Author;
class EventSubscriber implements EventSubscriberInterface
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => 'addAuthor',
);
}
public function addAuthor(FilterUserResponseEvent $event)
{
$user = $event->getUser();
$author = new Author();
$author->setName($user->getUsername();
$this->em->persist($author);
$this->em->flush();
}
}

Add constraints in upload image : SonataMediaBundle

How can I add constraints to upload an image, for example : max size, error message, there is not thing about that in the config of sonata_media.
thank you very much.
First you will use the CompilerPassInterface component to override the SonataMediaBundle's MediaAdmin class as per link:
Overriding the part of bundle
supose you are in AcmeDemoBundle:
<?php
namespace Acme\DemoBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class OverrideServiceCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition1 = $container->getDefinition('sonata.media.admin.media');
$definition1->setClass('Acme\DemoBundle\Admin\MediaAdmin');
}
}
Second you will activate your CompilerPassInterface as per the link:
how to activate CompilerPassInterface
<?php
namespace Acme\DemoBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Acme\DemoBundle\DependencyInjection\OverrideServiceCompilerPass;
class AcmeDemoBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new OverrideServiceCompilerPass());
}
}
and in third and final You will override MediaAdmin class of sonatamediabundle as per the link:
INLINE VALIDATION¶(19.3 USING THE ADMIN CLASS¶)
<?php
namespace Acme\DemoBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\MediaBundle\Provider\Pool;
use Sonata\AdminBundle\Route\RouteCollection;
use Sonata\MediaBundle\Admin\BaseMediaAdmin as BaseAdmin;
use Sonata\MediaBundle\Form\DataTransformer\ProviderDataTransformer;
use Sonata\AdminBundle\Validator\ErrorElement;
class MediaAdmin extends BaseAdmin
{
// add this method
public function validate(ErrorElement $errorElement, $object)
{
$errorElement
->with('name')
->assertMaxLength(array('limit' => 32))
->end()
->with('description')
->assertNotNull(array())
->assertLength(array('min' => 2,
'max' => 50))
->end()
// remaining field here
;
}
}
Now you may validate remaing fields of SonataMediaBundle's Media class located in
Sonata\MediaBundle\Model\Media
That's all above the need ..
I got this issue in my project recently. There is my little hack(symfony 2.3):
use Symfony\Component\Validator\ExecutionContextInterface;
/**
* #ORM\Entity(repositoryClass="CMS\RequestBundle\Repository\RequestVideoRepository")
* #ORM\Table(name="request")
* #Assert\Callback(methods={"isMediaSizeValid"})
*
*/
class RequestVideo
{
property
/**
* #ORM\OneToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Media",cascade={"persist"})
*/
protected $file;
Validation method
/**
* #param ExecutionContextInterface $context
*/
public function isMediaSizeValid(ExecutionContextInterface $context)
{
if($this->getFile() && $this->getFile()->getSize() > 5242880){
$context->addViolationAt('file', 'File is too big. Please upload file less than 5MB', array(), null);
}
}
Kinda dirty but I didn't find anything to sort this out. I hope someone will suggest solution better than this.

Execute an action right after the user confirms registration

I am using FOSUserBundle in my Symfony 2.3 project, and I want to execute some code right after the user confirms his account clicking on the email link. I was trying to override the
class RegistrationController extends ContainerAware
{
...
}
but no luck :(
Can I create any kind of Event to be executed right after this action?
Thanks!
You can create an EventListener which listens for FOSUserEvents::REGISTRATION_CONFIRMED like this:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\UserEvent;
class RegistrationConfirmedEventListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(FOSUserEvents::REGISTRATION_CONFIRMED => 'performOnRegistrationConfirmed');
}
public function performOnRegistrationConfirmed(UserEvent $event)
{
$user = $event->getUser();
// Do something
}
}

Extending form types in Symfony2 (aka creating a new form widget)

I'm trying to create/expand a form type in Symfony2, what i want to make is a category selector like in the following image. For that i was reading in symfony2 doc, The chapter: "How to create custom field type"(http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html)
The table database for this this have the following aspect...
What i pretend it's in Symfony extend the hidden form type widget to create my own type, I can not find in the documentation of symfony how to access to the Entities data from the custom type, and also how to call to the custo type object methods in the twig file of the widget. (In the example the twig file is src/Acme/DemoBundle/Resources/views/Form/fields.html.twig )
I know that i have to do some ajax callings to auto load the subcategories every time somebody touch a category, i have done this in the controller, but firstly i want to know how to do what i wrote. Wish this widget be reusable for all :).
Thanks a lot guys!
You should declare your new type as service and inject the Entity Manager into it :
namespace Your\Bundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityManager;
class NewExampleType extends AbstractType
{
protected $em;
public function __construct(EntityManager $entityManager)
{
$this->em = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
//your code
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
//your code
}
public function getParent()
{
return 'hidden';
}
public function getName()
{
return 'example_widget';
}
}
Then, declare new service in services.yml
services:
example.type:
class: Your\Bundle\Form\Type\NewExampleType
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: form.type, alias: "example_widget" }
Source: http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-your-field-type-as-a-service
Then, you should take a look here : http://symfony.com/doc/current/cookbook/form/data_transformers.html

Resources