Query param fetcher #185

Merged
merged 49 commits into from May 16, 2012
@lsmith77
FriendsOfSymfony member

maybe instead of a listener we can use a param converter:
http://symfony.com/doc/2.0/bundles/SensioFrameworkExtraBundle/annotations/converters.html

@stof
FriendsOfSymfony member

does the QueryParam stuff depend on FrameworkExtraBundle currently ?

@lsmith77
FriendsOfSymfony member

no .. currently it does not. but i don't really like having to use a listener to set the request attribute.

@vicb vicb and 1 other commented on an outdated diff Feb 7, 2012
Request/QueryFetcher.php
+ public function __construct(ContainerInterface $container, QueryParamReader $queryParamReader, Request $request)
+ {
+ $this->container = $container;
+ $this->queryParamReader = $queryParamReader;
+ $this->request = $request;
+ }
+
+ private function initParams()
+ {
+ $_controller = $this->request->attributes->get('_controller');
+
+ if (null === $_controller) {
+ throw new \InvalidArgumentException('No _controller for request.');
+ }
+
+ if (false !== strpos($_controller, '::')) {
@vicb
vicb added a line comment Feb 7, 2012

Could you leverage the ControllerResolver ?

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

yeah maybe ..

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

looking at the code it seems like it would be inefficient for the case when the controller is not implemented as a service. but it looks like we are lacking support for a:b:c notation atm.

@vicb
vicb added a line comment Feb 7, 2012

That would be more dry and future proof

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

ok .. we should now cover all the cases

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

yeah it would .. but i don't think the overhead makes this legitimate.

@vicb
vicb added a line comment Feb 7, 2012

could the controller event help with efficiency ?

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

hmm it could be a possibility. in that case we would move the other listener from a request listener to a controller listener as well. in that case of course the parameters would no longer be available in any listeners run before the controller, but i guess that would be ok.

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

ok .. i have an implementation using a controller event .. will push that into a new branch

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

see #186

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@vicb vicb commented on an outdated diff Feb 7, 2012
Request/QueryFetcher.php
+ */
+ public function getParameter($name)
+ {
+ if (!isset($this->params)) {
+ $this->initParams();
+ }
+
+ if (!isset($this->params[$name])) {
+ throw new \InvalidArgumentException(sprintf("No @QueryParam configuration for parameter '%s'.", $name));
+ }
+
+ $param = $this->request->query->get($name, $this->params[$name]->default);
+
+ // Set default if the requirements do not match
+ if ($param !== $this->params[$name]->default
+ && !preg_match('/^' . $this->params[$name]->requirements . '/xs', $param)
@vicb
vicb added a line comment Feb 7, 2012

is '$' missing on purpose ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@vicb vicb commented on an outdated diff Feb 7, 2012
Request/QueryFetcher.php
+ {
+ if (!isset($this->params)) {
+ $this->initParams();
+ }
+
+ if (!isset($this->params[$name])) {
+ throw new \InvalidArgumentException(sprintf("No @QueryParam configuration for parameter '%s'.", $name));
+ }
+
+ $param = $this->request->query->get($name, $this->params[$name]->default);
+
+ // Set default if the requirements do not match
+ if ($param !== $this->params[$name]->default
+ && !preg_match('/^' . $this->params[$name]->requirements . '/xs', $param)
+ ) {
+ $param = $this->params[$name]->default;
@vicb
vicb added a line comment Feb 7, 2012

factorize $default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@vicb vicb and 1 other commented on an outdated diff Feb 7, 2012
Request/QueryFetcher.php
+ *
+ * @param string $name Name of the query parameter
+ *
+ * @return mixed Value of the parameter.
+ */
+ public function getParameter($name)
+ {
+ if (!isset($this->params)) {
+ $this->initParams();
+ }
+
+ if (!isset($this->params[$name])) {
+ throw new \InvalidArgumentException(sprintf("No @QueryParam configuration for parameter '%s'.", $name));
+ }
+
+ $param = $this->request->query->get($name, $this->params[$name]->default);
@vicb
vicb added a line comment Feb 7, 2012

using has() would allow always validating against the requirement (thinking of the default value here but not sure of what is the desired behavior)

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

that $param !== $default further down is just a performance optimization to avoid the regexp if it isn't needed. so i think the code is ok as is.

@vicb
vicb added a line comment Feb 7, 2012

just wanted to make sure you were aware of the edge case here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@vicb vicb and 1 other commented on an outdated diff Feb 7, 2012
EventListener/QueryFetcherListener.php
+ * @param ContainerInterface $container container
+ */
+ public function __construct(ContainerInterface $container)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * Core request handler
+ *
+ * @param GetResponseEvent $event The event
+ */
+ public function onKernelRequest(GetResponseEvent $event)
+ {
+ $request = $event->getRequest();
+ $request->attributes->set('queryFetcher', $this->container->get('fos_rest.request.query_fetcher'));
@vicb
vicb added a line comment Feb 7, 2012

do we really need a listener, can't it be lazy loaded (just a thought, too late to check for now)

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment Feb 7, 2012

we need a listener to set the request attribute, so that it can be injected via the action signature, which is imperative to controllers that do not inject the DIC ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof
FriendsOfSymfony member

closures and fonctions won't be catched here as they are not arrays. The first if should only check for null (or eventually for is_callable if you want)

@vicb

Some thoughts:

Is the queryFetcher a good idea ? Let's imagine I do some processing in my controller based on the query parameters and then I call doSomeGreatStuff($request). This function would get the query parameters as $request->query->... and then we have a mismatch. Would it be possible to drop the queryFetcher and replace (or update) the query parameter bag instead so that the API does not get changed ?

I can imagine some day we have a router component that is aware of the query parameters. This PR could not work as the parameters are processed in the controller only. So I would prefer if the changes are moved to the router layer.

@lsmith77
FriendsOfSymfony member

Overriding the Request parameter bag would remove the need to set the request attribute. How would it behave in that case though? I guess it would then only overload get() to set the default from the annotation (what would happen if a default is passed?) and execute the given requirements checks from the annotation?

@lsmith77
FriendsOfSymfony member

the other question would be where and when do we override the default parameter bag? would this require a custom Request class or a listener again?

@vicb

@lsmith77

  • What I can imagine is to update the parameters in the bag and then use the bag as before.
  • I would go for the router layer for the reason explained in my previous message. I had first thought of a custom bag class but I don't even think it is necessary (see my point above).
@lsmith77
FriendsOfSymfony member

Well I see some major issues here:
1) it would mean we do a lot of work that may not become necessary
2) if we do it in the router, then we will have the issue with determining the class/method again

@vicb

Well maybe the best place is the controller event. IMO the most important thing is to drop the $queryFetcher and be able to use doSomeGreatStuff($request). I let you work out the details.

@lsmith77
FriendsOfSymfony member

If we do this, then we would best wrap the standard ParameterBag inside one that automatically sets the defaults and checks the requirements when any of the get*() methods are called. However this may also lead to a bit of unclearity as to when these requirements are applied. Aka sometimes when you use the request it would apply the requirements .. but for example inside a request listener they would not. I think this makes things more obscure, so I prefer the current approach.

@vicb

That might indeed be a bad idea but the current implementation is even worse then. The solution would be to change to router to support matching query params.

@lsmith77
FriendsOfSymfony member

I don't see the current implementation as worse at all. It just means that adopting this approach requires to change some API calls.

Now changing the router is of course another option. But I am not sure if this is possible without either not supporting all the dumpers or increasing the scope of this PR to require a gigantic amount of work. Then again I guess we will get this once we have uri-template support:
http://tools.ietf.org/html/draft-gregorio-uritemplate-08
symfony/symfony#3227

@lsmith77
FriendsOfSymfony member

Btw .. in this case we would of course get around the entire controller setting business, since we would add this information into the routes. Thinking about it .. maybe we could do this today as well? Aka instead of reading the annotations at runtime, we could integrate the query param annotations into the rest route loader and write this information in there somewhere (not sure if its possible) and then read it out in the query fetcher ..

@vicb

I think you mentioned that the code should work after re-factoring. Keeping the $queryFetcher prevent this, right ? Passing it as a parameter does not solve the solution either: it would introduce coupling and legacy (/3rd party) services would not work.

@lsmith77
FriendsOfSymfony member

Prevents what? Which refactoring do you mean specifically?

@vicb

Moving some code from an action to a service (i.e. doSomeGreatStuff($request)). Wasn't that you were speaking about.
Anyway the other part doSomeLegacyStuff($request), doSome3rdPartyStuff($request) is still valid.

@lsmith77
FriendsOfSymfony member

Ah yes. Any service after the controller listener can inject the query fetcher as it is now and things will work cleanly. Any server before the controller listener will get an exception. So no surprises.

@gimler

any news?

@lsmith77
FriendsOfSymfony member

basically we have decided we want to move the matching of the query parameters to the routing layer, which would be the case once we have full support for uri-templates. now the question is if we still merge the current state and then simply break BC once uri-template support is available. or one of us works on uri-template support. should not be toooo hard and would be a huge boost for Symfony2 in general.

@ibolmo

Could you piggy back on @Route?

@lsmith77
FriendsOfSymfony member

i have been thinking some more about this over the weekend also in regards to uri-templates. one thing that i finally realized is that path parameters requirements will need to be handled differently than query parameters requirements. especially for the later it should not prevent a route match and it will usually require custom code to handle errors.

CC @Tobion

@lsmith77
FriendsOfSymfony member

ok .. unless someone brings up a new concern .. i will soon merge this PR

@stof stof and 1 other commented on an outdated diff May 5, 2012
Controller/Annotations/QueryParam.php
+ */
+
+namespace FOS\RestBundle\Controller\Annotations;
+
+/**
+ * QueryParam annotation class.
+ *
+ * @Annotation
+ * @author Alexander <iam.asm89@gmail.com>
+ */
+class QueryParam
+{
+ public $name;
+ public $requirements;
+ public $default;
+ public $description;
@stof
FriendsOfSymfony member
stof added a line comment May 5, 2012

you should probably add the annotations allowing the AnnotationReader to validate annotations as of Common 2.2 (see the ORM or @schmittjoh's bundles for instance)

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on the diff May 5, 2012
DependencyInjection/FOSRestExtension.php
@@ -128,6 +129,10 @@ public function load(array $configs, ContainerBuilder $container)
} else {
$container->setParameter($this->getAlias().'.mime_types', array());
}
+
+ if (!empty($config['query_fetcher_listener'])) {
@stof
FriendsOfSymfony member
stof added a line comment May 5, 2012

you could use if ($config['query_fetcher_listener']) { as you will always have a boolean (the node is a booleanNode and it has a default value)

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

this would mean i need to write a lot more code into the tests .. its fine like it is.

@stof
FriendsOfSymfony member
stof added a line comment May 16, 2012

well, my comment is not really accurate anymore as it is not a boolean anymore (because of force)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff May 5, 2012
Request/QueryFetcher.php
+ throw new \InvalidArgumentException('Controller needs to be set as a class instance (closures/functions are not supported)');
+ }
+
+ $this->params = $this->queryParamReader->read(new \ReflectionClass($this->controller[0]), $this->controller[1]);
+ }
+
+ /**
+ * Get a validated query parameter.
+ *
+ * @param string $name Name of the query parameter
+ *
+ * @return mixed Value of the parameter.
+ */
+ public function getParameter($name)
+ {
+ if (!isset($this->params)) {
@stof
FriendsOfSymfony member
stof added a line comment May 5, 2012

I would use if (null === $this->params) {

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff May 5, 2012
Request/QueryParamReader.php
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\RestBundle\Request;
+
+use Doctrine\Common\Annotations\Reader;
+use FOS\RestBundle\Controller\Annotations\QueryParam;
+
+/**
+ * Class loading @QueryParameter annotations from methods.
+ *
+ * @author Alexander <iam.asm89@gmail.com>
+ */
+class QueryParamReader
@stof
FriendsOfSymfony member
stof added a line comment May 5, 2012

I think you should have an interface for the QueryParamReader, allowing people to have another implementation reading from another source than annotations

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff May 5, 2012
Request/QueryFetcher.php
+ *
+ * @param QueryParamReader $queryParamReader Query param reader
+ * @param Request $request Active request
+ */
+ public function __construct(QueryParamReader $queryParamReader, Request $request)
+ {
+ $this->queryParamReader = $queryParamReader;
+ $this->request = $request;
+ }
+
+ public function setController($controller)
+ {
+ $this->controller = $controller;
+ }
+
+ private function initParams()
@stof
FriendsOfSymfony member
stof added a line comment May 5, 2012

private methods should be declared after public ones

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Tobion
FriendsOfSymfony member

I agree that query param requirements shouldn't prevent route matching. As far as I see the requirements for params have two use cases:

  • I like that the default value is returned if a requirement for a param doesn't match.
  • I guess specifiying the requirement for a param is also used for API documentation.

But I don't see what this PR has to do with URI templates, that was also discussed here. And I thought we might plan to support query params in the routing component directly. There I would implement this quite differently (without using QueryFetcher etc).

@lsmith77
FriendsOfSymfony member

See my comment above. Imho the handling of what is supposed to happen in case of a mismatch of a query parameter will usually require specific logic that cannot be sensible defined via configuration in the routing. As such imho it should be handled in the controller. All this PR does is make it easier to do so.

As for uri-templates, the point again wasn't full uri-template support, but simply query parameter support. However as I just noted I don't think that the routing configuration is the right place to handle query parameters entirely. F.e. adding a requirement in the routing would cause the route to not match. Setting defaults makes a bit more sense via the routing layer, but without being able to handle setting a default on a mismatch etc its again not flexible enough.

@Tobion
FriendsOfSymfony member

I think this is all easiliy possible in the routing, even without breaking BC. I image a new option, besides pattern, for specifying query params: let's call it query. Example:

blog_show:
    pattern:   /blog/{slug}
    query: 
        param1: {param1}
        param2: {param2}
    defaults:  { param1: 1 }
    requirements:
        param1:  \d+

As you can see, we can simply use the existing default and requirements sections and introduce a new option for queries (similar to what is planned to be merged for host requirements). But a requirement for a param in the query section will of course not be used for matching. The query params will be passed as arguements to the controller action (only the ones specified, not all). And for validating them and returning the default on mismatch can be achieved by introducing a new method in Request (in addition to the standard $request->get()). This will allow a developer to implement any specific logic in the controller he wants.

That way, it will also make the implementation independent of where the parameter comes from (path, hostname or query). So one can simply change the route without needing to adjust any code. For example we decide to change the location of param2 in the above route and we are done:

blog_show:
    pattern:   /blog/{slug}/{param2}
    query: 
        param1: {param1}
    defaults:  { param1: 1 }
    requirements:
        param1:  \d+
@lsmith77
FriendsOfSymfony member

yeah .. but isn't that super confusing that the behavior of requirements changes based on where it matched? seems like a huge security risk.

@Tobion
FriendsOfSymfony member

I don't think so. Moving a param from query to path is even more restrictive. And moving from path to query will validate the requirement and pass the default to the action if it doesnt match. And if you have a non-matching requirement but not configured a default neither in the route nor in the action (fooAction($param1)) it will create a 404 (or a specific exception). You can of course specify a default in the action to circumvent the 404 and do your custom validation and logic in the controller.

@lsmith77
FriendsOfSymfony member

its still a change in behavior that isn't very transparent to the user

@asm89
FriendsOfSymfony member

The code hasn't changed a lot from the original PoC I send. I think that if this would get merged it would be supporting the original idea? #178 In short the idea was to support the developer with checking and documenting query parameters used in api controller actions.

@Tobion
FriendsOfSymfony member

I don't see any other reasonable way to implement query params in the routing component. And it's basically the same configuration style as with the upcoming hostname-pattern option. So quite straightforward. How would you like to see it implemented in core?

@lsmith77
FriendsOfSymfony member

well imho setting a requirement on a query param should cause an exception. which is why i was considering merging this PR. however maybe we could have a "validation" section that behaves like what we described above for query parameters.

@Tobion
FriendsOfSymfony member

I think having both a requirements (for path params and hostname params) and a validation (for query params) option makes it even more confusing. People would think: Are requirements not validated? Do I need to place a param in both sections to be sure?
Btw, in your current implementation your option is called requirement, too. So also the same option name with different meaning (in @Route and in @QueryParam

@lsmith77
FriendsOfSymfony member

but its not the same configuration. the difference is that people now know how requirements in the route work. we can't just have a different behavior depending on if its a path or query parameter. the only thing we could do is disallow using requirements for query parameters. but then we would still need a way to define such validation rules. now handling of default values could indeed be done via the routing.

however right now the routing is focused on the matching process only. while i was the one suggesting to add query support to the routing layer initially .. i am not so sure it makes sense now after all.

@Tobion
FriendsOfSymfony member

My concern is, that the main point of configuring routes is that it hides the implementation. So currently you can change the order of path params or change a prefix etc. without touching code for url matching and url generation. It will still work.
Same with the hostname PR: You will be able to change the locale from a hostname {_locale}.example.org to the path without problems.
But this implementation for query params can only be used for query params. You cannot even change the param name without modifying all code. E.g. you introcude a typo for a query name or simply want to change it, like ?query=value to ?q=value. It's not possible without rewriting code.

With my idea you can simply reconfigure it like

query: 
    q: {query}

and you're done. No need to touch the templates etc.

Btw query: [param1, param2, param3] should be a shorthand for query: { param1: {param1}, param2: {param2}, param3: {param3} }. And one could do stuff like query: { price: {amout}{currency} }.

@lsmith77
FriendsOfSymfony member

well sure that could be nice in order to deal with legacy or 3rd party controllers. but i don't really think that the ability to alias query param names is something we really need in core.

what i do think we need to provide for either in core or in this bundle is the ability to:

  • define the query parameters supported by a controller action
  • define the default values for this parameters if they are not supplied
  • define validation rules for these parameters (note that here in most causes falling back to a default is the right thing, but in other cases i might also want some assistance in determine what doesn't match so that i can return a custom error message).
@breerly

this is wicked sexy, btw.

@grEvenX

This rocks @lsmith77 , what's does the fortuneteller say about when this stuff is ready to be merged into master? And what's left before that can happen?

@lsmith77
FriendsOfSymfony member

as the example shows .. it basically works ..
now .. the main question is if we agree its the right approach ..
or should this rather be done inside the routing config?

@grEvenX

From my personal view, I think this approach is just fine. But I'm not a Symfony advocate, thus my points might/should not count for much in this case. But as you said, this works, and isn't that good enough for a first version.
Couldn't the possibility to configure it through routing config be added as an option at a later stage if there is actually need for it?

@lsmith77
FriendsOfSymfony member

sure it could be added later .. or replaced with .. would just like to avoid needless confusion

@grEvenX

Yes, but isn't that the same as for Route configuration. The developer has a choice, either through routing config or annotations?

@grEvenX

Btw, trying to test this out, but I get "<CLASS> requires that you provide a value for the "$queryFetcher" argument (because there is no default value or because there is a non optional argument after this one)." when I use first parameter with QueryFetcher. I've also added the QueryParam annotation to the method. It's based on the same as your example but using annotations to build the Route etc.
What is needed in order for the QueryFetcher to be injected when the method is called?

@lsmith77
FriendsOfSymfony member
@grEvenX

Thanks for pointing that out, works now :) now off to do some real testing

@coderbyheart

I also don't think the query parameter configuration should be part of the routing configuration as this tends to change quite often and would add a lot of noise to the routing config and add more ways to introduce errors to that file.

I'd favour a more expressive solution than having one QueryParamReader which behaves essentially like the Request.

If one decides to mark up his desired query params he should get them nicely laid out for him:

/**
 * Get the list of articles
 *
 * @param int $page
 * @QueryParam(name="page", requirements="\d+", default="1", description="Page of the overview.")
 */
public function getArticlesAction($page)
{

This perfectly aligns to the request parameter configuration where you also get to use the named parameter from the routing configuration.

@lsmith77
FriendsOfSymfony member

We can easily create a request listener that does that or rather extend the current one to optionally do that. The reason I say optionally is that with what you describe all parameters would always have to be parsed and validated even if they are not used, but in most cases most of the configured query params will likely be used anyway.

@coderbyheart

Of course one could image getting some query params only conditinally:

if ($search = $queryFetcher->getParameter('search')) {
    $term = $queryFetcher->getParameter('term');
}

but I personally would just fetch all the queryparams in one block anyway and deal with them conditionally later.

$search = $queryFetcher->getParameter('search');
$term = $queryFetcher->getParameter('term');
…
if ($search) { … }
@grEvenX

I agree on the expressability part of injecting the query params.
If one defines a route with parameters and also uses queryparam, how will it affect the method signature and which (if any) would take precedence?

E.g:

/*
 * @Route("/{id}", requirements={"id" = "\d+"})
 * @QueryParam(name="id",requirements={"id" = "\d+"})
 */
public function getCustomerAction($id) 
@stof
FriendsOfSymfony member

@grEvenX The bundle does not change the request attributes, and so will not change the params available for the method arguments.

@lsmith77
FriendsOfSymfony member

@stof but we could ..

@coderbyheart

@grEvenX I think a conflict should raise an exception.

@stof
FriendsOfSymfony member

it would duplicate the param in 2 parameter bags (query and attributes). I don't think it is a good idea

@asm89
FriendsOfSymfony member

Honestly I think it doesn't make sense to inject the query parameters in your method signature. That would make your code even less portable. My original idea was that the query param thing could help you with checking very basic requirements on the query parameters (like &page should be \d+) and return a default value (1 for page) or null otherwise. The upside of this would be less checking of stuff like that "by hand", but also having controller methods annotated with the appropriate query parameters which is very nice for api documentation etc.

@coderbyheart

That would make your code even less portable.

Can you elaborate?

Do you mean, by hard coding the query params in the method signature one limits possibility of extending the method in a subclass with a different implementation which would require other params?

@lsmith77
FriendsOfSymfony member

ok .. i have implemented the option of forcing the query params to be set as attributes. on conflict it throws an exception. however we also need to improve the route generation to skip any configured query parameter.

@lsmith77
FriendsOfSymfony member

btw .. just FYI .. you can always fork this branch and submit PRs back to this branch if you have ideas for improvements. for example it would be cool of someone could fix the above noted issue with using query params in the method signature causing them to be put into the route.

@lsmith77
FriendsOfSymfony member

nevermind .. already took care of it ..
anything else people think should be done?

@lsmith77
FriendsOfSymfony member

main thing missing now are docs ..

@stof
FriendsOfSymfony member

@lsmith77 As I already said a while ago, I think you should add an interface for the QueryParamReader and use it in the typehints, to allow people to replace the implementation if they want.

@lsmith77
FriendsOfSymfony member

QueryParamReader or QueryFetcher? Anyway, I will leave that to who ever wants to make the first alternative implementation :)

@stof
FriendsOfSymfony member

probably both :)
But I was talking about the reader first, thus allowing people to write an implementation reading from elsewhere than annotations if they don't like annotations

@stof stof and 1 other commented on an outdated diff May 16, 2012
DependencyInjection/Configuration.php
@@ -39,6 +39,7 @@ public function getConfigTreeBuilder()
$rootNode
->children()
+ ->scalarNode('query_fetcher_listener')->defaultValue(false)->end()
@stof
FriendsOfSymfony member
stof added a line comment May 16, 2012

shouldn't it be a booleanNode ? And you could use defaultFalse()

@stof
FriendsOfSymfony member
stof added a line comment May 16, 2012

ok, it is not a boolean. But you should probably limit the possible values

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

whats the syntax for that?

@lsmith77
FriendsOfSymfony member
lsmith77 added a line comment May 16, 2012

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff May 16, 2012
DependencyInjection/Configuration.php
@@ -39,6 +41,12 @@ public function getConfigTreeBuilder()
$rootNode
->children()
+ ->scalarNode('query_fetcher_listener')->defaultFalse()
+ ->validate()
+ ->ifNotInArray($this->forceOptionValues)
+ ->thenInvalid('The query_fetcher_listener option does not support %s. Please choose one of '.json_encode($this->forceOptionValues))
@stof
FriendsOfSymfony member
stof added a line comment May 16, 2012

missing one indentation level

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff May 16, 2012
DependencyInjection/Configuration.php
@@ -111,7 +119,12 @@ private function addViewSection(ArrayNodeDefinition $rootNode)
->defaultValue(array('html' => true))
->prototype('boolean')->end()
->end()
- ->scalarNode('view_response_listener')->defaultValue('force')->end()
+ ->scalarNode('view_response_listener')->defaultValue('force')
+ ->validate()
+ ->ifNotInArray($this->forceOptionValues)
+ ->thenInvalid('The view_response_listener option does not support %s. Please choose one of '.json_encode($this->forceOptionValues))
@stof
FriendsOfSymfony member
stof added a line comment May 16, 2012

same here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith77 lsmith77 merged commit 0aa7534 into master May 16, 2012
@schmittjoh

About silently setting the default value on validation failure, would it not make more sense to redirect to the URL with the default value? Also in terms of SEO, and duplicate content, this seems more sensible, no?

@lsmith77
FriendsOfSymfony member

i thought about that too .. we could provide such an option as part of the listener eventually. it should of course only be down for proper GET requests. however i don't think that query parameters are that important for SEO, but it is relevant for caches i guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment