Лучшие практики для повторно используемых пакетов

Лучшие практики для повторно используемых пакетов

Существует два типа пакетов:

  • Пакеты, специфичные для приложения: используются только для построения вашего приложения;
  • Повторно используемые пакеты: созданы для общего использования во многих проектах.

Эта статья полностью раскрывает то, как структурировать ваши повторно используемые пакеты так, чтобы их было легко конфигурировать и расширять. Многие из этих рекомендаций не относятся к пакетам приложений, так как вам нужно, чтобы они были максимально простыми. Для пакетов приложения, просто следуйте практикам, показанным в разных справочниках.

Лучшие практики для пакетов, специфичных для приложения, обсуждаются в The Symfony Framework Best Practices.

Имя пакета

Пакет также является PHP пространством имён. Пространство имени должно следовать стандартам совместимости PSR-0 или PSR-4 для PHP пространств имён и имён классов: оно должно начинаться с сегмента поставщика, затем идет ноль или другие сегменты категорий, и заканчивается оно коротким именем пространства имён, которое должно заканчиваться суффиксом Bundle.

Пространство имён становится пакетом, как только вы добавляете к нему класс пакета. Имя класса пакета долдно следовать этим простым правилам:

  • Использовать только алфавитно-цифровые символы и нижние подчёркивания;
  • Использовать CamelCased имя;
  • Использовать описательное и короткое имя (не более двух слов);
  • Вначале имени присоединять конкатенацию поставщика (и по желанию пространства имён категории);
  • Присоединять к имени суффикс Bundle.

Вот несколько валидных пространств имён пакетов и имён классов:

Пространство имён Имя класса пакета
Acme\Bundle\BlogBundle AcmeBlogBundle
Acme\BlogBundle AcmeBlogBundle

По соглашению, метод getName() класса пакета должен возвращать имя класса.

Note

Если вы публично делитесь вашим пакетом, то вы должны использовать имя класса пакета в качестве имени хранилища (например, AcmeBlogBundle, а не BlogBundle).

Note

Базовые пакеты Symfony не добавляют вначале класса пакета Symfony и всегда добавляют под-пространства имён Bundle; например: FrameworkBundle.

Каждый пакет имеет дополрительное имя, которое является короткой версией пространства имён пакета в нижнем регистре с использованием нижних подчёркиваний (acme_blog для AcmeBlogBundle). Это дополнительное имя используется для усиления уникальности в проекте и для определения опций конфигурации пакета (см. ниже некоторые примеры использования).

Структура каталога

Базовая структура каталога AcmeBlogBundle должна выглядеть так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<your-bundle>/
├─ AcmeBlogBundle.php
├─ Controller/
├─ README.md
├─ LICENSE
├─ Resources/
│   ├─ config/
│   ├─ doc/
│   │  └─ index.rst
│   ├─ translations/
│   ├─ views/
│   └─ public/
└─ Tests/

Следующие файлы обязательны так как они гарантируют соглашение структуры, на которую могут положиться автоматизированные инструменты:

  • AcmeBlogBundle.php: Это класс, трансформирующий простой каталог в пакет Symfony (измените его на имя вашего пакета);
  • README.md: Этот файл содержит базовое описание пакета и обычно показывает базовые примеры и ссылки на полную документацию (может использовать любые форматы разметки, поддерживаемые GitHub, например, README.rst);
  • LICENSE: Полное содержимое лицензии, используемой кодом. Большинство сторонних пакетов публикуются под лицензией MIT, но вы можете выбрать любую лицензию;
  • Resources/doc/index.rst: The root file for the Bundle documentation.

Глубина под-каталогов должна быть минимальной для большинства используемых классов и файлов (максимум два уровня).

Каталог пакета только для чтения. Если вам нужно написать временные файлы, храните их в каталоге cache/ или log/ хоста приложения. Инструменты могут генерировать файлы в структуре каталога пакета, но только, если сгенерированные файлы будут частью хранилища.

Следующие классы и файлы имеют специфические месторасположения (некоторые обязательны, а другие являются просто соглашениями, которым следует большинство разработчиков):

Тип Каталог Обязательно?
Команды Command/ Да
Контроллеры Controller/ Нет
Расширения сервис-контейнера DependencyInjection/ Да
Слушатели событий EventListener/ Нет
Модельные классы [1] Model/ Нет
Конфигурация Resources/config/ Нет
Веб-ресурсы (CSS, JS, изображения) Resources/public/ Да
Файлы переводов Resources/translations/ Да
Шаблоны Resources/views/ Да
Модульные и функциональные тесты Tests/ Нет

