symfony / symfony

The Symfony PHP framework
https://symfony.com
MIT License
29.64k stars 9.42k forks source link

Host Locale Feature Not Applied to Static Routes #58086

Open tugrul opened 3 weeks ago

tugrul commented 3 weeks ago

Symfony version(s) affected

6.4.10

Description

The host locale feature in Symfony is intended to set the locale based on the request's host. However, this feature does not work for static routes defined in routing configuration files. While the host locale is correctly applied when using annotation routes, static routes do not respect this configuration, resulting in the inability to serve localized static content like robots.txt based on the domain or subdomain.

How to reproduce

Expected config (it not works)

robots_txt:
  path: /robots.txt
  host:
    en: example.uk
    de: example.de
  defaults:
    _controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
    _format: txt
    template: static/robots.txt.twig

Workaround (it works)

robots_txt.en:
  path: /robots.txt
  host: example.uk
  defaults:
    _locale: en
    _controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
    _format: txt
    _canonical_route: robots_txt
    template: static/robots.txt.twig
robots_txt.de:
  path: /robots.txt
  host: example.de
  defaults:
    _locale: de
    _controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
    _format: txt
    _canonical_route: robots_txt
    template: static/robots.txt.twig

Possible Solution

No response

Additional Context

No response

xabbuh commented 3 weeks ago

Can you create a small example application that allows to reproduce your issue?

smnandre commented 3 weeks ago

I've looked at the code and think i understand what is happening here

In the YamlFileLoader, the

https://github.com/symfony/symfony/blob/c3bb47abc921b23d84591b1d9e2bdbdcc88b31fc/src/Symfony/Component/Routing/Loader/YamlFileLoader.php#L158-L168

The following line is the key to the problem

$this->addHost($routes, $config['host']);

This is called on "$routes", which is not the original $collection of the method, but a temporary one, containing the route that was just added to it.

See how createLocalizedRoute works in this specific case ($routes is a fresh instance, not the $collection passed in argument)

https://github.com/symfony/symfony/blob/c3bb47abc921b23d84591b1d9e2bdbdcc88b31fc/src/Symfony/Component/Routing/Loader/Configurator/Traits/LocalizedRouteTrait.php#L55-L58

        $routes->addDefaults($defaults);
        $routes->addRequirements($requirements);
        $routes->addOptions($options);
        $routes->setSchemes($config['schemes'] ?? []);
        $routes->setMethods($config['methods'] ?? []);
        $routes->setCondition($config['condition'] ?? null);

Theses methods work as expected because they are all implemented to apply the data to all its children

But here is the source of the troubles

        if (isset($config['host'])) {
            $this->addHost($routes, $config['host']);
        }

Because addHost either apply the data to its children or ... removes a route from the collection and adds new ones.

https://github.com/symfony/symfony/blob/c3bb47abc921b23d84591b1d9e2bdbdcc88b31fc/src/Symfony/Component/Routing/Loader/Configurator/Traits/HostTrait.php#L29-L39

So in this specific scenario, the $routes variable will contain the correct routes in the end, but not the $collection on which parseRoute is working.


Now, not sure what is the best way to fix this.. maybe try to remove these "temporary collections" ?

smnandre commented 3 weeks ago

@xabbuh

On a new symfony app

{# config/routes.yaml #}
robots_txt:
    path: '/robots.txt'
    defaults:
        _controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
        _template: 'robots.txt.twig'
    host:
        en: 'www.example.com'
        nl: 'www.example.nl'
        de: 'www.example.de'
php bin/console debug:router

Expected

 --------------- -------- -------- ----------------- -------------- 
  Name           Method   Scheme   Host              Path          
 --------------- -------- -------- ----------------- -------------- 
  robots_txt.en   ANY      ANY      www.example.com   /robots.txt  
  robots_txt.nl   ANY      ANY      www.example.nl    /robots.txt  
  robots_txt.de   ANY      ANY      www.example.de    /robots.txt  
 --------------- -------- -------- ----------------- -------------- 

Results

 ------------ -------- -------- ------ -------------
  Name         Method   Scheme   Host   Path
 ------------ -------- -------- ------ -------------
  robots_txt   ANY      ANY      ANY    /robots.txt
 ------------ -------- -------- ------ -------------