Symfony2的概念问题:一般捆绑与特定的问题

编辑: Symfony最佳实践回答了我的大部分问题。

我有几个关于我的Symfony2应用程序的问题。

它将有一个前端和一个后端,他们将使用一些常见的代码(如date显示器,分页器,一些常用的模板等)。

所以,我创build了一个FrontendBundle和一个BackendBundle,每个包含各自的布局。 第一个问题:为前端和后端创build捆绑包是一种很好的做法,即“通用”捆绑包,甚至没有控制器?

第二个问题:我在一本食谱上读过,我不应该把我的布局放入捆绑包中,而是放在app / Resources / views /目录中。 我已经有一个base.html.twig文件,我不知道是否应该把我的布局也在那里,就像一个frontend_layout.html.twig文件?

我创build了一个名为RootBundle的包,它将包含我的应用程序在前端和后端中所需的所有内容。 这是一个很好的做法吗? 或者我应该为build议的每个function创build一个专用的包,如PaginatorBundle,DateDisplayerBundle等? 这听起来很奇怪,我有一个“杂项”包含一切,我不知道在哪里放。 你如何做到这一点?

新的方法

我写了这个答案几个月后,我的方法已经改变了,所以我要和社区分享。 这个答案仍然非常受欢迎,可以引导新手进入我不认为是最好的方法了。 所以…

现在我只有一个 特定的应用程序包,我把它AppBundle 。 旧的方法有几个问题,这里有一些问题:

  • 创build很多捆绑包是很乏味的。 您必须为每个新捆绑创build捆绑类和一堆标准文件夹,然后将其激活并注册其路由和DI以及其他类别。

  • 不必要的硬核决策过程。 有时你不能决定一个特定的东西属于哪个包,因为它被多个包所使用。 在你花了半天的时间,终于决定把它放在哪里之后,你会发现在几天或几星期内,你将无法立即知道哪个包是在看什么东西 – 因为大部分时间的决定都不是build立在纯粹的逻辑基础之上的,而且你必须根据硬币的折腾或者用什么方式来select,才能获得更大的帮助。

    我build议在过去使用CommonBundle作为常见的东西,但是这样做的话,你将不得不做很多不必要的重构,根据有多less个或几个bundle将来会使用这个东西,从CommonBundle移出一个东西。

  • 无论如何,应用程序特定的包是相互依赖的。 当人们第一次遇到捆绑的想法时,其中一个主要想法就是“耶! 我会给我一堆可重复使用的捆绑包!“这个想法很好,我没有什么反对的。 问题是, 应用程序特定的包无论如何不是可重用的 – 这是相互依赖的。 在这种情况下忘记重用。

  • 不知道在哪里把Behatfunction和步骤的定义。 这个问题与以前的问题有关:你必须为每个包重复相同的无脑动作,然后做出硬核决定。

    当我开始写Behatfunction时,我不能决定在哪里放置很多function和步骤定义,因为它们一次属于几个包。 把它们放入CommonBundle似乎更糟糕,因为这是最后一捆我会寻找的东西。所以,我最终创build了FeatureBundle

切换到一个单一的捆绑解决了所有这些问题。

我也看到有些人为所有的实体单独包装。 我不喜欢这种方法,并且实际上build议保留实体和其他非Symfony2特定的东西 。

再次请注意,这种新方法适用于特定应用程序的软件包。 官方文档和其他地方对于如何构build打算与其他人分享并在众多项目中重复使用的捆绑包提供了很好的build议。 我也写这种types的包 。 但是我在Symfony2项目上工作了几个月之后发现,在重用的软件包和特定于应用程序的软件包之间是有区别的 – 一种方法并不适合所有人。

当然,当你看到在你的应用程序特定包中出现的可重用的东西时,只需将其解压缩,放在一个单独的回购站中,并作为供应商安装。

另外,我发现自己更加主动地使用子名称空间作为对逻辑分区进行分区的一种方式 – 而不是为此创build一堆捆绑,并且解决所有这些麻烦。

旧的方法

没有硬性规定,也没有silverlight的子弹,但是我会分享我的做事方式 – 也许会给你一两个洞见。

首先,我没有像FrontendBundleBackendBundle这样的两个包罗万象的软件包。 相反,我的bundle有前端和后端控制器,视图等等。所以,如果我从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 Standard发行版几乎相同:

 <!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.htmlCommonBundle/Resources/views/Admin/layout.html扩展app/Resources/views/base.html.twig 。 其他bundle的模板扩展了这两个布局之一,取决于它们是用于前端还是后端。 基本上,这是我如何使用三级inheritance的方法 。

所以,我把你的date显示器放入CommonBundle 。 根据其复杂性,它可能只是一个模板,一个macros或一个树枝 扩展 。

分页是一个常见的问题,所以我build议你使用现有的一个捆绑包,而不是重新发明轮子 – 当然,如果它们满足你的需求的话。

是的,拥有没有控制器或视图的软件包是完全可以的。

我build议创build一个DateDisplayerBundle和一个PaginatorBundle,而不是把他们的相关代码放在一个更通用的包中。 这有几个原因:

  • 每个包的作用是非常明确的,你知道你的代码在哪里。
  • 当你有不同的项目时,共享一些function(date显示器,分页器)更简单,而你可能需要修剪一个通用的bundle。

没有硬性的规则说捆绑必须有控制器。 捆绑包可以包含业务逻辑,模板,控制器和configuration的任何组合,但是对于可以存储在其中的内容没有限制。

另一方面,如果你的function不是很复杂,那么它可能不能保证被包含在一个包中。 在这种情况下,您可以在/vendor为它创build一个库。 Symfony以这种方式使用了大量的库(参见Monolog和Doctrine)。

至于你的第二个问题,我认为在app\Resources\views保留布局的原因是因为这是一个方便你跟踪所有布局的方法。 当你有一个项目有很多捆绑,你可能会失去一个特定布局的地方。 但是如果你把它们都放在一个集中的位置,你总是会知道在哪里看。 和Symfony2中的很多东西一样,这不是一个固定的规则。 您可以轻松地将您的布局存储在一个包中,但我不认为这是推荐的做法。

至于你关于你的一般根捆绑的问题,我想说在大多数情况下,你应该避免在捆绑中捆绑一堆不同的特性。 看到我以前的观点,关于保持你的捆绑特定。 当我开始使用Symfony2进行开发时,在确定哪些代码应该在什么捆绑中遇到困难。 这不是我习惯于编程的想法。 但是最终你会开始看到拼图的各个部分是如何匹配的,这使得确定捆绑结构更容易。