-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] Add MapSessionParameter
to map session parameters to controllers
#54458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 7.3
Are you sure you want to change the base?
Conversation
Hey! I see that this is your first PR. That is great! Welcome! Symfony has a contribution guide which I suggest you to read. In short:
Review the GitHub status checks of your pull request and try to solve the reported issues. If some tests are failing, try to see if they are failing because of this change. When two Symfony core team members approve this change, it will be merged and you will become an official Symfony contributor! I am going to sit back now and wait for the reviews. Cheers! Carsonbot |
Hey! Thanks for your PR. You are targeting branch "7.1" but it seems your PR description refers to branch "7.2". Cheers! Carsonbot |
MapSessionContext
to map multiple session value to…MapSessionContext
to map multiple session value to…
MapSessionContext
to map multiple session value to…MapSessionContext
to map multiple session value to…
Status: needs review |
This comment was marked as outdated.
This comment was marked as outdated.
Thank for the feedback. I didn't think about injecting the object itself, i think it would work yes and be simpler. Initially i made it this way to migrate a project that was using directly the set/get without constant, so the goal was mainly to proxy the calls and avoid issues like reading 'locale' but writing to '_locale'. In session i wanted to have the individual keys. I'm not sure which method would be better |
Not using proxies is better for sure :) |
Update done, i've removed the magic trait and also the possibility to specify the session key for each property. |
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 like this idea :)
src/Symfony/Component/HttpKernel/Attribute/MapSessionContext.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionContextValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
...Component/HttpKernel/Tests/Controller/ArgumentResolver/SessionParameterValueResolverTest.php
Outdated
Show resolved
Hide resolved
...Component/HttpKernel/Tests/Controller/ArgumentResolver/SessionParameterValueResolverTest.php
Outdated
Show resolved
Hide resolved
...Component/HttpKernel/Tests/Controller/ArgumentResolver/SessionParameterValueResolverTest.php
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
MapSessionContext
to map multiple session value to…MapSessionParameter
to map session parameters to controllers
Update done, good idea to allow the interface and thank for all the feedback. I made a change on which i'm not 100% certain if it was the right call : While it is not always mandatory because if there is already a value in session, it would work without a default value, it may lead to an error later if the controller is called without setting the session before. (For example, the server restart and clear the session). This is a case that may be complicated to detect during development, so trigger the error even if it was possible to continue without error. |
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 looks good to me, I only have CS-related comments.
src/Symfony/Component/HttpKernel/Attribute/MapSessionParameter.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/SessionParameterValueResolver.php
Outdated
Show resolved
Hide resolved
...Component/HttpKernel/Tests/Controller/ArgumentResolver/SessionParameterValueResolverTest.php
Show resolved
Hide resolved
2f18c59
to
8e4af59
Compare
1f956b1
to
348c194
Compare
8ad2497
to
77f9de7
Compare
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 like this PR because it enables more decoupling from framework-provided interfaces (SessionInterface here).
Any other opinions on the topic @symfony/mergers? Votes pending 🙏
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.
Is it a commun thing to store object in session?
It feel a bit wrong to me.
People need to deal with BC between 2 deploys...
return []; | ||
} | ||
|
||
if ((!$type = $argument->getType()) || (!class_exists($type) && !interface_exists($type, false))) { |
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.
- We should deal with nullable type?
- It does not work with union / intersection type
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.
Allowing null allow to use an interface or to create the object only if needed.
I didn't checked for the union type, i'll update the PR
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.
compound types aren't compatible with value resolvers IMHO, this one or any other
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.
For the record, I tested, an it fails indeed. It tells the class "App\Foo|AppBar"
does not exist
return [$value]; | ||
} | ||
|
||
if (\is_object($value = $argument->hasDefaultValue() ? $argument->getDefaultValue() : new $type())) { |
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 don't understand why there is a if is_object here
$argument->getDefaultValue()
is of type object, expect if null are allowed, but this is weird?new $type
is an object too
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.
What is there is a constructor with required arguments?
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.
The is_object check if the default value is null or not, if it's null, we don't write in session.
If you have a constructor with arguments, you'll have to provide the default value in the controller :
public function index(
#[MapSessionParameter()] Foobar $foobar1 = null,
#[MapSessionParameter()] Foobar $foobar2 = new Foobar("myParam"),
): Response
And I just tested the PR,
class HomepageController extends AbstractController
{
#[Route('/')]
public function index(
#[MapSessionParameter()] Foobar $foobar4,
): Response
{
dump($foobar4);
return $this->render('homepage/index.html.twig', [
]);
}
}
class Foobar
{
public function __construct(
) {
}
}
|
The goal of this PR is not to allow storing object but reducing type error and wrong session key error (username vs userName).
Didn't really think about this point. I guess you can use the fact that there is support for interface to leverage this point. |
My point about objects it that is encourage people to store objects in the session, and IMHO this is a terrible idea. So, even if this PR looks nice at glance, it's not a good idea. |
But we do ourselves put value objects in the session, I see no issue, with some care of course. |
I've added a new commit to add support for the union/intersection type, they are considered like the interface (need to provide a default value or make them nullable). There is one point that i didn't find an easy/effective way to do : Check if the data in the session match the expected type to trigger an exception saying that the type in session was not compliant. Instead, the user will have a message like Is there a method like that ? (instanceof and is_a doesn't seem to handle union types) |
dd43ddf
to
6087c60
Compare
80e891a
to
1070c54
Compare
… to a controller argument This attribute allow to pass an object from the session. The read/write to the public properties are proxied to the session using the property name as a key, or the value defined by the attribute SessionKey This allows to type property and have ide autocompletion, static validation and runtime validation of type. The default value of the argument is also used as a default value when not defined in session. In case of interfaces, the user will be required to provide a default value or make the parameter nullable. This check is done even if the session may have a value already to notify quickly of the potential issue
Two very genuine questions about this attribute, sorry if it has been mentionned in one of the previous threads. First: Isn't this the only value resolver that write things? If so I guess this is something that should be written in bold in the documentation. Second (related) question: does this mean if a controller is protected by a |
This is not desired to me, I would remove the |
This was not mentionned before, and for the second question, i have not a clue, so i'll dive more into this part, so thank you :)
It may be the only resolver that write, it was to avoid the case where depending of if the session was already set or not, the value would save automatically or not.
I don't know enough about the exact order for this process, i'll deep dive into this part to understand more. From all the feedback, i get that the fact that it is an object that is stored and we write automatically in the session is not the intended behavior. |
This attribute allow to map an object from/to the session. The read/write to the public properties are proxied to the session using the property name as a key, or the value defined by the attribute SessionKey. There is no prefix, so if two class use the same property, they will read/write to the same session entry, which is intended to have variable shared between context if needed.
This allow to type property and have ide autocompletion, static validation and runtime validation of type. The default value from the property is also used as a default value when reading from session.
Using this method reduce the errors related to a wrong key used or inconsistent default value. It also help seing which key are currently used and avoid conflicts
Calling isset will return if the property is defined in session but will not check if the value is null. Calling unset remove the entry from the session
For example, we can create a class like this :
and use it in a controller :
The term session context come from the idea that we get a lot of information that are often together. I avoided to use something too close of Object to avoid confusion with the SessionInterface object.
This pull request is based in HttpKernel to be close to
SessionValueResolver
but i'm not confident if the namespaces used are the right ones.I'm not fond of the eval to create the anonymous class, but didn't managed to create an anonymous class without that. Also, i'm not sure if it's possible to create a proxy during container build in this context.