[1] См. How to Provide Model Classes for several Doctrine Implementations, чтоб узнать, как обработать маршрутизацию с пропуском компилятора.

Классы

Структура каталога пакета используется в качестве иерархии пространства имён. Например, контроллер ContentController хранится в Acme/BlogBundle/Controller/ContentController.php, а полное имя класса - Acme\BlogBundle\Controller\ContentController.

Все классы и файлы должны следовать стандартам разработки кода Symfony.

Некторые классы должны рассматриваться как фасады и должны быть максимально короткими, например, Команды, Помощники, Слушатели и Контроллеры.

Классы, которые связываются с диспетчером событий, должны иметь суфикс Listener.

Классы исключений должны храниться в под-пространстве имён Exception.

Поставщики

Пакет не должен включать в себя сторонние PHP-библиотеки. Он должен полагаться на стандартную автозагрузку Symfony вместо этого.

Пакет не должен включать в себя сторонние библиотеки, написанные на JavaScript, CSS или любых других языках.

Тесты

Пакет должен поставляться с комплектом тестов, написанных с PHPUnit и хранящихся в каталоге Tests/. Тесты должны следовать следующим принципам:

  • Комплект тестов долежн быть выполняем простой командой phpunit, запущенной из пробного приложения;
  • Функциональные тесты должны быть использованы только для тестирования вывода ответа и некоторой профильной информации, если она у вас есть;
  • Тесты должны охватывать как минимум 95% базового кода.

Note

Комплект тестов не должен содержать скрипты AllTests.php, но должен полагаться на существование файла phpunit.xml.dist.

Документация

Все классы и функции должны поставляться с полным PHPDoc.

Расширенная документация также должна быть предоставлена в формате reStructuredText, в каталоге Resources/doc/; файл Resources/doc/index.rst - это единственный обязательный файл, который должен быть точкой входа документации.

Инструкции по установке

