Концептуальная проблема 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.

Другие вопросы по тегам