Symfony2 包继承丢失父包路由

Posted

技术标签:

【中文标题】Symfony2 包继承丢失父包路由【英文标题】:Symfony2 bundle inheritance losing parent bundles routes 【发布时间】:2012-03-11 12:28:36 【问题描述】:

我正在尝试按照here 中的说明创建一个简单的包继承,但遇到了路由问题。我正在使用注释进行路由。当我在 AppKernel.php 中注册我的子包时,我所有的父包路由都丢失了。

根据我从文档中了解到的情况,Symfony2 应该首先从子包中查看所有文件,包括路由,然后从父包中查看。现在这没有发生,似乎只加载了子捆绑控制器。

在我的子捆绑包文件中,我按照说明实现了 getParent 函数,在我的 routing.yml 中我有:

ParentBundle:
resource: "@Parent/Controller/"
type:     annotation
prefix:   /admin/

在继承之前运行良好。

我已经测试过,如果在 routing.yml 中单独包含所有控制器文件,系统可以正常工作,但这似乎很麻烦,因为我只想覆盖父包的少数部分(不是所有控制器)。

Profiler 显示我的两个包都处于活动状态。

【问题讨论】:

【参考方案1】:

我找到了解决这个问题的正确方法。今天我还试图覆盖一个配置了注释路由的父包,并且还发现如果注释路由导入了整个包(“@SomeBundle/Controller”),父路由被忽略了。

经过一点调试,我发现对此的解释是,如果您使用“@”作为控制器的前缀,这将传递给内核解析器,如果父资源已被覆盖,它将仅返回子资源。所以解决方案是提供包的完整路径,考虑到内核会尝试匹配 app/Resources 中的资源,所以你必须添加一个相对目录(../../ ) 在实际路径之前:

# app/config/routing.yml:
some_parent:
    resource: "../../src/Application/ParentBundle/Controller"
    type: annotation

# ChildBundle implements getParent() method to inherit from ParentBundle
some_child:
    resource: "@ChildBundle/Controller"
    type: annotation

这将按预期工作:所有父路由将被导入并被子包中指定的所有路由覆盖。

【讨论】:

即使 3 年后我发现这很有用,虽然有点出乎意料,即使你在同一个包中扩展控制器,父路由注释也会被忽略,所以如果你想要共享代码,你必须诉诸于一个 trait 或使用一个 SharedController,它们都从它们扩展而来,但其中没有路由 拯救了我的一天。非常感谢您的解决方案 即使在 2017 年,这也是非常有用的信息。坦克为此!【参考方案2】:

除了之前的答案,我还必须更改子包的 routing.yml 的名称(例如更改为 routing_child.yml)才能使其正常工作。我认为这是因为如果名称相同,Symfony 会完全忽略父捆绑路由文件。

编辑: 在许多情况下,将父捆绑路由导入子捆绑路由文件也很实用,如下所示:

# routing_child.yml     
_parent:
    resource: "@MyParentBundle/Resources/config/routing.yml"

【讨论】:

这似乎是最简单的方法恕我直言,绝对或相对路径,如下所述对我不起作用 当使用包继承时,Symfony 会覆盖任何同名文件(无论是模板还是配置文件)。 这也是我最终解决它的方式,在 FOSUserBundle 的帮助下【参考方案3】:

官方文档说您只需将父路由文件复制到您的子包:

“覆盖”捆绑包路由的最简单方法是根本不导入它。无需导入第三方包的路由,只需将该路由文件复制到您的应用程序中,对其进行修改,然后再导入即可。

此外,您不能使用符号名称“@ParentBundle”包含父包路由文件,因为此名称被解析为“@ChildBundle”。

如果你真的想包含父路由文件,那么你应该使用该文件的绝对路径或相对于当前目录的路径,即:

# @YourChildBundle/Resources/routing.yml
YourParentBundle:
  resource: "/srv/www/example.com/src/Your/ParentBundle/Resources/routing.yml"

# @YourChildBundle/Resources/routing.yml
YourParentBundle:
  resource: "../../../../../Your/ParentBundle/Resources/routing.yml"

另一种解决方法是将您的父路由文件符号链接到您的子包中,并将其包含在较短的路径中,即:

cd YourChildBunde
ln -s ../../../../../Your/ParentBundle/Resources/routing.yml parent_routes.yml

然后

# @YourChildBundle/Resources/routing.yml
YourParentBundle:
  resource: "parent_routing.yml"

附:我希望他们能找到一些更好且不那么丑陋的方法来覆盖和扩展父捆绑包的路由,但现在我们必须找到一些丑陋的解决方法。

【讨论】:

不得不说,尽管你说这些很丑,但符号链接几乎是丑得无法提及。【参考方案4】:

通过包继承,您可以覆盖父包的文件。

如果您在与 bundle 中的父文件相同的位置创建路由文件(如果父文件的路由位于 ParentBundle/Resources/config/routing.yml,并且您在 ChildBundle/Resources/ 创建路由文件config/routing.yml),它将覆盖父级的routing.yml,而symfony将只使用子级的routing.yml。

我没试过,但是如果你在子bundle的routing.yml中导入父bundle的routing.yml,就可以解决你的问题。由于 Symfony 路由器总是会选择它找到的第一个匹配的路由,因此您可以通过在导入代码之上编写相关的路由代码来覆盖您想要的特定路由。

【讨论】:

您似乎无法导入孩子的routing.yml,因为它会创建循环引用。

以上是关于Symfony2 包继承丢失父包路由的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 JSON 示例

Symfony2 路由:不允许的方法(允许:Method)

Symfony2 翻译 URL 和路由

如何使用 Symfony2 路由组件将路由与控制器绑定

Symfony2 资产路由和资源错误

symfony2 获取路由参数(控制器参数与请求)