-1

In this Symfony route

/**
 * @Route("/board/{board}/card/{card}", name="card_show", methods={"GET"}, options={})
 */
public function show(Board $board, Card $card): Response
{
    $card->getLane()->getBoard(); // Board instance
    // ...
}

How is it possible to add the {board} parameter programatically, since it is already available in {card}? Now, I always need to add two parameters, when generating links to show action.

After some research I've found the RoutingAutoBundle (https://symfony.com/doc/master/cmf/bundles/routing_auto/introduction.html#usage) which would provide the functions I need, but it's not available for Symfony 5 anymore.

Thanks.

Armin
  • 15,582
  • 10
  • 47
  • 64
  • 1
    why not change route to `/card/{card}` and be done with it? You also could just ignore the board parameter (remove it from function signature), if you retrieve board from card anyway ...... – Jakumi Aug 16 '20 at 21:36
  • Why not provide parameters in routes programmatically? I want to get rid of the required board parameter, but I also want to decorate the URI to display the structure. This is seo related. – Armin Aug 17 '20 at 09:50
  • 1
    There is a UrlGenerator(Interface) that's responsible for generating urls. If you're bend on generating stuff yourself, maybe you can extend that ... or you can hack the entire Router(Interface) – Jakumi Aug 17 '20 at 09:56
  • I don't get why some people vote this question down... – Armin Aug 17 '20 at 14:19
  • it's all about expectations. here (php/symfony) the expectation usually is, that the question should show efforts in solving the problem, with code, maybe particular error messages, none of which applies to your question. Thus the question is perceived "lazy" and might even have been closed for various reasons like opinionated / looking for resources. But the line to be drawn is quite variable and I can understand where you're coming from. *shrug* – Jakumi Aug 17 '20 at 14:42
  • Well, I am looking for the entry point, to solve my requirement with mentioned framework. It's true, there is no code I could show yet, just because I have no idea where to start. But your hint with extending the UrlGenerator, may be the glue. I'm testing it. Thanks! – Armin Aug 17 '20 at 16:39
  • Got it! My question was basically a duplicate of the mentioned questions. It didn't hurt as much as expected to decorate the default router :) – Armin Aug 18 '20 at 14:40
  • glad it worked ;o) – Jakumi Aug 18 '20 at 14:41

1 Answers1

2

Okay, after some investigation I've found this question Which lead me to this helpful answer.

My controller action (with @Route annotation) looks like this:

/**
 * @Route("/board/{board}/card/{card}", name="card_show", methods={"GET"})
 */
public function show(Card $card): Response
{
}

We just have one argument ($card) in method signature, but two arguments in route.

This is how to call the route in twig:

path("card_show", {card: card.id})

No board parameter required, thanks to a custom router.

This is how the custom router looks like:

<?php // src/Routing/CustomCardRouter.php

namespace App\Routing;

use App\Repository\CardRepository;
use Symfony\Component\Routing\RouterInterface;

class CustomCardRouter implements RouterInterface
{
    private $router;
    private $cardRepository;

    public function __construct(RouterInterface $router, CardRepository $cardRepository)
    {
        $this->router = $router;
        $this->cardRepository = $cardRepository;
    }

    public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH)
    {
        if ($name === 'card_show') {
            $card = $this->cardRepository->findOneBy(['id' => $parameters['card']]);
            if ($card) {
                $parameters['board'] = $card->getLane()->getBoard()->getId();
            }
        }
        return $this->router->generate($name, $parameters, $referenceType);
    }

    public function setContext(\Symfony\Component\Routing\RequestContext $context)
    {
        $this->router->setContext($context);
    }

    public function getContext()
    {
        return $this->router->getContext();
    }

    public function getRouteCollection()
    {
        return $this->router->getRouteCollection();
    }

    public function match($pathinfo)
    {
        return $this->router->match($pathinfo);
    }
}

Now, the missing parameter board is provided programatically, by injecting and using the card repository. To enable the custom router, you need to register it in your services.yaml:

App\Routing\CustomCardRouter:
    decorates: 'router'
    arguments: ['@App\Routing\CustomCardRouter.inner']
Armin
  • 15,582
  • 10
  • 47
  • 64