Для того, чтобы облегчить установку сторонних пакетов, рассмотрите использование следующих стандартизированных инструкций в файле README.md.

  • Markdown
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    Установка
    =========
    
    Шаг 1: Скачайте пакет
    ---------------------
    
    Откройте командный пульт, введите каталог вашего проекта и выполните
    следующую команду, чтобы скачать последнюю стабильную версию пакета:
    
    ```console
    $ composer require <package-name> "~1"
    ```
    
    Эта команда требует, чтобы у вас был глобально установлен Composer, как
    объясняется в [главе об установке](https://getcomposer.org/doc/00-intro.md)
    документации Composer.
    
    Шаг 2: Подключите пакет
    -----------------------
    
    Далее, подключите пакет, добавив его к списку зарегистрированных пакетов
    в файле `app/AppKernel.php` вашего проекта:
    
    ```php
    <?php
    // app/AppKernel.php
    
    // ...
    class AppKernel extends Kernel
    {
        public function registerBundles()
        {
            $bundles = array(
                // ...
    
                new <vendor>\<bundle-name>\<bundle-long-name>(),
            );
    
            // ...
        }
    
        // ...
    }
    ```
    
  • reStructuredText
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    Установка
    =========
    
    Шаг 1: Скачайте пакет
    ---------------------
    
    Откройте пульт управление, введите ваш каталог проекта и выполните
    следующую команду для скачивания последней стабильной версии пакета:
    
    .. code-block:: terminal
    
        $ composer require <package-name> "~1"
    
    This command requires you to have Composer installed globally, as explained
    in the `installation chapter`_ of the Composer documentation.
    
    Шаг 2: Подключите пакет
    -----------------------
    
    Далее, подключите пакет, добавив его к списку зарегистрированных пакетов
    в файле ``app/AppKernel.php`` вашего проекта:
    
    .. code-block:: php
    
        <?php
        // app/AppKernel.php
    
        // ...
        class AppKernel extends Kernel
        {
            public function registerBundles()
            {
                $bundles = array(
                    // ...
    
                    new <vendor>\<bundle-name>\<bundle-long-name>(),
                );
    
                // ...
            }
    
            // ...
        }
    
    .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
    

Пример выше предполагает, что вы устанаваливаете последнюю стабильную версию пакета, где вы не должны предоставлять номер версии пакета (например, composer require friendsofsymfony/user-bundle). Если инструкции по установке ссылаются на устаревшую или нестабильную версию пакета, включите ограничение версий (например, composer require friendsofsymfony/user-bundle "~2.0@dev").

По желанию вы можете добавить больше шагов установки (Шаг 3, Шаг 4, и т.д.), чтобы объяснить другие необходимые для установки задания, как, например, регистрация маршрутов или сборс ресурсов.

Маршрутизация

Если пакет предоставляет маршруты, они должны иметь префикс в виде дополнительного имени пакета. Например, если ваш пакет называется AcmeBlogBundle, все его маршруты должны иметь префикс acme_blog_.

Шаблоны

Если пакет предоставляет шаблоны, то они должны использовать Twig. Пакет не должен предоставлять главный макет, кроме случаев, когда он предоставляет полностью рабочее приложение.

Файлы переводов

Если пакет предоставляет переводы сообщений, они должны быть определены в формате XLIFF; домен должен быть назван по имени пакета (acme_blog).

Пакет не должен переопределять существующие сообщения из другого пакета.

Конфигурация

Чтобы предоставить большую гибкость, пакет может предоставить конфигурируемые настройки, используя встроенные механизмы Symfony.

Для простый настроек конфигурации, полагайтесь на запись parameters, по умолчанию находящуюся в конфигурации Symfony. Параметры Symfony - это простые пары ключ/значение; значение может быть любым валидным PHP-значением. Каждое имя параметра должно начинаться с дополнительного имени пакета, хотя это всего-лишь предложение лучших практик. Остаток имени параметра будет использовать точку (.) для разделения разных частей (например, acme_blog.author.email).

Конечный пользователь может предоставлять значения в любом файле конфигурации:

  • YAML
    1
    2
    3
    # app/config/config.yml
    parameters:
        acme_blog.author.email: '[email protected]'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <parameters>
            <parameter key="acme_blog.author.email">[email protected]</parameter>
        </parameters>
    
    </container>
    
  • PHP
    1
    2
    // app/config/config.php
    $container->setParameter('acme_blog.author.email', '[email protected]');
    

Извлеките параметры конфигурации в вашем коде из контейнера:

1
$container->getParameter('acme_blog.author.email');

Даже если этот механизм достаточно прост, вам стоит рассмотреть использование более продвиутой семантической конфигурации пакета.

Контроль версий

Пакеты должны быть версионированы, следуя Стандартам семантического версионирования.

Сервисы

Если пакет определяет сервисы, то они должны иметь префикс в виде дополнительного имени пакета. Например, сервисы AcmeBlogBundle должны иметь префикс acme_blog.

В дополнение, сервисы, которые не должны быть ипользованы приложениями напрямую, должны быть определены, как приватные. Для публичных сервисов должны быть созданы дополнительные имена из интерфейса / класса в id сервиса. Например, в MonologBundle, дополнительное имя создаётся из Psr\Log\LoggerInterface в logger, чтобы типизирование LoggerInterface можно было использовать для автомонтирования.

Сервисы не должны использовать автомонтирование или автоконфигурацию. Вместо этого, все сервисы должны быть ясно определены.

Вы можете узнать намного больше о загрузке сервисов в пакете, прочитав эту статью: Как загружать конфигурацию сервиса внутри пакета.

Метаданные Composer

Файл composer.json должен включать в себя как минимум следующие метаданные:

name
Состоит из поставщика и короткого имени пакета. Если вы реализуете пакет лично, а не от имени компании, используйте ваше имя (например, johnsmith/blog-bundle). Короткое имя пакета исключает имя поставщика и отделяет каждое слово дефисом. Например: AcmeBlogBundle трансформируется в blog-bundle, а AcmeSocialConnectBundle - в social-connect-bundle.
description
Краткое разъяснение цели пакета.
type
Использует значение symfony-bundle.
license
MIT - предпочитаемая лицензия для пакетов Symfony, но вы можете использовать любую другую.
autoload
Эта информация используется Symfony для загрузки классов пакета. Стандарт автозагрузки PSR-4 рекомендуется для современных пакетов, но стандарт PSR-0 также поддерживается.

Для того, чтобы облегчить разработчикам поиск вашего пакета, зарегистрируйте его в Packagist, официальном хранилище пакетов для Composer.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.