1

I try setup custom router loader like here

http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html

i want add dynamic parameter for all routes (parameter from session)

this is my code

namespace Mea\Crm4Bundle\Routing;

use Mea\Crm4Bundle\Entity\Application;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Loader\AnnotationClassLoader;
use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Config\Resource\FileResource;

class AppLoader extends YamlFileLoader
{
    private static $availableKeys = array(
        'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition',
    );
    private $yamlParser;

    private $loaded = false;
    /**
     * @var
     */
    private $annotationClassLoader;
    /**
     * @var
     */
    private $session;

    /**
     * Constructor.
     *
     * @param FileLocatorInterface $locator A FileLocatorInterface instance
     * @param AnnotationClassLoader $annotationClassLoader
     * @param Session $session
     */
    public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $annotationClassLoader, Session $session)
    {
        $this->locator = $locator;
        $this->annotationClassLoader = $annotationClassLoader;
        $this->session = $session;
    }


    public function load($file, $type = null)
    {

        $appId = $this->session->get(
            Application::CRM_APP_ID_SESSION
        );


        $path = $this->locator->locate($file);

        if (!stream_is_local($path)) {
            throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));
        }

        if (!file_exists($path)) {
            throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));
        }

        if (null === $this->yamlParser) {
            $this->yamlParser = new YamlParser();
        }

        try {
            $parsedConfig = $this->yamlParser->parse(file_get_contents($path));
        } catch (ParseException $e) {
            throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
        }

        $collection = new RouteCollection();
        $collection->addResource(new FileResource($path));

        // empty file
        if (null === $parsedConfig) {
            return $collection;
        }

        // not an array
        if (!is_array($parsedConfig)) {
            throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
        }

        foreach ($parsedConfig as $name => $config) {

            $config['defaults']['_applicationid']=$appId;

            if (isset($config['pattern'])) {
                if (isset($config['path'])) {
                    throw new \InvalidArgumentException(sprintf('The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
                }

                @trigger_error(sprintf('The "pattern" option in file "%s" is deprecated since version 2.2 and will be removed in 3.0. Use the "path" option in the route definition instead.', $path), E_USER_DEPRECATED);

                $config['path'] = $config['pattern'];
                unset($config['pattern']);
            }

            $this->validate($config, $name, $path);

            if (isset($config['resource'])) {
                $this->parseImport($collection, $config, $path, $file);
            } else {
                $this->parseRoute($collection, $name, $config, $path);
            }
        }

        return $collection;

    }

    public function supports($resource, $type = null)
    {
        return 'crmapp' === $type;
    }

}

here is routing.yml

mea_crm:
    resource: @MeaCrm4Bundle/Resources/config/routing.yml
    type: crmapp
    prefix: /{_applicationid}
    defaults:  { _applicationid: 5 }

here is services.yml

  app.routing_loader:
            class: Mea\Crm4Bundle\Routing\AppLoader
            arguments: [@file_locator, @sensio_framework_extra.routing.loader.annot_class,@session]
            tags:
                - { name: routing.loader }

This loader is fired once if i remove cache. So i think this is not what i need. How i can override router or in other way - i want setup _aplication id default value from session.

UPDATE 1

i setup router

here is working method

class RouteGenerator extends  UrlGenerator

public function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = array()){


        if(!isset($parameters[MeaCrm4Bundle::CRM_APP_SWITCH_PARAMETER])){

            //for test
            $parameters[MeaCrm4Bundle::CRM_APP_SWITCH_PARAMETER] = 1212;

        }

        $url = parent::doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes);

        return $url;
    }

when i add to parameters.yml

router.options.generator_base_class: Mea\Crm4Bundle\Routing\RouteGenerator

i have what i want - twig, controlerrs use this router and setup my parameter. Only one - this is not service so i dont have @session What is best method to get session here ?

Thy create other class - as service ? i get example to override twig generator but there exist way to override main router by service not class ?

UPDATE 2

so i override router - but dont have session - i need like here

public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null, Session $session)
    {
        $this->routes = $routes;
        $this->context = $context;
        $this->logger = $logger;
        $this->session = $session;
    }

but what now - how get session here ?

5
  • Where do you need to get back this value ? Commented Mar 26, 2016 at 15:32
  • i need it in example - i create route in template - {{ path('MeaTask_View',{id: task.id}) }} - so need to symfony auto add _applicationId from this var. route MeaTask_View is in @MeaCrm4Bundle/Resources/config/routing.yml so use this parameter but always use defaults: { _applicationid: 5 } Commented Mar 26, 2016 at 15:35
  • Yes i can setup it in listener - i do some test - to put to request, like here stackoverflow.com/questions/36223693/… but dont know how to put to symfony use as default router Commented Mar 26, 2016 at 15:39
  • So you may need a custom UrlGeneratorInterface instead Commented Mar 26, 2016 at 15:39
  • ok sounds good i try do it. Thanks Commented Mar 26, 2016 at 15:41

1 Answer 1

1

I guess you should try to implement Symfony\Component\Routing\Generator\UrlGeneratorInterface.

Or try to extends the router and register it as a service.

Then you need to create the appropriate extension following the one provided by the TwigBundle:

<service id="twig.extension.routing" class="Symfony\Bridge\Twig\Extension\RoutingExtension" public="false">
    <argument type="service" id="router" />
</service>

To pass it your custom generator:

<service id="app.twig.url_generator" class="AppBundle\Twig\Extension\RoutingExtension" public="false">
    <argument type="service" id="app.url_generator">
</service>

<service id="app.url_generator" class="AppBundle\Routing\AppUrlGenerator" public="false">
    <argument type="service" id="router">
    <argument type="service" id="session">
</service>

You need to decorate the router to load the route collection.

And don't forget to register the twig extension :)

Sign up to request clarification or add additional context in comments.

7 Comments

Ok but i need this modification for all routes not only from twig. i found - default router use parameter - router.options.generator_base_class: Mea\Crm4Bundle\Routing\RouteGenerator - i push my class and work :) but i need service - i need get session service. Is possible push service not class ? Sory - you give this info app.url_generator - ok i try now.
It is weird to pass the router as argument to your generator then push your generator back to the router. You should extend the router and override the needed methods while calling parent instead.
I not sure to i understand good - so don't use services but setup my router in parameters ?
Yes, by extending the router of the FrameworkBundle you just need to override the constructor to pass it the session and the methods of the UrlGeneratorInterface while calling the parent method. It's easier than decorate the router and less weird than passing each of them to the constructor of the other.
Im not understand how i should put seesion here , please look i update code
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.