Steven Musumeche
Steven Musumeche

Reputation: 2936

Symfony Match Route with Dynamic Default Subdomain

I know it is possible to match a route on multiple subdomains, like this:

irc_backend.report.stacking_issue:
    path: /reports/stacking-issues
    host: {subdomain}.domain.com
    defaults:  
        _controller: IRCBackendBundle:Reports/Product/StackingIssueReport:index
        subdomain: backend
    requirements:
        subdomain: backend|dev.backend

This works, but the problem with this approach is that every time I generate a URL using the router, I have to specify which subdomain to use. I was hoping to avoid having to pass in the current subdomain everytime I get a url from the router and instead default to the same subdomain as the current request. I need a way to dynamically set the default subdomain value:

irc_backend.report.stacking_issue:
    path: /reports/stacking-issues
    host: {subdomain}.domain.com
    defaults:  
        _controller: IRCBackendBundle:Reports/Product/StackingIssueReport:index
        subdomain: %subdomain%
    requirements:
        subdomain: backend|dev.backend

I tried using an event listener to set a container parameter, but by the time the listener is called, the container is already compiled, so you get a "Impossible to call set() on a frozen ParameterBag." if you try to set a container parameter there.

Upvotes: 1

Views: 1300

Answers (1)

Bogusław Wójcik
Bogusław Wójcik

Reputation: 109

Unfortunately Symfony alone does not have yet a built-in feature to recycle missing route parameters from a current route - something I believe will need to be addressed with rising number of SaaS solutions at least for host residing route parameters. I have solved the exact same problem by simply extending Symfony\Bridge\Twig\Extension\RoutingExtension in a way that if no domain parameter is being given to a view helper a current respective routing parameter is provided.

I have created a DomainAwareRoutingExtension class in AppBundle\Extension\Twig as follows

<?php

namespace AppBundle\Extension\Twig;

use Symfony\Bridge\Twig\Extension\RoutingExtension;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class DomainAwareRoutingExtension extends RoutingExtension
{

    /** @var \Symfony\Component\HttpFoundation\Request */
    private $request;

    /**
     * DomainAwareRoutingExtension constructor.
     *
     * @param UrlGeneratorInterface  $generator
     * @param null|RequestStack      $requestStack
     */
    public function __construct(UrlGeneratorInterface $generator, RequestStack $requestStack = null)
    {
        parent::__construct($generator);

        $this->request = ($requestStack) ? $requestStack->getCurrentRequest() : null;
    }

    public function getPath($name, $parameters = [], $relative = false)
    {
        if (empty($parameters['domain']) && !empty($this->request) && !empty($this->request->attributes->get('domain'))) {
            $parameters['domain'] = $this->request->attributes->get('domain');
        }
        return parent::getPath($name, $parameters, $relative);
    }

}

and registered it as a service

#services.yml
parameters:
twig.extension.routing.class: AppBundle\Extension\Twig\DomainAwareRoutingExtension

services:
    twig.extension.routing:
        class: '%twig.extension.routing.class%'
        public: false
        arguments:
            - '@router'
            - '@request_stack'

In your case you should just replace 'domain' in the code with 'subdomain'. Credit for inspiration goes to @Cerad and @Gambit for Symfony2 Twig overriding default path function.

Upvotes: 2

Related Questions