Pergunta

I want to copy a query param of a given request url automatically to all urls generated by my routes.

Lets say someone requests example.com/en?preview=true. So I want all urls generated on this page to also have the preview=true query param appended automatically, i.e. without updating all my route definitions.

I tried adding the preview param as a default for all existing routes in a onKernelRequest listener but didn't get very far.

Thanks in advance

Foi útil?

Solução

I've solved it myself by extending the default framework router.

# src/Your/Bundle/Resources/config/service.yml
parameters:
    router.class: Your\Bundle\Routing\PreviewRouter


<?php    
// src/Your/Bundle/Routing/PreviewRouter.php

namespace Your\Bundle\Routing;

use Symfony\Bundle\FrameworkBundle\Routing\Router as BaseRouter;

/**
 * extends the base router's generate function to always append
 * the preview query param on all generated urls
 */
class PreviewRouter extends BaseRouter
{

    public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
    {
        // parent router generates url
        $url = parent::generate($name, $parameters, $referenceType);

        // check for existing preview query string
        parse_str($this->getContext()->getQueryString(), $contextQueryParams);
        if(isset($contextQueryParams['preview']) && filter_var($contextQueryParams['preview'], FILTER_VALIDATE_BOOLEAN))
        {
            // put possible query string params into $queryParams array
            $urlParts = parse_url($url);
            parse_str(isset($urlParts['query']) ? $urlParts['query'] : '', $urlQueryParams);

            // strip everything after '?' from generated url
            $url = preg_replace('/\?.*$/', '', $url);

            // append merged query string to generated url
            $url .= '?'.http_build_query(array_merge(
                array('preview' => $contextQueryParams['preview']),
                $urlQueryParams
            ));
        }

        // remove preview param if set to false deliberately
        $url = preg_replace('/(\?|&)preview=(false|0|off)/', '', $url);

        return $url;
    }

}

Outras dicas

I have a possible implementation, there are some caveats however. If the urls you generate already have query strings on them this wont work.

You will need to create a new Twig Filter Extension. Lets start by creating the extension class. You will want to likely move and change this from the acme demo.

//src/Acme/DemoBundle/Twig/AcmeExtension.php
<?php
namespace Acme\DemoBundle\Twig;

class AcmeExtension extends \Twig_Extension
{
    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('queryString', array($this, 'queryStringFilter')),
        );
    }

    public function queryStringFilter($array)
    {
        return http_build_query($array);
    }

    public function getName()
    {
        return 'acme_extension';
    }
}

Then you will need to register this new extension as a service:

//src/Acme/DemoBundle/Resources/config/services.yml
parameters:
    acme_demo.acme_extension.class: Acme\DemoBundle\Twig\AcmeExtension

services:
    acme_demo.acme_extension:
        class: %acme_demo.acme_extension.class%
        tags:
            - { name: twig.extension }    

Then you will need to include this new service in your main config:

//app/config/config.yml
imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: "@AcmeDemoBundle/Resources/config/services.yml" }    

Then when you are generating your routes in your twig files:

<a href="{{path('some_route_id')}}?{{app.request.query.all|queryString}}">This will have your query string appended.</a>

You can add all existing queries as a second parameter to your path call:

<a href="{{ path('my_route', app.request.query.all)}}">My Link</a>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top