Fosuserbundle: Too few arguments / Override RegistrationController

Created on 3 Jan 2018  路  21Comments  路  Source: FriendsOfSymfony/FOSUserBundle

Hi guys!
I'm a new symfony user.
Today I updated symfony to version 3.4.
I had already installed friendsofsymfony/user-bundle "~2.0@dev".

When I go on the registration page ( http://xxxxxx/app_dev.php/register/ ) I get this message:

Type error: Too few arguments to function FOSUserBundleControllerRegistrationController::__construct(), 0 passed in /var/www/beta.jostratennis.com/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 195 and exactly 4 expected

friendsofsymfony/user-bundle dev-master 5884948

Where can I find the solution?

Most helpful comment

Ok, I'm going closer to solve the problem (@andevit's solution is not a solution as it simply doesn't pass dependencies that may be required).

In my app/config/services.yml file I've manually set the autowiring of my custom controllers:

MyNamespace\Bundle\UserBundle\Controller\:
        resource: '../../src/MyNamespace/Bundle/UserBundle/Controller'
        autowire: true

The error that now comes out is:

Cannot autowire service "SerendipityHQBundleUserBundleControllerChangePasswordController": argument "$formFactory" of method "FOSUserBundleControllerChangePasswordController::__construct()" references interface "FOSUserBundleFormFactoryFactoryInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "fos_user.profile.form.factory", "fos_user.registration.form.factory", "fos_user.change_password.form.factory", "fos_user.resetting.form.factory". Did you create a class that implements this interface?

As clearly stated by the error, this is caused by the fact that all controllers implement the interface FOS\UserBundle\Form\Factory\FactoryInterface and this interface is implemented by 4 different services tailored to the specifc controller with specific dependencies.

The real problem is that they are aliased and this causes the error because the autowire cannot recognize which dependency set in which controller.

To solve the problem in app/config/services.yml manually bind each service for each overridden controller and manually pass the container to it:

    MyNamespace\Bundle\UserBundle\Controller\ProfileController:
        tags: ['controller.service_arguments']
        calls:
            - [setContainer, ["@service_container"]]
        bind:
            $formFactory: "@fos_user.profile.form.factory"

So, the complete configuration to solve the problem is this:

    MyNamespace\Bundle\UserBundle\Controller\:
        resource: '../../src/MyNamespace/Bundle/UserBundle/Controller'
        autowire: true
    MyNamespace\Bundle\UserBundle\Controller\ProfileController:
        tags: ['controller.service_arguments']
        calls:
            - [setContainer, ["@service_container"]]
        bind:
            $formFactory: "@fos_user.profile.form.factory"

POSSIBLE SOLUTION ON FOSUserBundle side

To ease the overriding it is possible to create 4 different concrete classes and typecast the controllers to them: this way each controller will have its own class and the autowiring is possible without manual configuration on our side.

I've not explored this solution, so I don't know which changes it may require in the configuraation of services or in other parts of the bundle, but it is the definitive solution to not force developers to manually bind each overridden controller.

All 21 comments

Same with profile with symfony 3.3

Type error: Too few arguments to function FOSUserBundleControllerProfileController::__construct(), 0 passed in /data/www/dev/unilogin/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 195 and exactly 3 expected

I guess it has something to do with autowiring

Same here ! with Symfony 3.3

Type error: Too few arguments to function FOS\UserBundle\Controller\RegistrationController::__construct(), 0 passed in .../vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 195 and exactly 4 expected

For the moment i solved the problem with the overriding of the constructor:

class RegistrationController extends \FOS\UserBundle\Controller\RegistrationController
{
    public function __construct()
    {
    }
    public function registerAction(Request $request)
    {
    ....

This works for me, but i think it's not the most correct solution.

Controller overriding is not something that is related to fos user bundle. There is not even documentation section about it in a 2.0 version. You can use events. Or if you want to override controllers you should go to the symfony documentation where you can find all information (note that controller is defined as a service). Possible bugs should be consult on symfony side too. Or third solution is to create your own controller.

It is also not recommended to use dev version. Especially if you still run 3.x symfony version.

Ah ok my bad. They probably decided to remove, because it has nothing to do with this bundle. And maintenance was quite hard. Especially after publishing recent symfony versions.

The problem is not directly with overriding of controllers (which is not best practice but sometimes you don't really have a choice and there is no reason it shouldn't work). I believe it has to do with autowiring configuration, but I didn't have time to look properly into it.

The problem is with overriding. As I already said here is the section how to override any service. As you mentioned it tries to auto-wire your controller, but doesn't know how. That's why you have to create a compiler pass.

To complete my answer. You should modify fos_user.registration.controller service definition.

class Kernel extends BaseKernel implements CompilerPassInterface
{
  #....
  public function process(ContainerBuilder $container)
    {
        $definition = $container->findDefinition('fos_user.registration.controller');
        $definition->setClass(App\Entity\Overrides\RegistrationController::class);
    }
}

And change the default service definition by excluding RegistrationController.

# default service configuration
services:
    App\:
        resource: '../src/*'
        exclude: '../src/{Entity,Migrations,Tests,Controller/Overrides}'

    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']
        exclude: '../src/Controller/Overrides'

Auto-wiring doesn't seem to recognize that this service was overridden. (so you are probably right that it comes from there) I am not sure if this is an expected behavior, but for sure it has nothing to do with fos user bundle.

Same problem with s3.3

hi all, specialy @andevit @doctoome @r-ichard @grimmlink ,
bundle version is must be :
"friendsofsymfony/user-bundle": "~2.0",
i change version my problem is solved.

I had already installed friendsofsymfony/user-bundle "~2.0@dev".I

I solved this by andevit solution, and adding a route before fos ones

I found same issue and I didn't extend the controller. @sarpdorukaslan's fix helped me (I used ~2.0@dev)

I'm just experiencing the same exact issue after a composer update done yesterday.

The complete error is this:

Type error: Too few arguments to function FOSUserBundleControllerProfileController::__construct(), 0 passed in /Users/Aerendir/Documents/JooServer/_Projects/Coommercio/Apps/app-trust-back-me-www/var/cache/dev/jms_diextra/controller_injectors/SerendipityHQBundleUserBundleControllerProfileController.php on line 13 and exactly 3 expected

The new commit that causes the error is commit 32c2eed036dd85620cc5229fa482a7ae9455ded9 (release 2.1.1). Previously working release was (2.0.2, commit 2fc8a023d7ab482321cf7ec810ed49eab40eb50f).

The complete error refers to JMSDIExtraBundle: this bundle caused issues with autowiring some time ago (see https://github.com/symfony/symfony/issues/23200 and https://github.com/symfony/symfony/issues/25695).

I'm going to check the changes between the two commits and test the manual calling of setContainer.

Ok, I'm going closer to solve the problem (@andevit's solution is not a solution as it simply doesn't pass dependencies that may be required).

In my app/config/services.yml file I've manually set the autowiring of my custom controllers:

MyNamespace\Bundle\UserBundle\Controller\:
        resource: '../../src/MyNamespace/Bundle/UserBundle/Controller'
        autowire: true

The error that now comes out is:

Cannot autowire service "SerendipityHQBundleUserBundleControllerChangePasswordController": argument "$formFactory" of method "FOSUserBundleControllerChangePasswordController::__construct()" references interface "FOSUserBundleFormFactoryFactoryInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "fos_user.profile.form.factory", "fos_user.registration.form.factory", "fos_user.change_password.form.factory", "fos_user.resetting.form.factory". Did you create a class that implements this interface?

As clearly stated by the error, this is caused by the fact that all controllers implement the interface FOS\UserBundle\Form\Factory\FactoryInterface and this interface is implemented by 4 different services tailored to the specifc controller with specific dependencies.

The real problem is that they are aliased and this causes the error because the autowire cannot recognize which dependency set in which controller.

To solve the problem in app/config/services.yml manually bind each service for each overridden controller and manually pass the container to it:

    MyNamespace\Bundle\UserBundle\Controller\ProfileController:
        tags: ['controller.service_arguments']
        calls:
            - [setContainer, ["@service_container"]]
        bind:
            $formFactory: "@fos_user.profile.form.factory"

So, the complete configuration to solve the problem is this:

    MyNamespace\Bundle\UserBundle\Controller\:
        resource: '../../src/MyNamespace/Bundle/UserBundle/Controller'
        autowire: true
    MyNamespace\Bundle\UserBundle\Controller\ProfileController:
        tags: ['controller.service_arguments']
        calls:
            - [setContainer, ["@service_container"]]
        bind:
            $formFactory: "@fos_user.profile.form.factory"

POSSIBLE SOLUTION ON FOSUserBundle side

To ease the overriding it is possible to create 4 different concrete classes and typecast the controllers to them: this way each controller will have its own class and the autowiring is possible without manual configuration on our side.

I've not explored this solution, so I don't know which changes it may require in the configuraation of services or in other parts of the bundle, but it is the definitive solution to not force developers to manually bind each overridden controller.

Symfony 4.3 ==> For me ProfileController overrider I add the empty construct and it works

use FOS\UserBundle\Controller\ProfileController as BaseController;

class ProfileController extends BaseController
{
    use ControllerTrait;
    public function __construct()
    {
    }

what is the ControllerTrait ? what package?

For a resetController you could copy from vendor/friendsofsymfony/user-bundle/Resources/config/resetting.xml the fos_user.resetting.controller section and have something like this in your app/config/services/services.yml:

AppBundle\Controller\ResettingController:
    autowire: true
    arguments: 
      $eventDispatcher: '@event_dispatcher'
      $formFactory: '@fos_user.resetting.form.factory'
      $userManager: '@fos_user.user_manager'
      $tokenGenerator: '@fos_user.util.token_generator'
      $mailer: '@fos_user.mailer'
      $retryTtl: '%fos_user.resetting.retry_ttl%'

This "break" was introduced in 2.1.0

SF 3.4
If you have autowire true and autoconfigure true in default this was enough for overriding the ResettingController:
app/config/services.yml

AppBundle\Controller\ResettingController:
    arguments:
      $formFactory: '@fos_user.registration.form.factory'
      $mailer: '@fos_user.mailer'
      $retryTtl: '%fos_user.resetting.retry_ttl%'

You also need this as standard:

  AppBundle\Controller\:
    resource: '../../src/AppBundle/Controller'
    public: true
    tags: [ 'controller.service_arguments' ]
Was this page helpful?
0 / 5 - 0 ratings