10
<?php

declare(strict_types=1);

namespace App\Controller\User;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;

#[Route('/users', name: 'user.')]
class UserController extends AbstractController
{
    #[Route(name: 'list')]
    public function list(#[CurrentUser] ?User $user, Request $request): Response { 
        dd($user->getFirstName());
    }

Say's Call to a member function getFirstName() on null

But I'm authorized. At the Symfony Profiler it shows that I'm logged in.

Env: PHP 8.0.11 Symfony 5.3.9

IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • Which symfony version do you have? – vstm Nov 02 '21 at 11:33
  • Sure. "sensio/framework-extra-bundle": "^6.2", – Denzel Brazhnikoff Nov 02 '21 at 12:09
  • Is the `User` class correct (does it point to the correct entity)? Have you checked the debug log, maybe there's a hint there? Other than that it would be hard to track the error without a minimal example to reproduce it. – vstm Nov 02 '21 at 12:14
  • I've updated the Controller's code. @Ouus Ma L'aire Bien say's that the issue may be related to Argument Resolving. Do I really need to manually set the logic of resolving current user? I thought that's the main feature of #[CurrentUser] attribute, that I just specify entity class and it injects the user automatically. – Denzel Brazhnikoff Nov 02 '21 at 12:42
  • 2
    Something else is broken in your code but not in evidence here.. I've tried the code above, and `$user` is correctly injected with the`#[CurrentUser]` attribute. https://cln.sh/yyXGsK No need to add nothing manually. The comment in the answer below is a red-herring, it only apples to custom param converters. – yivi Nov 02 '21 at 13:44
  • 1
    The issues comes from ParamConverter. When I set sensio_framework_extra: auto_convert: false, the #[CurrentUser] attribute, finally, works fine. – Denzel Brazhnikoff Nov 02 '21 at 13:48
  • 3
    As per the documentation for the [Argument Resolver](https://symfony.com/doc/5.3/controller/argument_value_resolver.html#adding-a-custom-value-resolver) usage: *"Beware that this feature is already provided by the @ParamConverter annotation from the SensioFrameworkExtraBundle. If you have that bundle installed in your project, add this config to disable the auto-conversion of type-hinted method arguments:"* Which seems to apply to both Custom and Built-In usage – Will B. Nov 02 '21 at 14:39
  • Here is a [github issue](https://github.com/symfony/symfony/issues/40333) that also discusses the issue when Argument Resolvers are used with a Doctrine Entity type-hint that conflicts with the ParamConverter. *"Confirmed: The CurrentUser attribute currently does not work if your user is also a Doctrine entity and you have FrameworkExtraBundle's param converters enabled."* It seems that they plan to remove the ParamConverter support in favor of the Argument Resolvers in the future. – Will B. Nov 02 '21 at 16:01
  • Thank you @will-b for clarifying the question! `CurrentUser` attribute works well, when `sensio_framework_extra: auto_convert` is set to `false` . This way we should manually define `ParamConverter` attribute to provide url params to Entity converting, – Denzel Brazhnikoff Nov 02 '21 at 17:14
  • @DenzelBrazhnikoff I suggest adding it as an answer (instead of a comment), with the appropriate context as to why it appears to be failing. I cannot test to confirm ATM or I would have posted it as an answer. – Will B. Nov 02 '21 at 17:16

3 Answers3

10

The correct details on solution are provided by https://stackoverflow.com/users/1144627/will-b Symfony #[CurrentUser] attribute returns null

The issue is caused by enabled ParamConvertor (sensio/framework-extra-bundle). It can't resolve the User due to lack definitions of how to fetch the Entity from DB, so it sets the $user variable to null because of nullable #[CurrentUser] ?User $user . If you want to keep functionality of param converter and #[CurrentUser] attribute same time, you should disable auto convertion #

config/packages/sensio_framework_extra.yaml
sensio_framework_extra:
    request:
        converters: true
        auto_convert: false

And define route params each time manually. Sources: https://symfony.com/bundles/SensioFrameworkExtraBundle/current/annotations/converters.html https://symfony.com/blog/new-in-symfony-5-2-controller-argument-attributes https://symfony.com/doc/current/controller/argument_value_resolver.html

Solution to avoid such issues: Read the docs at 200% browser scale.

0

As pointed out by others, the problem is indeed the enabled ParamConverter in Sensio Framework Extra Bundle.

But instead of completely disabling it, you could change the typehinting in your Controller from User to UserInterface like this:

<?php

use Symfony\Component\Security\Core\User\UserInterface;
// ...

public function list(#[CurrentUser] ?UserInterface $user, Request $request): Response {
    assert($user instanceof User);
    dd($user->getFirstName());
}

Example of full Controller:

<?php

declare(strict_types=1);

namespace App\Controller\User;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Attribute\CurrentUser;

#[Route('/users', name: 'user.')]
class UserController extends AbstractController
{
    #[Route(name: 'list')]
    public function list(#[CurrentUser] ?UserInterface $user, Request $request): Response {
        assert($user instanceof User);
        dd($user->getFirstName());
    }
}
floriankapaun
  • 472
  • 1
  • 4
  • 19
-1

if your controller extends "AbstractController" you can use $this->getUser() to get the current User.

in your list function you are not giving an user id neither an $user so $user is rationally null

#[Route('/users', name: 'user.')]
class UserController extends AbstractController
 {
#[Route(name: 'list')]
public function list( Request 
$request): Response { 
    dd($this->getUser()->getFirstName());
}
  • dd($this->getUser()->getFirstName()); Works fine. The #[CurrentUser] attributed has been presented with Attribute feature of PHP 8. I'm curious, is that a bug or I'm doing something wrong. – Denzel Brazhnikoff Nov 02 '21 at 11:45
  • in Symfony doc, they talk about adding a new method to the ArgumentMetadata object passed to the argument value resolvers for this to work https://symfony.com/blog/new-in-symfony-5-2-controller-argument-attributes – Ouss Ma L'aire Bien Nov 02 '21 at 12:04
  • 1
    Thanks. That's a good comment. Now I'm completely confused. What's the point of the #[CurrentUser] attribute if I have to manually add all the logic of User parameter resolving? – Denzel Brazhnikoff Nov 02 '21 at 12:34