Is it possible to make the default parameter values for routes dynamic in symfony2?
Asked Answered
U

5

5

I have a route defined in a symfony2 controller using annotations. EG:

@Route("/{year}", name="show_list_for_user", defaults={ "year" = "2012" })

Is it possible to make make the default year dynamic. Maybe to read the year from a service object?

Unlade answered 9/8, 2012 at 14:43 Comment(0)
W
2

I'm afraid that is not possible, the defaults are static.

Windblown answered 9/8, 2012 at 14:50 Comment(0)
O
11

You can set default parameters in RequestContext.

When Symfony generates an URL, it uses values in this order:

See Symfony\Component\Routing\Generator\UrlGenerator::doGenerate :

$mergedParams = array_replace($defaults,
                              $this->context->getParameters(),
                              $parameters);
  1. user supplied parameters to generateUrl() function
  2. context parameters
  3. route defaults

You can set the context parameters in a request event listener to override Route defaults:

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Routing\RouterInterface;

class RequestListener
{
    private $_router;

    public function __construct(RouterInterface $router)
    {
        $this->_router = $router;
    }

    public function onRequest(GetResponseEvent $event)
    {
        $context = $this->_router->getContext();
        if (!$context->hasParameter('year')) {
            $context->setParameter('year', date('Y'));
        }
    }
}

Service configuration:

<service id="my.request_listener"
         class="MyBundle\EventListener\RequestListener">

    <argument id="router" type="service"/>

    <tag name="kernel.event_listener"
         event="kernel.request" method="onRequest" />
</service>

It depends on a use case, if you want to use dynamic default just to generate url, use code above. If you want your controller to dynamically pick right default value before executing action, you could probably use 'kernel.controller' event and set request attributes if not present.

Ormiston answered 21/11, 2012 at 14:22 Comment(2)
Using an kernel.request listener and using the RouterContext is a very smart solution. Thanks!Comyns
Currently (Symfony 5.3), the RouterListener has a priority of 32, so this listener must have a higher priority to work as expected. So it does in my case, where I set the domain parameter current host to support multiple hosts for my two main app contexts.Bookbinder
L
4

This is not possible, but workarounds do exist. Create an additional controller which handles the default case.

Method a - forward the request

/**
 * @Route("/recent", name="show_recent_list_for_user")
 */
public function recentAction()
{
    $response = $this->forward('AcmeDemoBundle:Foo:bar', array(
        'year' => 2012,
    ));

    return $response;
}

Method b - redirect the request

/**
 * @Route("/recent", name="show_recent_list_for_user")
 */
public function recentAction()
{
    $response = $this->redirect($this->generateUrl('show_list_for_user', array(
        'year' => 2012,
    )));

    return $response;
}
Langobard answered 9/8, 2012 at 18:33 Comment(0)
W
2

I'm afraid that is not possible, the defaults are static.

Windblown answered 9/8, 2012 at 14:50 Comment(0)
B
2

Use as default a placeholder, something like

defaults={ "year" = "CURRENT_YEAR" }

then in your controller do something like:

if ($year == "CURRENT_YEAR") {
    $year = //do something to find the current year
}
Basion answered 9/8, 2012 at 15:36 Comment(1)
This would create a url with the place holder in it. I dont really want that.Unlade
I
0

2023 version of Ludeks answer:


namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\RouterInterface;

#[AsEventListener(
    event: 'kernel.request',
    method: 'onRequest',
    priority: 0
)]
class RequestListener
{
    public function __construct(
        private readonly RouterInterface $router
    ) {
    }

    public function onRequest(RequestEvent $event): void
    {
        $context = $this->router->getContext();
        if (!$context->hasParameter('version')) {
            $context->setParameter('version', 1);
        }
    }
}
Inevitable answered 8/8, 2023 at 16:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.