编辑:Symfony best practices回答了我的大部分问题。
我有几个关于我的Symfony2应用程序的问题。
它将有一个前端和后端,它们将使用一些常用代码(例如日期显示器,分页器,常用的一些模板等)。
所以,我创建了一个FrontendBundle和一个BackendBundle,每个都包含例如它们各自的布局。第一个问题:为前端和后端创建捆绑包是不是很好的做法,这些捆绑包是甚至没有控制器的“通用”捆绑包?
第二个问题:我在食谱上读到我不应该将我的布局放在捆绑包中,而是放在app / Resources / views /目录中。我已经有了一个base.html.twig文件,我想知道是否应该将我的布局放在那里,比如frontend_layout.html.twig文件?
我创建了一个名为RootBundle的包,它将包含我的应用程序在前端和后端需要的所有内容。这是一个好的做法吗?或者我应该为每个提议的功能创建一个专用的捆绑包,例如PaginatorBundle,DateDisplayerBundle等等?听起来很奇怪,我有一个“杂项”捆绑包含我不知道放在哪里的所有内容。你是怎么做到的?
答案 0 :(得分:79)
自从我写这个答案几个月后,我的方法发生了变化,所以我正在与社区分享。这个答案仍然非常受欢迎,并且可以引导新手采用我认为不再是最好的方法。所以......
现在我只有一个 应用专用捆绑包,我将其称为AppBundle
。旧方法存在一些问题,其中一些是:
创建大量捆绑包很繁琐。您必须为每个新捆绑包创建捆绑类和一堆标准文件夹,然后激活它并注册其路由和DI等等
不必要的核心决策制定过程。有时您无法决定特定事物属于哪个捆绑包,因为它被多个捆绑包使用。在你花了半天时间并最终决定放置它的位置之后,你会发现在几天或几周内你将无法立即告诉哪个捆绑包看起来那个东西 - 因为大多数时候决定不是基于纯粹的逻辑,而你必须根据投掷硬币或用来提供更高权力的任何手段来选择。
我建议过去使用CommonBundle
来处理常见内容但是这样做你必须做很多不必要的重构,根据有多少或几个捆绑来移动CommonBundle
的内容以后再使用那件事。
应用程序特定的捆绑包无论如何都是相互依赖的。当人们第一次遇到捆绑包的想法时,他们心中想到的一个主要想法是“耶!我会给我一堆可重复使用的捆绑包!“这个想法太棒了,我没有反对它;问题是 app特定的捆绑包不是那么可重复使用 - 它们是相互依赖的。忘记此案例中的重用。
不知道在哪里放置Behat功能和步骤定义。此问题与之前的问题有关:您必须为每个捆绑重复相同的无脑动作,然后做出硬核决定。
当我开始编写Behat功能时,我无法决定在哪里放置大量功能和步骤定义,因为它们一次属于多个捆绑包。将它们放入CommonBundle
似乎更糟糕,因为这是我想要查找的最后一个包。所以,我最终为此创建了FeatureBundle
。
切换到单个捆绑包解决了所有这些问题。
我也看到有些人为所有实体分别拥有一个捆绑包。我既不喜欢这种方法,也不喜欢suggest keeping entities and other non Symfony2 specific stuff out of the bundles。
再次注意,这种新方法适用于 app特定的捆绑包。官方文档和其他地方对于如何构建旨在与他人共享并在众多项目中重用的捆绑包充满了很好的建议。 I write bundles of this type也是如此。但是我在Symfony2项目工作几个月后发现的是,用于重用的捆绑包与特定应用程序捆绑包之间存在差异 - 一种方法并不适合所有。
当然,当您看到特定应用程序包中出现可重用的内容时,只需将其解压缩,将其放在单独的仓库中并作为供应商安装。
此外,我发现自己更积极地使用子名称空间作为一种逻辑分区的方法 - 而不是为此创建一堆捆绑并经历所有这些麻烦。
没有严格的规则或银子弹,但我会分享我做事的方法 - 也许它会给你一两个洞察力。
首先,我没有两个包罗万象的捆绑包,例如FrontendBundle
和BackendBundle
。相反,我的捆绑包有前端和后端控制器,视图等。所以,如果我从UserBundle
除去控制器和视图之外的所有内容,它的结构将如下所示:
UserBundle
├── Controller
│ ├── Admin
│ │ └── UserController.php
│ └── UserController.php
├── Resources
│ └── views
│ ├── Admin
│ │ └── User
│ │ ├── add.html.twig
│ │ ├── delete.html.twig
│ │ ├── edit.html.twig
│ │ ├── form.html.twig
│ │ └── index.html.twig
│ └── User
│ ├── edit.html.twig
│ ├── sign-in.html.twig
│ ├── sign-up.html.twig
│ └── view.html.twig
└── UserBundle.php
其次,我有CommonBundle
,我用它来分享几个包的内容:
CommonBundle
├── Resources
│ ├── public
│ │ ├── css
│ │ │ ├── admin.css
│ │ │ ├── common.css
│ │ │ └── public.css
│ │ └── img
│ │ ├── add.png
│ │ ├── delete.png
│ │ ├── edit.png
│ │ ├── error.png
│ │ ├── return.png
│ │ ├── success.png
│ │ └── upload.png
│ └── views
│ ├── Admin
│ │ └── layout.html.twig
│ └── layout.html.twig
└── CommonBundle.php
我的app/Resources/views/base.html.twig
与Symfony标准发行版几乎相同:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ block('title') | striptags | raw }}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
CommonBundle/Resources/views/layout.html
和CommonBundle/Resources/views/Admin/layout.html
都延伸app/Resources/views/base.html.twig
。其他bundle的模板扩展了这两种布局中的一种,具体取决于它们是用于前端还是后端。基本上,这就是我使用Three-level Inheritance approach的方式。
所以,我会把你的日期显示器放到CommonBundle
。根据其复杂程度,它可能只是一个模板,macro或Twig extension。
分页是一个常见的问题,所以我建议您使用existing bundles中的一个,而不是重新发明轮子 - 当然,如果它们满足您的需求。
是的,拥有没有控制器或视图等的捆绑包是完全可以的。
答案 1 :(得分:4)
我建议创建一个DateDisplayerBundle和一个PaginatorBundle,而不是将它们的相关代码放在一个更通用的包中。这有几个原因:
没有硬规则说捆绑包必须有控制器。捆绑包可以包含业务逻辑,模板,控制器和配置的任意组合,但是您可以在其中存储的内容没有限制。
另一方面,如果您的功能不是很复杂,则可能无法保证完全包含在捆绑包中。在这种情况下,您可以在/vendor
中为它创建一个库。 Symfony以这种方式使用了许多库(例如,参见Monolog和Doctrine。)
至于你的第二个问题,我认为保持app\Resources\views
布局的原因是因为它是一种方便的方式来跟踪你的所有布局。当您的项目包含许多包时,您可能会忘记某个布局的位置。但如果你把它们全部放在一个集中的位置,你就会知道确切的位置。与Symfony2中的许多内容一样,这不是一个固定的规则。您可以轻松地将布局存储在一个包中,但我认为这不是推荐的做法。
至于你关于你的一般Root捆绑的问题,我想说在大多数情况下你应该避免在一个捆绑中破坏一堆不同的功能。请参阅我之前关于保持您的捆绑特定的要点。当我开始使用Symfony2进行开发时,我在确定哪些代码应该放在哪个包中时遇到了一些麻烦。这不是我习惯于编程的方式。但最终你会开始看到拼图的各个部分是如何合适的,这使得确定捆绑结构更容易。