1

I am using Symfony CMF, it has a RoutingAutoBundle, which exposes these parameters:

cmf_routing_auto:
    ....
    persistence:
        phpcr:
            route_basepath: /routes

I need to set the route_basepath dynamically on the go, is it possible to change config.yml values dynamically?

I am building a CMS that is isolated for every user, to do this, i am storing every users routes in his own PHPCR document.

My idea is to change the routers basepath based on the request HTTP_HOST and or subdomain, in a early request listener.

EDIT

Here is the structure.

enter image description here

  • You should create a config for your specific environment. Such as config_subdomain. Then load the desired environment in your AppKernel. – Will B. Mar 03 '17 at 16:01
  • Users and "Site" documents which contain routes to that specific site are created on the go, so this would be a bad idea, it has to be edited. –  Mar 03 '17 at 16:07
  • You can use a parameter, or multiple parameters but your application would need to know where the desired `routes` is located as a parameter to include in your config.yml. EG: `route_basepath: '%kernel.user_routes%'` I use `%router.request_context.host%` for my own, but have my applications isolated by configuration. – Will B. Mar 03 '17 at 16:16
  • My application would match the desired routes based on the HTTP_HOST or the subdomain, the desired routes is stored in the database, and would be mapped to a HOST or some specific trait. –  Mar 03 '17 at 16:29

1 Answers1

2

For anyone else trying to do this, it's quite a complicated task when you are new to the CMF bundle and AutoRouting, the route_basepath, cannot be changed dynamically by event listeners etc, if you are depending on the request, the request will not be available at that point.

I managed to do it by doing the following:

Override the "cmf_routing.phpcr_candidates_prefix" service, and replace all references to it with your own candidates prefix service.

class OverrideRoutePrefixListener implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $routePrefixDefinition = $container->getDefinition('cmf_routing.phpcrodm_route_idprefix_listener');
        $routePrefixDefinition->replaceArgument(0, new Reference('app.phpcr_candidates_prefix'));

        $routeLocalePrefixDefinition = $container->getDefinition('cmf_routing.phpcrodm_route_locale_listener');
        $routeLocalePrefixDefinition->replaceArgument(0, new Reference('app.phpcr_candidates_prefix'));
    }
}

Your own service should subclass the original and change the constructor, you might have to copy a bunch of the private fields etc.

public function __construct(array $prefixes, array $locales = array(), ManagerRegistry $doctrine = null, $limit = 20)
{
    // Do something else here, if you just want multiple prefixes, its supported by the config 
    // But if you want to fetch them from the database or the like, you have to do this.
    $prefixes = ['/users/admin/sites/test/routes', '/users/admin/sites/test/simple'];

    parent::__construct($prefixes, $locales = array(), $doctrine = null, $limit = 20);
    $this->setPrefixes($prefixes);

    $this->doctrine = $doctrine;
}

Inside of your own cmf_routing.phpcr_candidates_prefix, you are free to resolve the prefix to whatever you want.

The second step is overriding the PhpcrOdmAdapter, you can do this with a compiler pass aswell.

class OverridePhpcrOdmAdapter implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $definition = $container->getDefinition('cmf_routing_auto.adapter.phpcr_odm');
        $definition->setClass(PhpcrOdmAdapter::class);
    }
}

And change the base path at the constructor.