Официальный гайд по лучшим практикам в Symfony

  • Tutorial
Fabien Potencier, ментейнер Symfony несколько дней назад представил черновую версию гайда лучшх практик, для разработки приложений с использованием Symfony, как фреймворка (напомню, что также это набор независимых компонентов).
Мы знаем, как сложно отучиться от старых привычек и некоторые советы шокируют вас, но следуя им вы сможете разрабатывать приложения быстрее, сделать их менее сложными и в то же время более качественными.
В любом случае стоит помнить, что это всего лишь рекомендации и ваша команда не обязана им следовать. Вы можете продолжать использовать свои подходы, Symfony достаточно гибок для любых нужд и это никогда не изменится.

Под катом я выписал основные тезисы, большинство из них подробно аргументируется внутри книги, в некоторых «шокирующих» местах помимо тезиса есть небольшое объяснение.

  • Всегда используйте Composer для установки Symfony.
  • Создавайте только один бандл для логики приложения. Бандл — независимый компонент, который в дальнейшем можно переиспользовать. Например вашем приложении есть UserBundle и ProductBundle. Скорее всего ProductBundle не будет корректно работать без UserBundle, а это не правильно.
  • Параметры среды(база данных, логи) и приложения опишите в файле app/config/parameters.yml.
  • Параметры среды и приложения по умолчанию опишите в app/config/parameters.yml.dist.
  • Не меняющиеся параметры опишите в константах (прямо в app/config/parameters.yml).
  • Названия ваших сервисов должны быть как можно более коротки и просты, в идеале это должно быть одно слово (например slugger, geocoder).
  • Для определения сервисов приложения используйте YAML.
  • Используя Doctrine ORM, определяйте схему с помощью аннотаций. Все форматы конфигурации имеют одинаковую производительность.
  • Контроллеры приложения должны наследовать Symfony\Bundle\FrameworkBundle\Controller\Controller, использовать аннотации для роутинга и кеширования, когда это возможно.
  • Не используйте аннотацию @Template() для настройки шаблона, используемого контроллером. Аннотация полезна, но работает «магически», поэтому рекомендуется ее не использовать. Также использование этой аннотации замедляет ваше приложение на 21мс.
  • Используйте автоматическую конвертацию параметров, когда это полезно и удобно
    /**
    * @Route("/{id}", name="admin_post_show")
    */
    public function showAction(Post $post)
    

  • Для шаблонизации используйте Twig.
  • Храните ваши шаблоны в директории app/Resources/views/.
  • Для каждой формы создавайте класс.
  • Добавляйте кнопки в шаблоне, а не в PHP коде.
  • Для переводов используйте формат XLIFF.
  • Храните файлы переводов в app/Resources/translations/.
  • Всегда используйте ключевые слова для перевода, вместо текста. Например не Username, а label.username.
  • Если ваше приложение имеет два варианта авторизации, рекомендуется использовать один firewall, с включенным параметром anonymous.
  • Используйте алгоритм bcrypt для хеширования пользовательских паролей.
  • Для автоматической проверки прав доступа по URL используйте access_control. Когда возможно, используйте аннотацию @Security. В более сложных ситуациях используйте сервис security.context.
  • Храните статику(ассеты) в директории web/.
  • Используйте Assetic для обработки статики, или другие подобные инструменты, например GruntJS.
  • При использовании фронтенд-фреймворков, таких как AngularJS, вы должны отделить фронтенд и бекенд на два проекта.
  • Пишите как минимум функциональные тесты для проверки, что страницы приложения успешно загружаются. Хардкодьте URL страницы, вместо использования UrlGenerator.
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 47

    +3
    > Создавайте только один бандл для логики приложения. Бандл — независимый компонент, который в дальнейшем можно переиспользовать. Например вашем приложении есть UserBundle и ProductBundle. Скорее всего ProductBundle не будет корректно работать без UserBundle, а это не правильно.

    Сомнительный совет, в связанных бандлах не вижу ничего плохого, если связь древовидная, а не рекурсивная.
    Теряется весь смысл бандлов: ведь можем захотеть иметь UserBundle и ProductBundle в одном приложении, и UserBundle и ApplicationBundle в другом. И система бандлов как раз поможет в этом.
      0
      Ничего сомнительного — речь идет именно о той части, которая не может быть переиспользована в другом приложении. Разумеется, никто не утверждает, что надо свалить весь код в одну бааааальшую кучу. Речь о том, что не надо делить то, что не будет использоваться в качестве запчастей.
        +2
        Многое зависит от проекта. Я начинал так же с UserBundle, CompanyBundle и еще куча бандлов. Вроде как всё независимо и расширяемо. Но через некоторое время начались непонятки, в какой бандл класть какую логику. В итоге пришел к WebappBundle + ApiBundle -> ApplicationBundle -> DataBundle. Сейчас уже приходит осознание, что надо выпиливать и последние два.
          0
          Согласен, тем более что есть composer, чтобы следить за этими зависимостями.
            0
            Есть отделяемые абстрактные компоненты, вроде OAuthBundle, или UserBundle. А есть приложение, в котором Entity\User зависит от других компонентов, банально у User могут быть посты/проекты/статистика и тд. Думаю имеется ввиду помещать в один бандл код, который без дополнительных плясок с бубном нельзя отсоеденить от проекта.
            А повторяющийся код — да, хорошо бы выделять в отдельные бандлы.
            0
            А часто ли вы использовали повторно бандлы приложения? На практике проще весь код, связанный с симфони поместить в бандл, а остальное вывести выше, т.е. отделить весь бизнес слой, который можно повторно использовать где угодно и в каком угодно фреймворке. И не будет дилемм куда класть и где искать нужную структуру классов.
              –1
              Часто. Мелкие подпроекты (1-6 месяцев), которые могут быть перенесены в отдельные приложения, оформляю в отдельные бандлы.
              Если поместить все эти тонны кода в один бандл, то получится свалка. Поэтому Фабиен тут не прав со своим советом, хоть и создатель этого чудесного фреймворка.
            0
            Добавляйте кнопки в шаблоне, а не в PHP коде.

            Этот совет про то, что не надо писать такой код, или имеется в виду что-то другое?

            $form->add('submit', 'submit', array('label' => 'Сохранить', 'attr'=>array('class'=>'btn btn-primary')));
            

              0
              Да.
              Помимо этого я бы добавил, что даже если вы не используете переводы в проекте — вам стоит начать их использовать для форм. Формы автоматом смотрят есть ли перевод и для однотипных названий вроде submit можно прописать перевод один раз и потом не указывать каждый раз label.
                0
                Сначала они переделали половину компонента Form для поддержки кнопок, а сейчас просят не использовать их))
                Кто как решает эту проблему с лейблами для кнопок Create/Edit? Т.е. в каком месте решается, какой будет label и на основании чего?
                  0
                  используйте разные шаблоны

                  create.html.twig

                  {% extends "::base.html.twig" %}
                  
                  {% block body %}
                        {{ form(form) }}
                        <input type="submit" value="Create">
                  {% endblock %} 
                  


                  edit.html.twig

                  {% extends "::base.html.twig" %}
                  
                  {% block body %}
                        {{ form(form) }}
                        <input type="submit" value="update">
                  {% endblock %} 
                  


                  как то так
                    0
                    Ну я обычно объявляю что-то типа form.html.twig и наследую от него create и edit а кнопки в блок form_buttons но идея в принципе та же.
              0
              Чёрт, ребята, подскажите, аннотации только мне не нравятся?
                0
                А чем вам аннотации не нравятся? У меня есть парочка аргументов против, например сразу не понятно как работает конкретная аннотация, соответсвенно не понятно как она влияет на производительность (привет @Template). Но если внутренности аннотации написаны качественно, подключив плагин в phpstorm с аннотациями работать одно удовольствие.
                  0
                  В основном, мне не нравится идея слияния кода и конфигурации, и как следствие, невозможность найти всю конфигурацию в одном месте.
                    +1
                    На мой взгляд все как раз наоборот. Если вы используете аннотации в роутах, например, вам достаточно удалить экшн и роут пропадет вместе с ним. Не надо никуда лезть и так далее. Ровно как и с модельками, надо добавить поле — пожалуйста.
                    Другие варианты конфигурации раскидывают каждую модельку в отдельный файл, в итоге получается что нужно всегда править два файла.
                    А поиск — возьмите норм ide, с go-to-symbol, опять таки под phpstorm есть отличный плагин для symfony.
                      +1
                      Я не спорю с тем, что многие любят аннотации, вопрос заключался в том, кто их не любит :-)
                  0
                  По-моему аннотации это круто, а если их сделают еще и частью языка так, чтобы они не вырезались как комментарии, то вообще будет шикарно.
                  Но при их использовании надо знать какую-то меру, которая у всех, конечно, разная. Меня, например, несколько удивляет, когда серьезную логику пытаются перенести в аннотации — иногда получается забавно, когда action-ы не содержат ни строчки кода, но зато у каждого по 10 аннотаций :)
                  Сам использую только Route и JMSDiExtra: не люблю лезть каждый раз в конфиги для этих задач. Для повторно используемых частей приложения, разумеется, всё через конфиги
                    0
                    Мне тоже не нравятся. Примерно по тем же причинам
                      0
                      Это по каким?
                      –1
                      Логично, что не нравятся. Они порождают сильную связанность. Это же нарушение IoC принципа, которое даже подсознательно вызывает отторжение, поэтому никаких указаний зависимостей в хорошем коде в сервисах быть не должно.
                        +2
                        Да какой принцип? Вы пишите конечный код, далее он не будет переиспользоваться, абстракция должна когда-то кончаться. Я сам не согласен с некоторыми тезисами, однако общий настрой советов в сторону уменьшения кол-ва абстракций внутри приложения полностью поддерживаю.
                          +1
                          > Да какой принцип?
                          en.wikipedia.org/wiki/Inversion_of_control

                          > Вы пишите конечный код, далее он не будет переиспользоваться
                          Может в этом и разница? Если писать заведомо качественный код, то его можно переиспользовать. И его будут переиспользовать (продолжительная поддержка = переиспользование). И это уже неоднократно случалось с моим кодом.

                          > абстракция должна когда-то кончаться
                          Абстракция абстракцией, но базовые правила ООП (SOLID) надо применять всегда, за исключением специальных осознанных случаев.
                            +1
                            Если писать заведомо качественный код, то его можно переиспользовать

                            Вам часто доводилось переиспользовать код контроллеров? Бизнес логики в них нету, всяких полезностей которые можно реально переиспользовать там так же нету… Так зачем?

                            Аннотации как по мне не особо влияют на соблюдение/несоблюдение принципов SOLID. Ну или приведите пример, ибо я вас не понимаю. Чем скажем использование аннотаций типа Route или Method влияют на соблюдение принципа инверсии зависимостей?
                              0
                              Что касается контроллеров, то их можно использовать как сервисы, и баловаться с ними из контейнера.
                              А в сервисах уже не выйдет использовать аннотации контроллеров.

                              В данном же высказывании я имел ввиду использование аннотаций DI в сервиса с указанием зависимостей уже из самого сервиса. Получается, что мы теряем сам паттерн DI.
                                0
                                Ничего мы не теряем, мы просто конфигурацию переносим из yml поближе к определению класса сервиса. Хотя я не вижу в этом особо смысла и мне кажется это даже менее удобным. Авторесолвинг зависимостей по тайп хинтингу был бы намного более удобной штукой.

                                Что до контроллеров как сервисов, мне к слову интересно по какой причине фабьен не рекомендует такой подход…
                      0
                      Также использование этой аннотации замедляет ваше приложение на 21мс.

                      Видимо в контексте надо почитать, ибо не понятно откуда такие цифры берутся… Вообще аннотации все эти клевые штуки, но это больше для RAD.
                        0
                        Не хотел сильно статью захламлять. Контекст такой — взяли простейшее приложение (BlogApp) и замерили, $twig->render() быстрее @Template на 21 мс
                          0
                          Это и странно:
                          заглянул в TemplateListener — не увидел ничего страшного: угадывание путей шаблона и вызов render();
                          проверил несколько раз скорость работы с @Template и без — абсолютно равны;
                          выключил целиком TemplateListener (sensio_framework_extra.view.annotations: false) — тоже ничего не изменилось;

                          Конечно, какой-то оверхед присутствует (то же угадывание путей шаблонов), но в целом описанная в документе разница (5 мс и 26 мс) недостижима.
                          0
                          Как раз RAD — это отсутсвие аннотаций и использование принципа convention over configuration.
                          А аннотации — это конфигурация.
                            0
                            Строго говоря, да, но согласитесь, эта аннотация умеет сама определять какой шаблон вы хотите отрендерить на основе того какой экшен контроллера выполняется. То есть грубо говоря используя эту аннотацию без каких либо параметров мы просто говорим фреймворку «мне лень, сделай это за меня».
                          0
                          Не используйте аннотацию @Template()
                          А альтернатива какая? Писать каждый раз имя шаблона утомительно.

                          PS: «Контроллеры приложения должны наследовать Symfony\Bundle\FrameworkBundle\Controller\Controller» это точно Fabian там?
                            0
                            А что не так? Если его позиция за последнее время не изменилась, то он настаивает на несервисных контроллерах
                              0
                              Ну его позицию не знаю, но это же не запись с его блога, а документ на сайте симфони с громким названием. Хотелось бы, чтобы все пункты были объективны, а не аргументации в виде «no benefits when using controllers as services» и premature optimization.
                            0
                            > Храните ваши шаблоны в директории app/Resources/views/.
                            Немного не понял. Это призыв не хранить шаблоны внутри бандла, а выносить их отдельно?
                              0
                              В целом вообще призыв, как я понял — исключить Resources из AppBundle. Я сходу не понял, предрагается также вынести все DI в app/config/services.yml.
                                0
                                Довольно жуткий совет, как мне кажется.
                                  0
                                  Почему?
                                    +1
                                    Раз уж бандл — независимая еденица, то не стоит отделять от него шаблоны. Хотя бы поэтому.
                                      0
                                      В оригинальном документе называются два преимущества:
                                      For starters, this drastically simplifies their logical names

                                      для начинающих: сильно упрощает наименование файлов (default/index.html.twig вместо AcmeDemoBunde:Default:index.html.twig)

                                      Another advantage is that centralizing your templates simplifies the work of your designers. They don't
                                      need to look for templates in lots of directories scattered through lots of bundles.

                                      упрощает поиск шаблонов для дизайнеров.

                                      Как по мне — так оба довода сомнительны.
                                +1
                                Тоже обратил внимание, очень странный совет. Но Фабиен говорит, что просто не надо использовать бандлы :)

                                А если хранить ресурсы в бандлах, то сразу появляются другие проблемы, следтсвием отсутсвия решения которых появляется еще один странный совет:
                                > При использовании фронтенд-фреймворков, таких как AngularJS, вы должны отделить фронтенд и бекенд на два проекта.

                                Причина — невозможность разработки фронтенда с использованием ассетика (с использованием бандлов его придется юзать и в dev). Приходится заменять ассетик, либо разделять на два проекта.
                                Но не может же Фабиен написать «не используйте ассетик, мы не научили его нормально работать с JS», вот и появляются такие необычные советы.
                                  0
                                  А есть вообще удачные билд-системы для фронтенда не на nodejs? Просто если нужно что-то сложное — сразу появляются костыли, которых как раз и стоит избегать разделением проекта.
                                    0
                                    На фронтенде желательно не иметь билд-систем (и бандлов): тогда можно вносить изменения код в браузер прямо из браузера.
                                    Понятно, почему теперь Фабиен советует от них отказаться.
                                    А так можно написать набор правил для Grunt, который все перенесет и соберет по необходимым требованиям.
                                      0
                                      А что плохого в node.js? Я вот вообще выкинул assetic и phing и заменил на gulp. node.js при таком подходе нужно только на билд сервере ставить а в билд попадают только уже подготовленные файлики.
                                      0
                                      Да, я тоже «заметил» этот совет про два проекта. Хотя не особо представляю как это.
                                      И тем не менее, я согласен, что разрабатывать одновременно на Angular и Symfony довольно проблематично, если хочется использовать какие-либо системы сборки и прочие плюшки.
                                    0
                                    Что-то не открывается сейчас их pdf
                                    An unexpected error occurred (error code: 500).

                                    Если кто скачал себе, можете перезалить куда-нибудь?

                                  Only users with full accounts can post comments. Log in, please.