8000 [DependencyInjection] Introduce a new ParameterResolver by GuilhemN · Pull Request #17192 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DependencyInjection] Introduce a new ParameterResolver #17192

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

Closed
wants to merge 1 commit into from

Conversation

GuilhemN
Copy link
Contributor
Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets #17160
License MIT
Doc PR

Actually, to resolve a value we can use ParameterBag::resolveValue() which is accessible in the Container.
This works fine but the problem is when we want to resolve a value at runtime and we have a custom ContainerInterface instance.

So I would like to have a trait or a class which would allow to resolve values without an access to a ParameterBag instance.

You can find an example of use case in FOSRestBundle where we need to resolve values at runtime.
We actually use a trait but I'd prefer to use something from the core.

As suggested by @xabbuh, this PR creates a new ParameterResolver used internally by the ParameterBag.

@@ -264,6 +219,9 @@ public function escapeValue($value)
return $value;
}

/**
* {@inheritdoc}
*/
public function unescapeValue($value)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this function should also be moved in the ParameterResolver.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not really related to resolving values, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is, after resolving a value we must want to unescape it.
An example if I use

$resolver = new ParameterResolver(function() { return 'foobar'; });
$resolver->resolveValue('foo %bar% %%');

I will obtain foo foobar %% which is still escaped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like an issue with resolveValue, isn't it? I'd expect resolveValue to resolve parameters and escaping in the same run (but without exposing any specific public method for that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that it was mostly introduced in #4707.
We can still add a new argument to resolveValue() which would specify if the value must be unescaped (and change its default value in 4.0) and deprecate unescapeValue and escapeValue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolas-grekas I added BC layers in the latest commits to unescape values by default but I'm not sure we should do that in this PR (this makes a lot of changes).
Should I open a new PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveValue can return different values depending if the ParameterBag is resolved or not...

See this example:

$parameterBag = new ParameterBag(array(
    'foo' => '100 %%',
));

$parameterBag->resolveValue('%foo% %%'); // will return '100 %% %%'

$parameterBag->resolve();
$parameterBag->resolveValue('%foo% %%'); // will return '100% %%'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only solution I see to fix this inconsistency is to manage the entire unescaping process in resolveValue

@GuilhemN
Copy link
Contributor Author

@xabbuh Do you prefer this solution where the values fetched are resolved in the ParameterBag?

@GuilhemN
Copy link
Contributor Author
GuilhemN commented Jan 2, 2016

My second proposition needs a more complex callback but in case we use the Container instead of a ParameterBag to resolve values, this is more natural (no need to mark the values as resolved).

private function getResolver()
{
if (null === $this->resolver) {
$self = $this;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for that as this is targetting master (which requires php 5.5)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right I didn't know that this changed in php 5.5.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it actually chnaged in php 5.4 :}

{
$this->parameters = $parameters;
$this->resolved = true;
$this->resolver = $resolver;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the resolver useless here in the frozen bag ? Shoudn't everything already being resolved ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FrozenParameterBag::resolveValue() can still be used.

@GuilhemN
Copy link
Contributor Author
GuilhemN commented Jan 2, 2016

I'm wondering if instead of using a ParameterResolver in the ParameterBag it should not just extend the ParameterResolver class

@Taluu
Copy link
Contributor
Taluu commented Jan 2, 2016

No, you wouldn't be able to change the resolver then (and thus the point of such a class would be next to none). But it could be defined as a trait

@unkind
Copy link
Contributor
unkind commented Jan 4, 2016

Generic names like ParameterResolver force many devs to depend on a class instead of an interface. If class has 1-to-1 interface, it shouldn't have generic name. It becomes more clear when you don't use the Interface suffix: http://verraes.net/2013/09/sensible-interfaces/

@GuilhemN
Copy link
Contributor Author
GuilhemN commented Jan 4, 2016

@unkind you're right, makes even more sense now that there is a trait... But are you sure CallableParameterResolver is a good name? Maybe an english native could help us?

*
* @throws ParameterNotFoundException if the parameter is not defined
*/
abstract protected function getParameter($name, $resolving = array());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this function should be named getParameter or something else to avoid conflicts...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having an abstract method in the trait. What about adding a private setParameterBag() method instead that must be called by the consuming class? This method could populate an internal ParameterBag property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like it to work on top of a any container (and a container may not use ParameterBag). I didn't find anything better to solve this abstraction issue.

@GuilhemN
Copy link
Contributor Author
GuilhemN commented Jan 8, 2016

Other reviews?

@@ -227,7 +159,7 @@ public function testEscapeValue()
/**
* @dataProvider stringsWithSpacesProvider
*/
public function testResolveStringWithSpacesReturnsString($expected, $test, $description)
public function testLegacyResolveStringWithSpacesReturnsString($expected, $test, $description)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the @group legacy annotation

@GuilhemN
Copy link
Contributor Author

The build failure doesn't seem related...

@GuilhemN
Copy link
Contributor Author

In fact it is... I'll try to fix them

@GuilhemN
Copy link
Contributor Author

I reverted the last commits because this is a big subject and they just make this PR bigger than it has to be...
So the tests are fixed again.

@TomasVotruba
Copy link
Contributor

@Ener-Getick Very nice PR! Thanks for great job

@GuilhemN
Copy link
Contributor Author

Deprecation message updated to 3.2.
I would love to see that merged ! It would avoid me having to copy-paste this trait...

* @throws ParameterCircularReferenceException if a circular reference is detected
* @throws RuntimeException when a given parameter has a type problem.
*/
public function resolveValue($value, array $resolving = array())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo the public interface should not leak the $resolving argument (it's an implementation detail). We could add a private method that does the actual resolving an let resolveValue() call it with an empty array as the second argument.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And by the way, the ParameterResolverInterface even doesn't require this second argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine for me.

Besides that, I'm wondering if we shouldn't make this method private by default: in userland it is unlikely to be used outside the class using the trait.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: I agree, but we can't do that for bc reasons, see our previous conversation

/**
* Implementation of {@link ParameterResolverInterface}.
*
* @author Guilhem N. <egetick@gmail.com>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add the author(s) of the ParameterBag class too (the main logic was only slightly touched).

*
* @author Guilhem N. <egetick@gmail.com>
*/
interface ParameterResolverInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need an extra interface for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking using it for other classes than ParameterBag but indeed we can remove it unless someone explicitly requests it.

@GuilhemN GuilhemN force-pushed the PARAMETERRESOLVER branch 2 times, most recently from 91e6f1a to 83f3954 Compare October 26, 2016 21:04
@nicolas-grekas
Copy link
Member
nicolas-grekas commented Nov 5, 2016

Shouldn't this one be closed in favor of #20276?

@GuilhemN
Copy link
Contributor Author

@nicolas-grekas the goal is not the same. I'd like to use this to resolve values at runtime (in annotations for example) without copying a large portion of code like what we did in FOSRestBundle.

@nicolas-grekas nicolas-grekas added this to the 3.x milestone Dec 6, 2016
@xabbuh
Copy link
Member
xabbuh commented Dec 29, 2016

I agree with @GuilhemN and I would like to see this in 3.3 too.

@nicolas-grekas
Copy link
Member

@xabbuh would you like to take over this PR? I personally don't get its point but I think that's just because I'm not in this part of the business :)

@xabbuh
Copy link
Member
xabbuh commented Sep 26, 2017

I'll try to do that by the end of the week. If someone wants to take over before, just feel free to do so.

@nicolas-grekas nicolas-grekas modified the milestones: 3.4, 4.1 Oct 8, 2017
@xabbuh xabbuh self-assigned this Oct 11, 2017
@nicolas-grekas
Copy link
Member

Could this be solved differently with #25288?

@GuilhemN
Copy link
Contributor Author
GuilhemN commented Dec 6, 2017

@nicolas-grekas it looks like it does indeed, 👍 for your approach :)

@nicolas-grekas
Copy link
Member

Cool, closing then. Cheers.

@GuilhemN GuilhemN deleted the PARAMETERRESOLVER branch March 17, 2019 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0