Skip to content
This repository was archived by the owner on Feb 24, 2023. It is now read-only.

[WIP] Replace Param converter with configurable argument resolvers #436

Closed
wants to merge 3 commits into from

Conversation

fabpot
Copy link
Member

@fabpot fabpot commented Sep 23, 2016

needs symfony/symfony#20036 for more advanced usage.

@fabpot
Copy link
Member Author

fabpot commented Sep 23, 2016

Some usage examples:

    /**
     * @Route("/posts/{slug}", name="blog_post")
     * @Method("GET")
     * @Arg("post", expr="repository.findOneBySlug(slug)")
     * This @Arg is technically not needed, but here as a usage example
     */
    public function postShowAction(Post $post)
    {
    }
    /**
     * @param Post[] $posts
     *
     * @Route("/", defaults={"page": 1}, name="blog_index")
     * @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="blog_index_paginated")
     * @Method("GET")
     * @Cache(smaxage="10")
     * @Arg("posts", expr="repository.findLatest(page)")
     */
    public function indexAction($posts, $page)
    {
    }
    /**
     * @Route("/{start}/{stop}", defaults={"stop": "2009-09-09"})
     * @Template()
     *
     * @Arg("start", format="Y-m-d:H:i:s")
     */
    public function indexAction(\DateTime $start = null, \DateTime $stop)
    {
        return ['start' => $start, 'stop' => $stop];
    }

@fabpot fabpot changed the title Replace Param converter with configurable argument resolvers [WIP] Replace Param converter with configurable argument resolvers Sep 23, 2016
'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\ParamConverterManager',
));
if ($config['request']['resolvers']) {
$annotationsToLoad[] = 'resolvers.xml';
Copy link
Contributor

Choose a reason for hiding this comment

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

What if you want to use the @Arg feature without using the default set of resolvers? If I'm not using doctrine nor the datetime resolver in a project, I don't really need them but would like to expand on the feature.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, performance/configurability/lazyness is something that needs to be done. This is an early PoC.

*/
class Arg
{
private $arg;
Copy link
Contributor

Choose a reason for hiding this comment

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

This one is meant to be stand-alone and not a ConfigurationInterface implementation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is handled in a total different and more flexible way (options are validated via OptionsResolver). I think ConfigurationInterface should die :)

Copy link
Contributor

Choose a reason for hiding this comment

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

It's still a pretty cool extension point and used by some packages. Anyway, this is probably a challenge for later on.

https://github.com/FriendsOfSymfony/FOSHttpCacheBundle/blob/master/Configuration/InvalidatePath.php
https://github.com/jaytaph/RateLimitBundle/blob/master/Annotation/RateLimit.php
https://github.com/mayeco/EasyAnnotationBundle

Google in:github.com "extends ConfigurationAnnotation"


if (!is_array($controller)) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In theory normal functions can be controllers too (afaik anonymous doesn't support docblocks but not sure), this would make it a string, I think the same goes for static declared methods in a string 'Foo::barAction'.

Copy link
Member Author

Choose a reason for hiding this comment

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

Anonymous functions do support docblocks, but unfortunately, this is a known limitation of Doctrine Annotations: doctrine/annotations#83

throw new LogicException(sprintf('Wrong @Arg configuration for argument "%s" on "%s".', $name, $context), 0, $e);
}

$event->getRequest()->attributes->set($parameter->getName().'_options', $options);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah nice leveraging the use of the old setup here, that would prevent them from being executed unless they set a higher priority on their own converter. This should probably be documented as pitfall if they decide to use a higher priority and still try to use @Arg.

@@ -69,26 +111,26 @@ public function apply(Request $request, ParamConverter $configuration)
// find by identifier?
} elseif (false === $object = $this->find($class, $request, $options, $name)) {
// find by criteria
// FIXME: to be done elsewhere for expr for instance
$method = $method->isArray() ? 'findBy' : 'findOneBy';
Copy link
Contributor

Choose a reason for hiding this comment

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

$method->isArray() should probably be $metadata->isArray()

I think this case should only occur when guessing, otherwise it's simply a miss-configuration. If it's an array requested, it should probably never even hit findOne cases and thus never have an identifier in the URL. That means it can only be findBy and deserves its own case in this construction

@linaori
Copy link
Contributor

linaori commented Sep 23, 2016

This solution looks a lot more elegant than ParamConverters and feels less like a "hack". Is there any specific reason to not have this in Symfony (+doctrine bridge) instead of the bundle at this point? As long as the feature is opt-in it should be all cool.

@fabpot
Copy link
Member Author

fabpot commented Sep 23, 2016

@iltar Having this part of Symfony is indeed a possibility that I've thought of. Creating a new HttpKernel Annotation sub-namespace is one idea, creating a new Annotation component is another one. In any case, I'd like this code to be moved outside of a bundle as it can be useful to Drupal or Silex as well.

@linaori
Copy link
Contributor

linaori commented Sep 23, 2016

Not just Drupal or Silex, pretty much every framework could use this ^^

@Koc
Copy link
Contributor

Koc commented Sep 23, 2016

How we can understand what repository to use when loading array of posts? By parsing param phpdoc?

@stof
Copy link
Contributor

stof commented Sep 23, 2016

This is a huge BC break as long as the SecurityListener is not refactored to run after argument resolvers, as it would mean that the expression does not receive the converted arguments anymore.

$method = new \ReflectionMethod($className, $controller[1]);
$annotations = $this->reader->getMethodAnnotations($method);
$context = $className.'::'.$controller[1].'()';
$argumentMetadata = $this->metadataFactory->createArgumentMetadata($controller);
Copy link
Contributor

Choose a reason for hiding this comment

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

I was just thinking this might need some internal caching so that it's only generated once. Arguments will now be generated in this method and the HttpKernel.

Could probably store it in an array internally at least for the current request:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php

*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ParamConverterInterface

Choose a reason for hiding this comment

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

We should deprecate it first in 3.x, shouldn't we?

fabpot added a commit to symfony/symfony that referenced this pull request Feb 2, 2017
… resolvers (chalasr)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[HttpKernel][FrameworkBundle] Lazy load argument value resolvers

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

The ArgumentResolver resolves an arg using the first ArgumentValueResolver which `supports()` it (which can be complex, see e.g. [sensiolabs/SensioFrameworkExtraBundle#436](https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/436/files#diff-865d48d9369c4431bce36ba642834570R10)).

Commits
-------

02b4aaa [HttpKernel] Lazy load argument value resolvers
@TomasVotruba
Copy link
Contributor

Any ETA?

@fabpot
Copy link
Member Author

fabpot commented Sep 12, 2020

Closing in favor of symfony/symfony#37829

@fabpot fabpot closed this Sep 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy