Symfony FOSUserBundle cannot override form, no effect - php

with this article I'm trying to override RegisterFormType.php, and do not see the result, but Symfony Profiler shows in Forms fos_user_registration is overwritten by app_user_registration.
Firstly, I have in AppKernel.php:
new FOS\UserBundle\FOSUserBundle(),
new Sonata\UserBundle\SonataUserBundle('FOSUserBundle'),
new Application\Sonata\UserBundle\ApplicationSonataUserBundle(),
services.yml
app.form.registration:
class: Application\Sonata\UserBundle\Form\RegistrationFormType
tags:
- { name: form.type, alias: app_user_registration }
config.yml:
fos_user:
db_driver: orm # can be orm or odm
firewall_name: main
user_class: Application\Sonata\UserBundle\Entity\User
use_listener: true
group:
group_class: Application\Sonata\UserBundle\Entity\Group
group_manager: sonata.user.orm.group_manager # If you're using doctrine orm (use sonata.user.mongodb.group_manager for mongodb)
service:
user_manager: sonata.user.orm.user_manager # If you're using doctrine orm (use sonata.user.mongodb.user_manager for mongodb)
registration:
form:
type: app_user_registration
#validation_groups: [AppRegistration]
profile:
form:
name: app_user_profile
src/Application/Sonata/UserBundle/Form/RegistrationForm.php:
namespace Application\Sonata\UserBundle\Form;
use ...
class RegistrationFormType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('fullName')
;
}
public function getParent() {
return "fos_user_registration";
}
public function getName() {
return 'app_user_registration';
}
}
src/Application/Sonata/UserBundle/Entity/User.php:
namespace Application\Sonata\UserBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
class User extends BaseUser
{
/**
* #var int $id
*/
protected $id;
/**
* #var string
*/
protected $fullName;
/**
* #return string
*/
public function getFullName() {
return $this->fullName;
}
/**
* #param string $fullName
*/
public function setFullName($fullName) {
$this->fullName = $fullName;
}
/**
* Get id
*
* #return int $id
*/
public function getId() { return $this->id;}
}
As other way (I think not correct) tried to override RegistrationController.php in my custom directory, changed there $form = $this->container->get('app.form.registration') (alias for my form), but I receive error Attempted to call an undefined method named "createView" of class "Application\Sonata\UserBundle\Form\RegistrationFormType. After this I changed this class' parent extended class from ContentAware to Controller, and can see form and new field, but after submitting receive unknown error, even in Profiler not written about it name.
Symfony 2.8.18, FOSUserBundle 1.3.7. Thank you for your time.

Did you update the configuration of the FOSUserBundle in config.yml ?
fos_user:
# ...
registration:
form:
name: app_user_registration

Related

PUGXMultiUserBundle Container error

i installed PUGXMultiUserBundle using this documentation and i follow this, but i have an error
Type error: Argument 1 passed to FOS\UserBundle\Controller\RegistrationController::__construct() must implement interface Symfony\Component\EventDispatcher\EventDispatcherInterface, none given...
fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\User
service:
user_manager: pugx_user_manager
from_email:
address: "%mailer_user%"
sender_name: "%mailer_user%"
pugx_multi_user:
users:
simple_user:
entity:
class: AppBundle\Entity\SimpleUser
registration:
form:
type: AppBundle\Form\SimpleUserType
name: fos_user_registration_form
validation_groups: [Registration, Default]
template: AppBundle:Registration:simple_user.form.html.twig
society_user:
entity:
class: AppBundle\Entity\SocietyUser
registration:
form:
type: AppBundle\Form\SocietyUserType
name: fos_user_registration_form
validation_groups: [Registration, Default]
template: AppBundle:Registration:society_user.form.html.twig
and this is my RegistrationSimpleUserController:
/**
* Class RegistrationSimpleUserController
* #package AppBundle\Controller
*
*/
class RegistrationSimpleUserController extends Controller
{
/**
* #return mixed
*
*
* #Route("/register/simple", name="registration_simple_user")
*/
public function registerAction()
{
return $this->container
->get('pugx_multi_user.registration_manager')
->register('Acme\UserBundle\Entity\UserOne');
}
}
I think this is a bug in the PUGX bundle which is not up to date.
They define the FOSUserBundle Registration controller as a service like this:
pugx_multi_user.registration_controller:
class: FOS\UserBundle\Controller\RegistrationController
But the RegistrationController in the FOSUserBundle has some dependencies:
public function __construct(EventDispatcherInterface $eventDispatcher, FactoryInterface $formFactory, UserManagerInterface $userManager, TokenStorageInterface $tokenStorage)
{
$this->eventDispatcher = $eventDispatcher;
$this->formFactory = $formFactory;
$this->userManager = $userManager;
$this->tokenStorage = $tokenStorage;
}
I think you can solve it by defining an alias like this:
pugx_multi_user.registration_controller:
alias: fos_user.registration.controller
Or overriding the whole definition in your own services.yml:
pugx_multi_user.registration_controller:
class: FOS\UserBundle\Controller\RegistrationController
arguments:
- '#event_dispatcher'
- '#fos_user.registration.form.factory'
- '#fos_user.user_manager'
- '#security.token_storage'

