ParamConverter to inject the current user #327
ParamConverter to inject the current user #327
Conversation
* Does not require controllers to depend upon the entire | ||
* SecurityContext object. | ||
* | ||
* @author Benjamin Eberlei <kontakt@beberlei.de> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is correct.
/** | ||
* {@inheritdoc} | ||
* | ||
* @throws NotFoundHttpException When invalid date given |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems wrong :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I used the DateTime converter as reference. Updated now, thanks.
{ | ||
if (null === $this->security) { | ||
throw new \LogicException('The SecurityBundle is required for the current_user ParamConverter annotation'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see 2 better alternatives here:
A) Instead of making it optional and throwing an exception if missing, add this service/converter only if the security component is available
B) Move this to the supports()
and just return false if non-existent.
I'm in favor of A.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iltar This is actually intentional. If this converter is ignored because the SecurityBundle is not enabled, either the type-hinted $user
object will not be injected, or it might be handled by another converter which wasn't the developer's intention.
This way forces a meaningful error message to the user, and tells them how to fix the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have a dependency on the SecurityContext(Interface)
. That means this converter should not be registered at the moment your application doesn't have it. This can be gracefully done by removing it when the security.context
is not available. What if I register a second param converter that listens to that interface with a lower priority that doesn't need the SecurityContext
for this?
In my opinion it's not up to the param converter to determine what should happen when the SecurityContext
is not available, but the configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point, although there can always be conflicts between two converters, as I found when doctrine was trying to handle my User objects (when not using the UserInterface) for this converter.
I'll try it this way too, only defining the service if the SecurityBundle is enabled.
Just nit picking but I don't really like the name |
@hhamon Completely open to better names, although isn't it possible that the current user isn't authenticated? |
If you type-hint against the UserInterface, or an interface which extends UserInterface, | ||
you may omit this annotation entirely, like this: | ||
|
||
public function myAccountAction(\Symfony\Component\Security\Core\User\UserInterface $currentUser) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a use
statement to make this more readable:
use Symfony\Component\Security\Core\User\UserInterface;
// ...
public function myAccountAction(UserInterface $currentUser)
{
// ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xabbuh Updated. Thanks.
|
||
// ... | ||
|
||
public function myAccountAction(\Symfony\Component\Security\Core\User\UserInterface $currentUser) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to public function myAccountAction(UserInterface $currentUser)
as you have a use
statement above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. 944ec39
@fabpot Job failed on travis for transient composer network issue. Restarted and it's good again. |
@fabpot Updated from most recent master. Any other changes I should make? |
nice addition :) |
*/ | ||
public function apply(Request $request, ParamConverter $configuration) | ||
{ | ||
$param = $configuration->getName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamquaile $param
is used after if+throw so the value could be fetched later (after if+throw)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamquaile Well, typehinting UserInterface
/ EntityWithUserInterface
is exactly what I'm looking for, so I hope it's gonna be resolved soon :)
@adamquaile I think this PR is no longer required. This functionality can be build either inside the SecurityBundle in symfony or in your app manually. This PR is actually the inspiration I've used to add a doc example: https://github.com/symfony/symfony-docs/pull/6438/files#diff-378394f006769e0d975a8e861369dc33R99 |
agreed |
This PR was merged into the 3.2-dev branch. Discussion ---------- Added a SecurityUserValueResolver for controllers | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | ~ | License | MIT | Doc PR | ~ This PR uses the new `ArgumentResolver` to inject a security user when the signature implies so. This is based on the [docs code example](symfony/symfony-docs#6438 (comment)) and [existing pr on the SFEB](sensiolabs/SensioFrameworkExtraBundle#327). With the new example you can do the following: ```php // when a User is mandatory, e.g. behind firewall public function fooAction(UserInterface $user) // when a User is optional, e.g. where it can be anonymous public function barAction(UserInterface $user = null) ``` This deprecates the `Controller::getUser()` method. I have added it on a priority of 40 so it falls just under the `RequestValueResolver`. This is because it's already used and the initial performance is less of an impact. There was a comment asking if the `controller_argument.value_resolver` tag name wasn't too long. If decided this tag should change before 3.1 is released, I will update it in here. *`RequestValueResolver` contains a small codestyle consistency fix.* Commits ------- d341889 Added a SecurityUserValueResolver for controllers
When creating testable controllers, it's often desirable to not use the
getUser
function in the base controller, as this relies on the whole service container.In this case, we might add a dependency on the
SecurityContext
to achieve the same result, replicating this code:This parameter converter streamlines the process and injects the current user into the controller method instead using the following format: