Symfony 3.0.9路由器generateUrl相对路径

时间:2016-09-13 10:54:25

标签: methods routing symfony

我想使用twig函数路径(' route_name')和路由器生成器的generateUrl方法,在我的symfony项目中呈现多域的相对链接。

解决方案听起来很简单,同时让routing.yml正确地调整并简单地调用这些方法。但它不起作用。如果有任何人遇到同样的问题或者知道问题是什么,我将不胜感激。

转储$this->container->get('router')时,我可以看到请求主机是我请求的主机:local.domain.com

protected 'generator' => 
    object(appDevUrlGenerator)[2301]
      protected 'routes' => null
      protected 'context' => 
        object(Symfony\Component\Routing\RequestContext)[247]
          private 'baseUrl' => string '/app_dev.php' (length=12)
          private 'pathInfo' => string '/my/link/path' (length=34)
          private 'method' => string 'GET' (length=3)
          private 'host' => string 'local.domain.com' (length=13)

但是在symfony官方示例中调用方法:http://symfony.com/doc/current/routing.html#generating-urls

我得到绝对网址,或者更确切地说是使用在routing.yml中编写的默认域名的网址

默认值:{page_domain:domain.com}

我不太确定这是否是问题,因为请求带有正确的主机。

为什么函数不生成相对URL?如果您需要任何其他信息进行调试,请随时提出。我会发布您需要的所有内容。

最诚挚的问候,MiKE

2 个答案:

答案 0 :(得分:2)

这是因为您通过将整个或部分域作为路由参数来定义路由或路由资源以对主机敏感 - 这是 SaaS 体系结构中的常见解决方案。如果当前主机与提供的主机不同,则Symfony始终生成完整URL,如果没有给出,则默认生成默认值。您的路由可能如下所示:

#routing.yml
app:
    resource: "@AppBundle/Controller/"
    type:     annotation
    prefix:   /
    host:     "{page_domain}"
    requirements:
        page_domain: ".+"
    defaults:
        page_domain: "domain.com"

当框架生成URL时,它需要知道生成它的域 - 如果您没有明确提供它,它将回退到默认设置。您可以很容易地想象,虽然client1.domain.com中生成的大多数链接也应该指向client1.domain.com,但从技术上讲,它仍然可以从client1.domain中生成到client2.domain.com的跨域链接。 .COM。您需要意识到,在您的情况下,域是与任何其他域相同类​​型的路由参数。您只需在URL生成期间提供当前域。

在Twig中你可以这样做:

{{ path('your_route_name', {'page_domain': app.request.attributes.get('page_domain')}) }}

在控制器中它看起来像这样:

    $url = $this->generateUrl(
        'your_route_name',
        ['page_domain' => $this->get('request_stack')->getCurrentRequest()->attributes->get('page_domain')]
    );

答案 1 :(得分:0)

就我所见,这是一个正常的"如果路由将主机作为参数处理,则会出现问题。 在这种情况下,如果您使用的是另一个主机而不是默认主机,则默认的Twig函数path()将生成与架构相关的URI。 例如,代替/homepage,它将提供//www.example.com/homepage

我的解决方法是覆盖Twig默认功能的默认行为。在这种情况下,工作非常简单。

我们说我们有这个文件routing.yml

administration:
    resource: "@AppBundle/Controller/"
    type:     annotation
    host: "{_host}"
    defaults:
        _host: "%app.host.default%"
    requirements:
        _host: "%app.host.regex%"

这意味着我们的主机参数是名称_host

将此代码添加到文件AppBundle/Twig/RoutingExtension.php(或您的捆绑包中):     

namespace AppBundle\Twig;

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

/**
 * Class RoutingExtension
 * Overrides the {@see BaseRoutingExtension::getPath()} method to fix issue on Twig's function path() returning
 * schema-relative URI instead of path-relative.
 *
 * @package AppBundle\Twig
 */
class RoutingExtension extends BaseRoutingExtension
{
    /**
     * @var RequestStack $requestStack
     */
    private $requestStack;

    /**
     * @var string $host
     */
    private $host;

    /**
     * @inheritdoc
     */
    public function __construct(UrlGeneratorInterface $_generator, RequestStack $_requestStack)
    {
        parent::__construct($_generator);
        $this->requestStack = $_requestStack;
    }


    /**
     * @inheritdoc
     */
    public function getPath($_name, $_parameters = [], $_relative = false)
    {
        // fastening the _host value, as cannot be loaded in constructor
        if (!$this->host) {
            $this->host = $this
                ->requestStack
                ->getCurrentRequest()
                ->attributes
                ->get('_host')
            ;
        }

        // merges the parameters, keep "_host" key priority from the given $_parameters
        $parameters = array_merge(
            $_parameters,
            [
                '_host' => $this->host,
            ]
        );

        // generate the route as usual
        return parent::getPath($_name, $parameters, $_relative);
    }
}

注意方法getPath,将_host替换为routing.yml中的密钥。

现在,我们所要做的就是将其声明为要使用的服务而不是本地服务。转到您的文件services.yml

services:
  twig.extension.routing:
    class: AppBundle\Twig\RoutingExtension
    tags:
      - { name: twig.extension }
    arguments:
      - "@router"
      - "@request_stack"

这就是全部!您不必编辑任何Twig:Twig文件将使用此更改。清楚地注意内部服务的关键:它必须是twig.extension.routing!如果你改变了这一点,那么所有代码​​都不会起作用,Twig将继续生成我们试图解决的那些模式相对。