Концептуальная проблема Symfony2: общие пакеты против конкретных
Изменить: лучшие практики Symfony отвечают на большинство моих вопросов.
У меня есть несколько вопросов, касающихся моего приложения Symfony2.
Он будет иметь внешний и внутренний интерфейсы, и они будут использовать некоторый общий код (например, средство отображения даты, paginator, некоторые часто используемые шаблоны и т. Д.).
Итак, я создал один FrontendBundle и один BackendBundle, каждый из которых содержит, например, соответствующий макет. Первый вопрос: это хорошая практика для создания пакетов для внешнего интерфейса и бэкэнда, которые являются "общими" пакетами, у которых даже не будет контроллера?
Второй вопрос: я прочитал в кулинарной книге, что я должен размещать макеты не в пакетах, а в каталоге app/Resources/views/. У меня уже есть файл base.html.twig, и мне интересно, должен ли я также размещать там свои макеты, например, файл frontend_layout.html.twig?
Я создал пакет с именем RootBundle, который будет содержать все, что нужно моему приложению в интерфейсе и бэкэнде. Это хорошая практика или нет? Или я должен создать специальный пакет для каждой предложенной функциональности, такой как PaginatorBundle, DateDisplayerBundle и т. Д.? Звучит странно, что у меня есть один "разный" комплект, содержащий все, что я не знаю, куда положить. Как ты это делаешь?
2 ответа
Новый подход
Спустя несколько месяцев после того, как я написал этот ответ, мой подход изменился, поэтому я делюсь им с сообществом. Этот ответ по-прежнему довольно популярен и может привести новичков к подходу, который я не считаю более подходящим. Так...
Теперь у меня есть только один пакет для конкретного приложения, и я называю его AppBundle
, Было несколько проблем со старым подходом, и вот некоторые из них:
Создание большого количества связок утомительно. Вы должны создать класс пакета и набор стандартных папок для каждого нового пакета, а затем активировать его и зарегистрировать его маршруты и DI и еще много чего.
Ненужный хардкорный процесс принятия решений. Иногда вы просто не можете решить, к какому пакету принадлежит конкретная вещь, потому что она используется более чем одним пакетом. И после того, как вы потратите полдня и, наконец, примете трудное решение о том, где его разместить, вы обнаружите, что через пару дней или недель вы не сможете сразу сказать, в каком комплекте искать эту вещь - потому что в большинстве случаев решение не было основано на чистой логике, и вы должны были выбирать, основываясь на подбрасывании монеты или любых других средствах, которые вы используете, чтобы принести помощь высшим силам.
Я предложил использовать
CommonBundle
для обычных вещей в прошлом, но для этого вам придется сделать много ненужных рефакторингов, перемещая вещи в и изCommonBundle
в зависимости от того, сколько или несколько пакетов будут использовать эту вещь позже.Пакеты для приложений в любом случае взаимозависимы. Когда люди впервые сталкиваются с идеей связок, одна из главных мыслей, которая приходит им в голову, - это что-то вроде "Yay! У меня будет куча многоразовых пачек! "Эта идея великолепна, и я ничего не имею против; проблема в том, что специфичные для приложения пакеты в любом случае не так многоразовы - они взаимозависимы. Забудьте о повторном использовании в этом случае.
Не знаю, где поставить Behat функции и определения шагов. Эта проблема связана с предыдущими: вы должны повторять одни и те же безмозглые движения для каждого пакета, а затем принимать жесткие решения.
Когда я начал писать функции Behat, я просто не мог решить, куда поместить множество функций и определений шагов, потому что они принадлежали нескольким пакетам одновременно. Положить их в
CommonBundle
казалось, еще хуже, потому что это последний пакет, в котором я искал все это. Итак, я закончил тем, что создалFeatureBundle
для этого.
Переход на один пакет решил все эти проблемы.
Я также видел, как у некоторых людей был отдельный пакет, скажем, для всех сущностей. Мне также не нравится этот подход, и я на самом деле предлагаю не включать в пакеты сущности и другие не относящиеся к Symfony2 вещи.
Еще раз обратите внимание, что этот новый подход применяется к конкретным пакетам приложений. Официальные документы и другие места полны полезных советов о том, как структурировать пакеты, предназначенные для совместного использования с другими и повторного использования в многочисленных проектах. Я также пишу связки этого типа. Но что я узнал после нескольких месяцев работы над проектами 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 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.html
а также CommonBundle/Resources/views/Admin/layout.html
простираться app/Resources/views/base.html.twig
, Шаблоны других пакетов расширяют один из этих двух макетов, в зависимости от того, предназначены ли они для внешнего интерфейса или внутреннего интерфейса. По сути, именно так я использую подход трехуровневого наследования.
Итак, я бы поставил ваш дисплей даты в CommonBundle
, В зависимости от сложности это может быть просто шаблон, макрос или расширение Twig.
Нумерация страниц является распространенной проблемой, поэтому я предлагаю вам использовать один из существующих комплектов вместо того, чтобы заново изобретать колесо - если они, конечно, соответствуют вашим потребностям.
И да, вполне нормально иметь связки без контроллеров или представлений и т. Д.
Я предлагаю создать DateDisplayerBundle и PaginatorBundle вместо того, чтобы помещать их связанный код в более общий пакет. Есть несколько причин для этого:
- Роль каждого пакета очень ясна, и вы знаете, где находится ваш код.
- Совместное использование частей функциональности (средство отображения даты, разбивка на страницы) между различными проектами проще, если у вас есть отдельные пакеты, а не один общий пакет, который вам, возможно, понадобится затем удалить.
Нет строгого правила, утверждающего, что связки должны иметь контроллеры. Пакеты могут иметь любое сочетание бизнес-логики, шаблонов, контроллеров и конфигурации, но нет никаких ограничений на то, что вы можете хранить в них.
С другой стороны, если ваша функциональность не очень сложна, она может вообще не содержать содержимого в комплекте. В этом случае вы можете создать библиотеку в /vendor
для этого. Таким образом Symfony использует несколько библиотек (см. Monolog и Doctrine.)
Что касается вашего второго вопроса, я думаю, что причина для сохранения макетов в app\Resources\views
потому что это удобный способ отслеживать все ваши макеты. Когда у вас есть проект, который имеет много пакетов, вы можете потерять отслеживание того, где находится определенный макет. Но если вы храните их все в одном централизованном месте, вы всегда будете точно знать, где искать. Как и во многих вещах в Symfony2, это не правило, которое заложено в камень. Вы можете легко хранить свои макеты в пачке, но я не думаю, что это рекомендуемая практика.
Что касается вашего вопроса о вашем основном Root-пакете, я бы сказал, что в большинстве случаев вам следует избегать использования множества различных функций в одном пакете. Смотрите мои предыдущие пункты о том, как сохранить ваши связки конкретными. When I started developing with Symfony2, I had some trouble determining what code should go in what bundle. It's not how I was used to thinking about programming. But eventually you start to see how the individual pieces of the puzzle fit, and that makes determining the bundle structure easier.