Кращі практики фреймворку Symfony
Дата оновлення перекладу 2024-06-07
Кращі практики фреймворку Symfony
Ця стаття описує кращі практики для розробки веб-додатків з Symfony, які відповідають філософії, що була розроблена творцями Symfony.
Якщо ви не згодні з деякими з цих рекомендацій: вони можуть стати гарною відправною точкою, яку ви потім зможете розширити та підлашутвати під власні потреби. Ви навіть можете повністю їх проігнорувати, та продовжувати використовувати власні кращі практики та методології. Symfony достатньо гнучка, щоб адаптуватися під ваші потреби.
Ця стаття передбачає, що ви вже маєете досвід у розробці додатків Symfony. Якщо це не так, прочитайте спочатку розділ документації Початок роботи.
Tip
Symfony надає пробний застосунок під назвою Symfony Demo, який слідує усім цим кращим практикам, тому ви можете випробувати все наочно.
Створення проекту
Використовуйте бінарність Symfony для створення додатків Symfony
Бінарність Symfony - це здійсненна команда, створена на вашій машині, коли ви Завантажити Symfony. Вона надає безліч утиліт, включно з найпростішим способом для створення нових додатків Symfony:
1
$ symfony new my_project_directory
За лаштунками, ця команда бінарності Symfony виконує необхідну команду Composer, щоб створити новий застосунок Symfony , базуючись на поточній стабільній версії.
Використовуйте структуру каталогів за замовчуванням
Якщо ваш проект не слідує практикам розробки, які потребують певної структури каталогів, слідуйте структурі каталогів Symfony за замовчуванням. Вона пряма, проста та не замикається на Symfony:
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
your_project/
├─ assets/
├─ bin/
│ └─ console
├─ config/
│ ├─ packages/
│ └─ services.yaml
├─ migrations/
├─ public/
│ ├─ build/
│ └─ index.php
├─ src/
│ ├─ Kernel.php
│ ├─ Command/
│ ├─ Controller/
│ ├─ DataFixtures/
│ ├─ Entity/
│ ├─ EventSubscriber/
│ ├─ Form/
│ ├─ Repository/
│ ├─ Security/
│ └─ Twig/
├─ templates/
├─ tests/
├─ translations/
├─ var/
│ ├─ cache/
│ └─ log/
└─ vendor/
Конфігурація
Використовуйте змінні середовища для конфігурації інфраструктури
Значення цих опцій відрізняються від машини до машини (наприклад, від вашої машини розробки до серверу виробництв), але вони не змінюють поведінку додатку.
Використовуйте змінні середовища в вашому проекті , щоб визначити ці
опції та створити множину файлів .env
для конфігурації змінних середовища для кожного з середовищ .
Використовуйте секрети для конфіденційної інформації
Якщо у вашому додатку є конфіденційна конфігурація - на кшталт ключів API - вам варто зберігати її безпечно, використовуючи систему управління секретами Symfony.
Використовуйте параметри для конфігурації додатку
Це опції, що використовуються для зміни поведінки додатку, такої як повідомлень про відправку листів або включення feature toggles. Їх значення не змінюється в залежності від машини, тому не визначайте їх як змінні середовища.
Визначайте ці опції як параметри в файлі
config/services.yaml
. Ви можете перевизначити ці опції для кожного
середовища в файлах config/services_dev.yaml
та config/services_prod.yaml
.
Використовуйте стислість та префікси в назвах параметрів
Розгляньте використання app.
в якості префіксу ваших параметрів ,
щоб уникнути колізій з параметрами Symfony та сторонніх пакетів/бібліотек.
Після цього, використовуйте лише одне чи два слова для опису цілі параметру:
1 2 3 4 5 6 7 8 9 10
# config/services.yaml
parameters:
# не робіть так: 'dir' занадто загальний та не несе ніякого сенсу
app.dir: '...'
# робіть так: стислі, але прості для розуміння назви
app.contents_dir: '...'
# можна використовувати крапки, нижні підкреслення, слеші або нічого, але завжди
# будьте послідовні та використовуйте однаковий формат для всіх параметрів
app.dir.contents: '...'
app.contents-dir: '...'
Використовуйте константи для визначення опцій, що рідкоб змінюються
Опції конфігурації, як кількість об'єктів в деякому списку, рідко змінюються. Замість того, щоб визначати їх як параметри сервіс-контейнера , визначте їх як PHP-константи у пов'язаних класах. Наприклад:
1 2 3 4 5 6 7 8 9
// src/Entity/Post.php
namespace App\Entity;
class Post
{
public const NUMBER_OF_ITEMS = 10;
// ...
}
Головна перевага констант в тому, що ви можете використовувати їх всюди, включно із шаблонами Twig та сутностями Doctrine, в той час як параметри доступні лише з місць з доступом до сервіс-контейнера.
Єдиним вагомим недоліком використання констант для таких значень конфігурації є складне перевизначення їхніх значень у ваших тестах.
Бізнес-логіка
Не створюйте пакетів для організації логіки вашого додаку
Коли було випущено Symfony 2.0, додатки використовували пакети для розділення свого коду на логічні функції: UserBundle, ProductBundle, InvoiceBundle, і т.д. Проте пакет має бути чимось, що можна використовувати знову в якості окремого ПЗ.
Якщо вам потрібно повторно використати якусь функцію у ваших проектах, створіть для неї пакети (в приватному сховищі, щоб не робити його загальнодоступним). Для решти вашого коду додатку використовуйте простори імен PHP для організації коду, а не пакети.
Використовуйте автомонтування для автоматизації конфігурації сервісів додатку
Автомонтування сервісів - це функція, яка читає підказки вашого конструктору (або інші методи), та автоматично передає правильні сервіси кожному методу, позбавлюючи від необхідності чіткої конфігурації сервісів, та спрощуючи утримання додатку.
Використовуйте його у поєднанні з автоконфігурацією сервісів , щоб також додавати теги сервісів до тих сервісів, що їх потребують, таких як розширення Twig, слухачі подій і т.д.
Сервіси мають бути приватними завжди, коли це можливо
Робіть сервіси приватними , щоб запобігти доступ до них через
$container->get()
. Замість цього вам необхідно буде використовувати відповідне
впровадження залежності.
Використовуйте формат YAML для конфігурації власних сервісів
Якщо ви використовуєте конфігурацію services.yaml за замовчуванням , більшість сервісів будуть сконфігуровані автоматично. Проте, в деяких випадках, вам необхідно буде конфігурувати сервічи (або їх частини) вручну.
YAML - це рекомендований формат для конфігурації сервісів, так як він дружелюбний по відношенню до новачків та ємний, але Symfony також підтримує конфігурацію XML та PHP.
Використовуйте атрибути для визначення відображення сутностей Doctrine
Сутності Doctrine - це прості PHP-об'єкти, які ви зберігаєте в деякій "базі даних". Doctrine знає про ваші сутності лише через відображення метаданих, сконфігурованих для ваших класів моделей.
Doctrine підтримує декілька форматів метаданих, але рекомендовано використовувати атрибути, так як вони найбільш зручні та швидкі в налаштуванні та пошуку інформації відображення.
Контролери
Зробіть так, щоб ваш контролер розширював базовий контролер AbstractController
Symfony надає базовий контролер , який включає в себе ярлики для найбільш розповсюджених потреб на кшталт відображення шаблонів або перевірки дозволів безпеки.
Розширення ваших контролерів з цього базового контролеру пов'язує ваш застосунок з Symfony. Пов'язаність зазвичай не схвалюється, але в даному випадку може бути корисною, так як контролери не мають містити ніякої бізнес-логіки. Контролери мають містити лише декілька рядків сполучного коду, щоб ви не пов'язували важливі частини вашого додатку.
Використовуйте атрибути для конфігурації маршрутизації, кешування та безпеки
Використання атрибутів для маршрутизації, кешування та безпеки спрощує конфігурацію. Вам не потрібно шукати декілька файлів, створених в різних форматах (YAML, XML, PHP): вся конфігурація буде саме там, де вам потрібно, і використовуватиме лише один формат.
Використовуйте впровадження залежності для отримання сервісів
Якщо ви розширите базовий AbstractController
, ви зможете отримати доступ лише до
найбільш розповсюджених сервісів (наприклад, twig
, router
, doctrine
, і т.д.),
прямо з контейнеру через $this->container->get()
.
Замість цього, ви маєте використовувати впровадження залежності для отримання сервісів
шляхом підказок аргументів методів дії або аргументів
конструктора.
Використовуйте розвʼязувачі значень сутностей, якщо це зручно
Якщо ви використовуєте Doctrine, то ви можете за бажанням використати EntityValueResolver , щоб автоматично запитувати сутність і передавати її як аргумент до вашого контролера. Він також відобразить сторінку 404, якщо сутність не буде знайдено.
Якщо логіка отримання сутності зі змінної маршруту є складнішою, замість конфігурації EntityValueResolver, краще зробити запит Doctrine всередині контролера (наприклад, за допомогою виклику методу сховища Doctrine).
Шаблони
Використовуйте зміїний регістр для назв та змінних шаблонів
Використовуйте нижньорядковий snake_case для назв, каталогів та змінних шаблонів
(наприклад, user_profile
замість userProfile
та product/edit_form.html.twig
замість Product/EditForm.html.twig
).
Додавайте до фрагментів шаблонів префікс нижнього підкреслення
Фрагменти шаблонів, які також називаються "частковими шаблонами", дозволяють
повторно використовувати зміст шоблонів . Додайте
до їх назви префікс нижнього підкреслення для кращої диференціації від повних шаблонів
(наприклад, _user_metadata.html.twig
або _caution_message.html.twig
).
Форми
Визначайте свої форми як PHP-класи
Створення форм в класах дозволяє повторно використовувати їх в різних частинах додатку. Крім того, створення форм не в контролерах, спрощує код та зміст контролерів.
Додавайте кнопки форм у шаблони
Класи форми мають бути незалежними від того, де вони будуть використані. Наприклад, кнопка форми, що використовується для створення та редагування об'єктів, має змінюватися з "Додати" на "Зберегти зміни" в залежності від того, де вона використовується.
Замість додавання кнопок в класах форм або контролерах, рекомендовано додавати кнопки в шаблонах. Це також покращує розділення тем, так як стиль кнопок (CSS-клас та інші атрибути) визначається в шаблоні, а не в PHP-класі.
Однак, якщо ви створюєте форму з декількома кнопками відправки, ви маєте визначити їх в контролері, а не в шаблоні. Інакше ви не зможете перевірити, на яку кнопку натиснули, при роботі з формою в контролері.
Визначайте обмеження валідації в підлеглому об'єкті
Приєднання обмежень валідації до полей форми замість відображеного об'єкту запобігає повторному використанню валідації в інших формах або місцях, де використовується об'єкт.
Використовуйте одну дію для відображення та обробки форми
Відображення форм та обробка форм - це дві головні задачі при роботі з формами. Обидві дуже схожі (в більшості випадків майже ідентичні), тому набагато легше дозволити однії дії контролера розібратися з ними обома.
Інтернаціоналізація
Використовуйте формат XLIFF для ваших файлів перекладу
Серед всіх форматів перекладу, які підтримуються Symfony (PHP, Qt, .po
, .mo
,
JSON, CSV, INI, і т.д.), XLIFF
та gettext
мають найкращу підтримку в інструментах,
які використовуються професійними перекладачами. І так як він засновується на XML, ви
можете валідувати зміст файлу XLIFF
під час написання.
Symfony також підтримує нотатки в XLIFF-файлах, що робить їх більш зручними для перкладачів. Врешті-решт, гарні переклади - це про контекст, а ці нотатки XLIFF дозволяють вам визначати цей контекст.
Використовуйте для перекладів ключі замість рядків змісту
Використання ключів спрощує управління файлами перекладів, так як ви можете змінювати початковий зміст в шаблонах, контролерах та сервісах без необхідності оновлювати всі файли перекладів.
Ключі мають завжди описувати свою ціль, а не локацію. Наприклад, якщо форма
має поле з ярликом "Username", тоді гарним ключем буде label.username
, а не
edit_form.label.username
.
Безпека
Визначайте один брандмауер
Хіба що у вас немає двух абсолютно різних систем аутентифікації та користувачів (наприклад, форма входу в систему на головний сайт та токен-система тільки для вашого API), рекомендовано мати лише один брандмауер, щоб не ускладнювати.
Окрім того, ви маєте використовувати ключ anonymous
під вашим брандмауером. Якщо
ви вимагаєте, щоб користувачі увійшли в систему в різних розділах вашого сайту,
використовуйте опцію access_control.
Використовуйте хешування паролів auto
Авто-хешування паролів автоматично
обирає кращі можливі кодування/хешування, в залежності від вашої PHP-установки.
На даний момент, авто-хешування за замочуванням - bcrypt
.
Використовуйте виборців для реалізації точних обмежень безпеки
Якщо ваша логіка безпеки складна, вам варто створити користувацьких
виборців безпеки замість визначення довгих
виразів всередині атрибуту #[Security]
.
Веб-ресурси
Використовуйте AssetMapper для управління веб-ресурсами
Веб-ресурси - це файли CSS, JavaScript та зображень, які роблять фронтенд вашого сайту гарним та змушує його чудово працювати. AssetMapper дозволяє вам писати сучасний JavaScript і CSS без складнощів використання бандлера такого як Webpack (безпосередньо або через Webpack Encore).
Тести
Тестуйте працездатність ваших URL
В програмуванні, smoke testing складається з "попереднього тестування для виявлення маленьких помилок, достатніх для відміни релізу перспективного ПЗ". Використовуючи постачальників даних PHPUnit, ви можете визначити функціональний тест, який перевірить, щоб усі URL додатку завантажувались успішно:
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
// tests/ApplicationAvailabilityFunctionalTest.php
namespace App\Tests;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ApplicationAvailabilityFunctionalTest extends WebTestCase
{
/**
* @dataProvider urlProvider
*/
public function testPageIsSuccessful($url): void
{
$client = self::createClient();
$client->request('GET', $url);
$this->assertResponseIsSuccessful();
}
public function urlProvider(): \Generator
{
yield ['/'];
yield ['/posts'];
yield ['/post/fixture-post-1'];
yield ['/blog/category/fixture-category'];
yield ['/archives'];
// ...
}
}
Додайте цей тест при створенні вашого додатку, так як він потребує небагато зусиль та перевіряє, щоб жодна з ваших сторінок не повертала помилку. Пізніше ви додасте більш конкретні тести для кожної сторінки.
Жорстко кодуйте URL у функціональному тесті
В додатках Symfony рекомендовано генерувати URL , використовуючи маршрути для автоматичного оновлення усіх посилань при зміні URL. Однак, якщо змінюється публічний URL, користувачі не зможуть перейти по ньому, якщо ви не налаштуєте перенаправлення по новому URL.
Тому рекомендовано використовувати чисті URL в тестах замість їхнього створення з маршрутів. Кожен раз при зміні маршруту, тести будуть видавати помилку, і ви знатимете, що вам необхідно налаштувати перенаправлення.