Symfony - Inject Entity Manager in EventSubscriber of form

This is the first time I am working with EventListener of a form so I am struggling on how to inject EntityManager in it.
I have this formType called UserType and in this class I have an EventSubscriber AddDepartmentDegreeCourseFieldSubscriber which needs access to EntityManager
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber(new AddProfileFieldSubscriber());
$builder->addEventSubscriber(new AddDepartmentDegreeCourseFieldSubscriber());
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User'
));
}
}
This is my services.yml
app.department_course_degree_subscriber:
class: AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: kernel.event_subscriber }
The error I get is as following
Catchable Fatal Error: Argument 1 passed to
AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber::__construct()
must be an instance of Doctrine\ORM\EntityManager, none given, called
in /Users/shairyar/Sites/oxford-portal/src/AppBundle/Form/UserType.php
on line 21 and defined
I know what the error means but I thought the service i registered in services.yml should inject the EntityManager so why I am getting this error? What am i missing here? Any help will be really appreciated.
It's because, you pass new instance of AddDepartmentDegreeCourseFieldSubscriber when building form. You need to pass instance from service container.
use AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber;
class UserType extends AbstractType
{
private $addDepartmentDegreeCourseFieldSubscriber;
public function __construct(AddDepartmentDegreeCourseFieldSubscriber $subscriber)
{
$this->addDepartmentDegreeCourseFieldSubscriber = $subscriber;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->addDepartmentDegreeCourseFieldSubscriber);
}
}
# app/config/services.yml
services:
app.department_course_degree_subscriber:
class: AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: kernel.event_subscriber }
app.form.type.my_user_form:
class: AppBundle\Form\UserType
arguments: [ "#app.department_course_degree_subscriber" ]
tags:
- { name: form.type }

UserProvider not implementing correct interface

I am trying to use a custom UserProvider with the FOS User bundle package and the FOS Oauth package. I have been following this tutorial http://blog.tankist.de/blog/2013/07/17/oauth2-explained-part-2-setting-up-oauth2-with-symfony2-using-fosoauthserverbundle/.
When I try and register my new user service I am getting the following error
UserProvider::__construct() must implement interface Doctrine\Common\Persistence\ObjectRepository, array given
UserProvider:
UserProvider implements UserProviderInterface
{
/**
* #var ObjectRepository
*/
protected $userRepository;
/**
* #param ObjectRepository $userRepository
*/
public function __construct(ObjectRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* #param string $username
* #return mixed
*/
public function loadUserByUsername($username)
{ ... }
UserRepository
class UserRepository extends EntityRepository implements ObjectRepository
services.yml
parameters:
entity_name: Hornby\UserBundle\Entity\UserRepository
services:
user_provider_me:
class: Hornby\UserBundle\Provider\UserProvider
arguments:
name: [%entity_name%]
Your services.yml file is wrong. I'm not really sure what you want to achieve but you pass array
arguments:
name: [%entity_name%] #entity_name is just a string
as an argument to UserProvider class. Constructor of this class expects ObjectRepository and this is your problem here.
A translation of services.xml from link you provided should look rather like that:
parameters:
platform.entity.user.class: Acme\DemoBundle\Entity\User
platform.user.provider.class: Acme\DemoBundle\Provider\UserProvider
services:
platform.user.manager:
class: Doctrine\ORM\EntityManager
factory: ["#doctrine", getManagerForClass]
arguments: [%platform.entity.user.class%]
platform.user.repository:
class: Acme\DemoBundle\Repository\UserRepository
factory: ["#platform.user.manager", getRepository]
arguments: [%platform.entity.user.class%]
platform.user.provider:
class: %platform.user.provider.class%
arguments: [#platform.user.repository]

Extending FOSUserBundles Registration to have different fields stored in different tables?

I am new with Symfony2 and FOSUserBundle. I am using Symfony2 version 2.4.1. I would like to extend FOSUserBundle in a few ways. I want to add fields to the registration form, some fields i would like to add to the user table which contains username and password but i would like to add fields that get added to a different table. (I think i have to rewrite the registerController??)
Currently i have inherited FOSUserBundle into my own UserBundle. I have tried to simply add fields to the current registration form by following the documentation but i keep returning this error.
Could not load type "acme_user_registration"
// src/Fixie/UserBundle/Entity/User.php
<?php
namespace Fixie\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
* #Assert\Length(
* min=3,
* max="255",
* minMessage="The name is too short.",
* maxMessage="The name is too long.",
* groups={"Registration", "Profile"}
* )
*/
protected $name;
public function __construct()
{
parent::__construct();
// your own logic
}
}
I then add the name field to the form builder
// src/Fixie/UserBundle/Form/Type/RegistrationFormType.php
<?php
namespace Fixie\UserBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
class RegistrationFormType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
// add your custom field
$builder->add('name');
}
public function getName()
{
return 'acme_user_registration';
}
}
I then go on to declare the custom form type:
// src/Fixie/UserBundle/Resources/config/services.yml
services:
acme_user.registration.form.type:
class: Fixie\UserBundle\Form\Type\RegistrationFormType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: acme_user_registration }
Then updated config:
fos_user:
db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: main
user_class: Fixie\UserBundle\Entity\User
registration:
form:
type: acme_user_registration
//AppKernel.php
<?php
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new Fixie\WelcomeBundle\WelcomeBundle(),
new Fixie\UserBundle\UserBundle(),
new FOS\UserBundle\FOSUserBundle(),
);
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
}
return $bundles;
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
}
// Fixie/UserBundle/UserBundle.php
<?php
namespace Fixie\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class UserBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
My main questions are:
Can anyone see an error with my current code?
In relation to extending the form to have multiple fields being stored in multiple tables. What are the step i have to take? Do i rewrite the logic of the controller and the form???
Any help would be very much appreciated.
Ok.
In appKerenl.php you have
new Fixie\UserBundle\UserBundle(),
But in service.yml
class: Acme\UserBundle\Form\Type\RegistrationFormType
Maybe it should be:
class: Fixie\UserBundle\Form\Type\RegistrationFormType
If in result of command app/console container:debug you can't see acme_user.registration.form.type it means that your service don't register and fos_user can't see you service, and can't find your form type.
My UserBundle store in Webmil/Joint/UserBundle. In UserBundle folder I have file WebmilJointUserBundle.php
My file:
<?php
namespace Webmil\Joint\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class WebmilJointUserBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
So I think that your problem in this file. Can you compare file and your file, and maybe you will find error.
With me it was that i had already a services.yml in app/config, so the one in my bundle was ignored. In the end I added the registry to this file
# app/config/services.yml
services:
# [other already existing services]
acme_user.registration.form.type:
class: Acme\UserBundle\Form\Type\RegistrationFormType
tags:
- { name: form.type, alias: acme_user_registration }

Injecting SecurityContext into a Listener prePersist or preUpdate in Symfony2 to get User in a createdBy or updatedBy Causes Circular Reference Error

