Натискання Laravel далі - найкращі поради та хороші практики для Laravel 5.7

Ця публікація має аудіоверсію завдяки додатку Blogcast Мігеля П'єдрафіти.

Laravel вже відомий багатьма розробниками PHP для написання чистого, робочого та відлагодженого коду. Він також має підтримку багатьох функцій, які іноді не вказані в документах або вони були, але їх видаляли з різних причин.

Я працюю з Laravel у виробництві-використанні вже 2 роки, і я навчився писати поганий код, щоб покращити код, і я скористався перевагою Laravel з першого разу, коли я почав писати з ним код. Я збираюся показати вам таємничі хитрощі, які можуть вам допомогти при написанні коду з Laravel.

Використовуйте місцеві сфери застосування, коли потрібно запитувати речі

У Laravel є чудовий спосіб писати запити до драйвера вашої бази даних за допомогою Query Builder. Щось на зразок цього:

$ замовлення = Замовлення :: де ('статус', 'доставлено') -> де ('оплачено', правда) -> отримати ();

Це досить приємно. Це змусило мене відмовитися від SQL і зосередитись на кодуванні, яке для мене є більш доступним. Але цей біт коду можна краще записати, якщо ми будемо використовувати локальні області застосування.

Локальні сфери дозволяють нам створювати власні методи побудови запитів, на які ми можемо зв'язати ланцюги, намагаючись отримати дані. Наприклад, замість -> де () заяви, ми можемо використовувати -> доставлений () і -> оплачений () більш чистий спосіб.

По-перше, у нашу модель замовлення слід додати кілька методів:

клас Замовлення розширює Модель
{
   ...
   public function rangeDelivered ($ запит) {
      повернути $ query-> where ('статус', 'доставлено');
   }
   public function rangePaid ($ запит) {
      повернути $ query-> where ('оплачено', правда);
   }
}

При оголошенні локальних областей слід використовувати точне іменування області [Щось]. Таким чином, Laravel буде знати, що це область, і використовуватиме його у вашому Builder Query. Переконайтеся, що ви включили перший аргумент, який автоматично вводиться Laravel, і це екземпляр конструктора запитів.

$ замовлення = Замовлення :: доставлено () -> оплачено () -> отримати ();

Для більш динамічного пошуку можна використовувати динамічні локальні області застосування. Кожна область дозволяє надати параметри.

клас Замовлення розширює Модель
{
   ...
   public function rangeStatus ($ запит, рядок $ status) {
      повернути $ query-> where ('status', $ status);
   }
}
$ замовлення = Замовлення :: статус ('доставлено') -> оплачено () -> отримати ();

Пізніше в цій статті ви дізнаєтеся, чому слід використовувати snake_case для полів баз даних, але ось перша причина: Laravel за замовчуванням використовує де [Something] для заміни попередньої області. Тож замість попереднього ви можете:

Замовлення :: деStatus ('доставлено') -> сплачено () -> отримати ();

Laravel шукатиме версію snake_case Щось звідки [Something]. Якщо у вашій БД є статус, ви будете використовувати попередній приклад. Якщо у вас є shipping_status, ви можете використовувати:

Замовлення :: деShippingStatus ('доставлено') -> оплачено () -> отримати ();

Це твій вибір!

Використовуйте запити файлів за потреби

Laravel дає вам красномовний спосіб підтвердити свої форми. Або запит POST або GET-запит, він не пропустить його, якщо вам це потрібно.

Ви можете перевірити цей спосіб у своєму контролері:

загальнодоступний магазин функцій (Запит $ запиту)
{
    $ validatedData = $ request-> validate ([
        'title' => 'обов'язковий | унікальний: posts | max: 255',
        'body' => 'потрібно',
    ]);

    // Повідомлення в блозі дійсне ...
}

Але коли у вас в контролері занадто багато коду, це може бути дуже неприємно. Ви хочете зменшити якомога більше коду у своєму контролері. Принаймні, це те, що я вважаю першим, що мені потрібно писати дуже багато логіки.

Laravel дає вам * милий * спосіб перевірки запитів, створюючи класи запитів та використовуючи їх замість старомодного класу Request. Вам просто потрібно створити свій запит:

php artisan make: запит StoreBlogPost

Всередині програми / Http / Запити / папки ви знайдете файл запиту:

клас StoreBlogPostRequest розширює FormRequest
{
   public function autize ()
   {
      повернути $ this-> user () -> can ('create.posts');
   }
   правила публічної функції ()
   {
       повернути [
         'title' => 'обов'язковий | унікальний: posts | max: 255',
         'body' => 'потрібно',
       ];
   }
}

Тепер замість вашого Illuminate \ Http \ Request у вашому методі слід замінити новостворений клас:

використовувати додаток \ Http \ Запити \ StoreBlogPostRequest;
загальнодоступний магазин функцій (StoreBlogPostRequest $ запит)
{
    // Повідомлення в блозі дійсне ...
}

Метод autorize () повинен бути булевим. Якщо він невірний, він викине 403, тому переконайтеся, що ви його зафіксували у застосуванні методу app / Exceptions / Handler.php 's render ():

надання публічної функції ($ запит, виняток $ виняток)
{
   if ($ виключення instanceof \ Illuminate \ Auth \ Access \ AuthorizationException) {
      //
   }
   return parent :: render ($ запит, $ виняток);
}

Відсутній метод у класі запиту - це функція messages (), тобто масив, що містить повідомлення, які будуть повернуті у разі невдачі перевірки:

клас StoreBlogPostRequest розширює FormRequest
{
   public function autize ()
   {
      повернути $ this-> user () -> can ('create.posts');
   }
   правила публічної функції ()
   {
       повернути [
         'title' => 'обов'язковий | унікальний: posts | max: 255',
         'body' => 'потрібно',
       ];
   }
   повідомлення про загальнодоступні функції ()
   {
      повернути [
        'title.required' => 'Назва потрібна.',
        'title.unique' => 'Заголовок публікації вже існує.',
        ...
      ];
   }
}

Щоб зафіксувати їх у своєму контролері, ви можете використовувати змінну помилок у файлах лез:

@if ($ помилки-> будь-який ())
   @foreach ($ error-> all () як $ error)
      {{$ error}}
   @endforeach
@endif

Якщо ви хочете отримати повідомлення про валідацію певного поля, ви можете зробити це так, як тоді (воно поверне хибно-булеву сутність, якщо перевірка пройде для цього поля):


@if ($ error-> has ('title'))
   
@endif

Чарівні сфери застосування

Будуючи речі, ви можете використовувати чарівні приціли, які вже вбудовані

  • Отримайте результати створеними create_at, у зменшенні:
Користувач :: найновіший () -> get ();
  • Отримайте результати за будь-яким полем у порядку зменшення:
Користувач :: найновіший ('last_login_at') -> get ();
  • Отримайте результати у випадковому порядку:
Користувач :: inRandomOrder () -> get ();
  • Запустіть метод запиту, лише якщо щось істинне:
// Припустимо, що користувач перебуває на сторінці новин, і бажає спочатку сортувати його за останнім
// mydomain.com/news?sort=new
Користувач :: коли ($ request-> query ('сортувати'), функція ($ query, $ sort) {
   if ($ sort == 'new') {
      повернути $ query-> latest ();
   }
   
   повернути $ запит;
}) -> get ();

Замість того, коли () ви можете використовувати хіба що, це навпаки, коли ().

Використовуйте відносини, щоб уникнути великих запитів (або неправильно написаних)

Ви коли-небудь використовували тону приєднань у запиті, щоб отримати більше інформації? Написати ці команди SQL навіть із програмою Query Builder досить важко, але моделі вже роблять це з Relationships. Можливо, ви не будете знайомі спочатку через велику кількість інформації, яку надає документація, але це допоможе вам краще зрозуміти, як все працює і як зробити вашу програму більш гладкою.

Перевірте документацію щодо відносин тут.

Використовуйте роботу для трудомістких завдань

Laravel Jobs - це потужний необхідний інструмент для виконання завдань у фоновому режимі.

  • Ви хочете надіслати електронний лист? Вакансії.
  • Ви хочете транслювати повідомлення? Вакансії.
  • Ви хочете обробити зображення? Вакансії.

Завдання допомагають вам відмовитись від завантаження часу для своїх користувачів на такі трудомісткі завдання. Їх можна помістити в іменовані черги, їм можна визначити пріоритет, і здогадайтесь, що - Laravel реалізував черги майже скрізь, де це було можливо: або обробляти якийсь PHP у фоновому режимі, або надсилати сповіщення, або транслювати події, черги є!

Ви можете перевірити документацію черг тут.

Я люблю використовувати Laravel Horizon для черг, оскільки його легко налаштувати, його можна демонструвати за допомогою Supervisor і через файл конфігурації, я можу сказати Horizon, скільки процесів потрібно для кожної черги.

Дотримуйтесь стандартів бази даних та аксесуарів

Laravel навчає вас з самого початку, що ваші змінні та методи повинні бути $ camelCase camelCase (), тоді як поля вашої бази даних повинні бути snake_case. Чому? Тому що це допомагає нам будувати кращі аксесуари.

Аксесуари - це власні поля, які ми можемо побудувати прямо з нашої моделі. Якщо наша база даних містить ім’я, прізвище та вік, ми можемо додати спеціальне поле з ім'ям, яке поєднує ім'я та прізвище. Не хвилюйтеся, це не буде записано в БД жодним чином. Це лише спеціальний атрибут, який має ця конкретна модель. Усі аксесуари, як і сфери, мають спеціальний синтаксис іменування: getSomethingAttribute:

клас Користувач розширює Модель
{
   ...
   публічна функція getNameAttribute (): рядок
   {
       повернути $ this-> first_name. ' '. $ this-> прізвище;
   }
}

При використанні $ user-> name він поверне конкатенацію.

За замовчуванням атрибут імені не відображається, якщо ми dd ($ user), але ми можемо зробити це загальнодоступним за допомогою змінної $ appends:

клас Користувач розширює Модель
{
   захищені $ appends = [
      "ім'я",
   ];
   ...
   публічна функція getNameAttribute (): рядок
   {
       повернути $ this-> first_name. ' '. $ this-> прізвище;
   }
}

Тепер, кожного разу, коли ми dd ($ user), ми бачимо, що змінна є (але все-таки, її немає в базі даних)

Однак будьте обережні: якщо у вас вже є поле імені, справи дещо відрізняються: ім’я всередині $ додається більше не потрібно, а функція атрибута чекає одного параметра, який є вже збереженою змінною (ми більше не будемо використовуйте $ this).

У цьому ж прикладі ми можемо захотіти ucfirst () імена:

клас Користувач розширює Модель
{
   захищені $ appends = [
      //
   ];
   ...
   публічна функція getFirstNameAttribute ($ firstName): рядок
   {
       повернути ucfirst ($ firstName);
   }
   публічна функція getLastNameAttribute ($ lastName): рядок
   {
      повернути ucfirst ($ lastName);
   }
}

Тепер, коли ми використовуємо $ user-> first_name, він поверне верхній регістр рядка.

Завдяки цій функції добре використовувати тему snake_case для полів вашої бази даних.

Не зберігайте статичні дані, пов’язані з моделлю, у налаштуваннях

Що я люблю робити, це зберігати статичні дані, пов'язані з моделлю, всередині моделі. Дозвольте мені показати вам.

Замість цього:

BettingOdds.php

клас BettingOdds розширює Модель
{
   ...
}

config / bettingOdds.php

повернути [
   'спорт' => [
      'футбол' => 'спорт: 1',
      'теніс' => 'спорт: 2',
      'баскетбол' => 'спорт: 3',
      ...
   ],
];

І отримати доступ до них за допомогою:

config ("bettingOdds.sports.soccer");

Я вважаю за краще це робити:

BettingOdds.php

клас BettingOdds розширює Модель
{
   захищені статичні $ sports = [
      'футбол' => 'спорт: 1',
      'теніс' => 'спорт: 2',
      'баскетбол' => 'спорт: 3',
      ...
   ];
}

І отримати доступ до них за допомогою:

BettingOdds :: $ sports ['футбол'];

Чому? Оскільки його легше використовувати в подальших операціях:

клас BettingOdds розширює Модель
{
   захищені статичні $ sports = [
      'футбол' => 'спорт: 1',
      'теніс' => 'спорт: 2',
      'баскетбол' => 'спорт: 3',
      ...
   ];
   сфера публічної функціїSport ($ запит, рядок $ sport)
   {
      if (! isset (self :: $ sports [$ sport])) {
         повернути $ запит;
      }
      
      повернути $ query-> where ('sport_id', self :: $ sports [$ sport]);
   }
}

Тепер ми можемо насолоджуватися сферами:

BettingOdds :: sport ('футбол') -> get ();

Використовуйте колекції замість обробки необробленого масиву

Ще в ті часи ми звикли працювати з масивами в сирому вигляді:

$ фрукти = ['яблуко', 'груша', 'банан', 'полуниця'];
foreach ($ фрукти як $ фрукти) {
   відлуння «я маю». $ фрукти;
}

Тепер ми можемо використовувати передові методи, які допоможуть нам обробити дані в масивах. Ми можемо фільтрувати, перетворювати, повторювати та змінювати дані всередині масиву:

$ фрукти = збирати ($ фрукти);
$ фрукти = $ фрукти-> відхилити (функція ($ фрукти) {
   повернути $ фрукт === 'яблуко';
}) -> toArray ();
['груша', 'банан', 'полуниця']

Для отримання більш детальної інформації перегляньте велику документацію про колекції.

Під час роботи з Builder запитів метод -> get () повертає екземпляр Collection. Але будьте обережні, щоб не плутати колекцію із конструктором запитів:

  • У Inside Builder Query ми не отримали жодних даних. У нас є багато методів, пов'язаних із запитами: orderBy (), where () тощо.
  • Після натискання -> get (), дані витягуються, пам'ять споживається, вона повертає екземпляр колекції. Деякі методи побудови запитів недоступні, або вони є, але назва їх інша. Перевірте доступні методи для отримання додаткової інформації.

Якщо ви можете фільтрувати дані на рівні Builder запитів, зробіть це! Не покладайтеся на фільтрацію, коли мова заходить про екземпляр Collection - ви використовуєте занадто багато пам’яті, де не захочете. Обмежте свої результати та використовуйте індекси на рівні БД.

Використовуйте пакети і не вигадуйте колесо

Ось кілька пакунків, які я використовую:

  • Директиви щодо лез Ларавеля
  • Laravel CORS (захищайте свої маршрути від іншого походження)
  • Laravel Tag Helper (краще використання тегів HTML у Blade)
  • Laravel Sluggable (корисно, якщо мова йде про генерацію молюсків)
  • Laravel Responder (спростити побудову API JSON)
  • Втручання зображення (обробка зображень у стилі)
  • Horizon (черги нагляду з мінімальною конфігурацією)
  • Socialite (мінімальна конфігурація для входу з соціальними мережами)
  • Паспорт (реалізація OAuth для маршрутів)
  • ActivityLog Spatie (активність треку для моделей)
  • Резервне копіювання Spatie (файли резервного копіювання та бази даних)
  • Blade-X Spatie (визначте свої власні теги HTML; добре працює з помічником Lag Lag)
  • Медіатека Spatie (простий спосіб приєднання файлів до моделей)
  • Кеш відповіді Spatie (відповіді контролера кеша)
  • Макроси колекції Spatie (більше макросів у колекціях)

Ось декілька пакунків, які я написав:

  • Дружив (як, слідкуйте за блоками, як у соціальних мережах)
  • Розклад (створити графіки руху та перевірити години та дні)
  • Рейтинг (моделі оцінок)
  • Guardian (система дозволів, простий спосіб)

Занадто важко зрозуміти? Доберись до мене!

Якщо у вас є додаткові запитання щодо Laravel, якщо вам потрібна допомога з будь-якою інформацією, що стосується DevOps або просто хочете сказати спасибі !, ви можете знайти мене на Twitter @rennokki!