0

The original post: https://github.com/symfony/symfony/discussions/43960

I want to use a QueryParam attribute to read a query string into a Controller method argument.

An example controller class.

#[Route("/posts")]
class PostController extends AbstractController{
    //... other methods.

    #[Route(path: "", name: "all", methods: ["GET"])]
    function all(#[QueryParam] string $keyword,
                 #[QueryParam] int $offset = 0,
                 #[QueryParam] int $limit = 20): Response
    {
        $data = $this->posts->findByKeyword($keyword || '', $offset, $limit);
        return $this->json($data);
    }
}

Then I tried to create a QueryParam attribute and a custom ParamConverter to archive the purpose.

#[Attribute(Attribute::TARGET_PARAMETER)]
final class QueryParam
{
    private string $name;

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $name
     * @return QueryParam
     */
    public function setName(string $name): QueryParam
    {
        $this->name = $name;
        return $this;
    }
}

The source codes of QueryParamParamConverter.

class QueryParamParamConverter implements ParamConverterInterface, LoggerAwareInterface
{
    public function __construct()
    {
    }

    private LoggerInterface $logger;

    /**
     * @inheritDoc
     * @throws ReflectionException
     */
    public function apply(Request $request, ParamConverter $configuration): bool
    {
        $param = $configuration->getName();
        $this->logger->debug("configuration name: " . $param);
        $className = $configuration->getClass();
        $reflector = new ReflectionClass($className);
        $attrs = $reflector->getAttributes(QueryParam::class);
        $attr = $attrs[0];
        $name = $attr->getArguments()[0] ?? $param;
        $value = $request->attributes->get($param);
        $this->logger->debug("set request attribute name: " . $name . ", value: " . $value);
        $request->attributes->set($name, $value);
        return true;
    }

    /**
     * @inheritDoc
     * @throws ReflectionException
     */
    public function supports(ParamConverter $configuration): bool
    {
        $className = $configuration->getClass();
        $this->logger->debug("class name:" . $className);
        if ($className) {
            // determine this method argument is annotated with `QueryParam`?
        }

        return false;
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

The $className = $configuration->getClass(); always return empty string instead of a class name.

I am not sure what is the best way to select a method argument with QueryParam.

Hantsy
  • 8,006
  • 7
  • 64
  • 109
  • Please paste your route. and which keyword from route you needed – Ravi Damasiya Nov 09 '21 at 11:22
  • Too many types of annotation make the code difficult to read and reflection slows the application. – Daniel W. Nov 09 '21 at 12:38
  • @DanielW. If Symfony read all of these controller metadata info(like the config in the *config* folder) and store it to share globally in future steps the performance is not a big problem. – Hantsy Nov 09 '21 at 14:14

0 Answers0