I setup a listener class where i'll set the ownerid column on any doctrine prePersist. My services.yml file looks like this ...
services:
my.listener:
class: App\SharedBundle\Listener\EntityListener
arguments: ["#security.context"]
tags:
- { name: doctrine.event_listener, event: prePersist }
and my class looks like this ...
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\SecurityContextInterface;
class EntityListener
{
protected $securityContext;
public function __construct(SecurityContextInterface $securityContext)
{
$this->securityContext = $securityContext;
}
/**
*
* #param LifecycleEventArgs $args
*/
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entityManager = $args->getEntityManager();
$entity->setCreatedby();
}
}
The result of this is the following error.
ServiceCircularReferenceException: Circular reference detected for service "doctrine.orm.default_entity_manager", path: "doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> my.listener -> security.context -> security.authentication.manager -> fos_user.user_manager".
My assumption is that the security context has already been injected somewhere in the chain but I don't know how to access it. Any ideas?
I had similar problems and the only workaround was to pass the whole container in the constructor (arguments: ['#service_container']).
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
class MyListener
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
// ...
public function prePersist(LifeCycleEventArgs $args)
{
$securityContext = $this->container->get('security.context');
// ...
}
}
As of Symfony 2.6 this issue should be fixed. A pull request has just been accepted into the master. Your problem is described in here.
https://github.com/symfony/symfony/pull/11690
As of Symfony 2.6, you can inject the security.token_storage into your listener. This service will contain the token as used by the SecurityContext in <=2.5. In 3.0 this service will replace the SecurityContext::getToken() altogether. You can see a basic change list here: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service
Example usage in 2.6:
Your configuration:
services:
my.entityListener:
class: App\SharedBundle\Listener\EntityListener
arguments:
- "#security.token_storage"
tags:
- { name: doctrine.event_listener, event: prePersist }
Your Listener
namespace App\SharedBundle\Listener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class EntityListener
{
private $token_storage;
public function __construct(TokenStorageInterface $token_storage)
{
$this->token_storage = $token_storage;
}
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entity->setCreatedBy($this->token_storage->getToken()->getUsername());
}
}
For a nice created_by example, you can use https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php for inspiration. It uses the hostnet/entity-tracker-component which provides a special event that is fired when an entity is changed during your request. There's also a bundle to configure this in Symfony2
https://github.com/hostnet/entity-tracker-component
https://github.com/hostnet/entity-tracker-bundle
There's a great answer already in this thread but everything changes. Now there're entity listeners classes in Doctrine:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners-class
So you can add an annotation to your entity like:
/**
* #ORM\EntityListeners({"App\Entity\Listener\PhotoListener"})
* #ORM\Entity(repositoryClass="App\Repository\PhotoRepository")
*/
class Photo
{
// Entity code here...
}
And create a class like this:
class PhotoListener
{
private $container;
function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/** #ORM\PreRemove() */
public function preRemoveHandler(Photo $photo, LifecycleEventArgs $event): void
{
// Some code here...
}
}
Also you should define this listener in services.yml like that:
photo_listener:
class: App\Entity\Listener\PhotoListener
public: false
autowire: true
tags:
- {name: doctrine.orm.entity_listener}
I use the doctrine config files to set preUpdate or prePersist methods:
Project\MainBundle\Entity\YourEntity:
type: entity
table: yourentities
repositoryClass: Project\MainBundle\Repository\YourEntitytRepository
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
lifecycleCallbacks:
prePersist: [methodNameHere]
preUpdate: [anotherMethodHere]
And the methods are declared in the entity, this way you don't need a listener and if you need a more general method you can make a BaseEntity to keep that method and extend the other entites from that. Hope it helps!
Symfony 6.2.4
Add this in your Entity :
#[ORM\EntityListeners(["App\Doctrine\MyListener"])]
Add this in your services.yaml:
App\Doctrine\MyListener:
tags: [doctrine.orm.entity_listener]
Then you can do this :
<?php
namespace App\Doctrine;
use App\Entity\MyEntity;
use Symfony\Component\Security\Core\Security;
class MyListener
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function prePersist(MyEntity $myEntity)
{
//Your stuff
}
}
Hope it helps.

Categories