如何覆盖 Bundle 的任何部分
当使用第三方 bundle 时,你可能想要自定义或覆盖它的某些功能。本文档描述了覆盖 bundle 最常用功能的方法。
模板
第三方 bundle 模板可以在 <your-project>/templates/bundles/<bundle-name>/
目录中被覆盖。新的模板必须使用与原始模板相同的名称和路径(相对于 <bundle>/templates/
)。
例如,要覆盖来自 AcmeUserBundle 的 templates/registration/confirmed.html.twig
模板,请创建此模板:<your-project>/templates/bundles/AcmeUserBundle/registration/confirmed.html.twig
警告
如果你在一个新的位置添加了一个模板,你*可能*需要清除你的缓存 (php bin/console cache:clear
),即使你处于 debug 模式。
除了覆盖整个模板,你可能只想覆盖一个或多个块。然而,由于你正在覆盖你想要扩展的模板,你最终会陷入无限循环错误。解决方案是在模板名称中使用特殊的 !
前缀,以告诉 Symfony 你想要从原始模板扩展,而不是从被覆盖的模板扩展。
1 2 3 4 5 6 7
{# templates/bundles/AcmeUserBundle/registration/confirmed.html.twig #}
{# the special '!' prefix avoids errors when extending from an overridden template #}
{% extends "@!AcmeUser/registration/confirmed.html.twig" %}
{% block some_block %}
...
{% endblock %}
提示
Symfony 内部也使用了一些 bundle,所以你可以应用相同的技术来覆盖核心 Symfony 模板。例如,你可以通过覆盖 TwigBundle 模板来自定义错误页面。
路由
路由永远不会在 Symfony 中自动导入。如果你想包含来自任何 bundle 的路由,那么它们必须从你的应用程序中的某个位置手动导入(例如 config/routes.yaml
)。
“覆盖” bundle 路由的最简单方法是完全不导入它。与其导入第三方 bundle 的路由,不如将该路由文件复制到你的应用程序中,修改它,然后导入它。
控制器
如果控制器是一个服务,请参阅下一节关于如何覆盖它。否则,定义一个新的路由 + 控制器,其路径与你想要覆盖的控制器关联(并确保新的路由在 bundle 路由之前加载)。
实体 & 实体映射
只有当 bundle 提供映射的父类(例如 FOSUserBundle 中的 User
实体)时,覆盖实体映射才有可能。可以通过这种方式覆盖属性和关联。在Doctrine 文档中了解更多关于此功能及其限制的信息。
验证元数据
Symfony 从每个 bundle 加载所有验证配置文件,并将它们组合成一个验证元数据树。这意味着你可以向属性添加新的约束,但你不能覆盖它们。
为了克服这个问题,第三方 bundle 需要为验证组进行配置。例如,FOSUserBundle 就有这个配置。要创建你自己的验证,请将约束添加到新的验证组
1 2 3 4 5 6 7 8 9 10
# config/validator/validation.yaml
FOS\UserBundle\Model\User:
properties:
plainPassword:
- NotBlank:
groups: [AcmeValidation]
- Length:
min: 6
minMessage: fos_user.password.short
groups: [AcmeValidation]
现在,更新 FOSUserBundle 配置,使其使用你的验证组而不是原始的验证组。
翻译
翻译与 bundle 无关,而是与翻译域有关。因此,你可以从主 translations/
目录覆盖任何 bundle 翻译文件,只要新文件使用相同的域。
例如,要覆盖在 AcmeUserBundle 的 translations/AcmeUserBundle.es.yaml
文件中定义的翻译,请创建一个 <your-project>/translations/AcmeUserBundle.es.yaml
文件。