• Час читання ~4 хв
  • 25.08.2022

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

Я буду використовувати той самий приклад для кожного підходу, щоб ви могли побачити пряме порівняння.У цьому прикладі властивість UUID моделі буде призначено UUID під час створення самої моделі.

Наш перший підхід використовує статичний метод завантаження моделі для реєстрації поведінки. Це дозволяє нам працювати безпосередньо над моделлю та реєструвати зворотний виклик, який ми хочемо запустити під час створення моделі.

declare(strict_types=1);
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
 
class Office extends Model
{
	public static function boot(): void
	{
		static::creating(fn (Model $model) =>
			$model->uuid = Str::uuid(),
		);
	}
}

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

Це чудово підводить нас до другого підходу, використовуючи ознаку. У Laravel ваші моделі можуть успадковувати ознаки та автоматично завантажувати їх, якщо ви створюєте метод на своїй ознакі, який починається з boot і закінчується назвою ознаки. Ось приклад:

declare(strict_types=1);
 
namespace App\Models\Concerns;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
 
trait HasUuid
{
	public static function bootHasUuid(): void
	{
		static::creating(fn (Model $model) =>
			$model->uuid = Str::uuid(),
		);
	}
}

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

Це веде нас до наступного варіанту, моделі спостерігачів.Model Observers — це підхід на основі класів до реагування на події моделі, де методи відповідають конкретним подіям, що запускаються.

declare(strict_types=1);
 
namespace App\Observers;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
 
class OfficeObserver
{
	public function creating(Model $model): void
	{
		$model->uuid = Str::uuid();
	}
}

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

Ще один спосіб підійти до цієї проблеми — скористатися властивістю $dispatchesEvents у самій моделі Eloquent. Це властивість кожної моделі Eloquent, яка дозволяє вам перераховувати події, які ви хочете прослухати, і клас, що викликається для цих подій.

declare(strict_types=1);
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
 
class Office extends Model
{
	protected $dispatchesEvents = [
		'creating' => SetModelUuid::class,
	];
}

SetModelUuid< /код>буде створено протягом життєвого циклу моделі Eloquent і це ваш шанс додати поведінку та властивості до моделі.

declare(strict_types=1);
 
namespace App\Models\Events;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
 
class SetModelUuid
{
	public function __construct(Model $model)
	{
		$model->uuid = Str::uuid();
	}
}

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

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

Наприклад, спостерігач є хорошим варіантом, якщо вам потрібно додати кілька властивостей до моделі подій моделі .Однак чи це найкращий варіант? Як щодо того, якби ми використали властивість подій диспетчеризації, щоб запустити спеціальний конвеєр для цієї моделі?

declare(strict_types=1);
 
namespace App\Models\Pipelines;
 
use App\Models\Office
 
class OfficeCreatingPipeline
{
	public function __construct(Office $model)
	{
		app(Pipeline::class)
			->send($model)
			->through([
				ApplyUuidProperty::class,
				TapCreatedBy::class,
			]);
	}
}

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

Як ви обробляєте модельні події у своїх проектах Laravel? Повідомте нас у Twitter!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297