• Час читання ~2 хв
  • 10.07.2022

Атрибути Eloquent Castable є однією з найпотужніших функцій Laravel; деякі люди використовують їх релігійно, а інші, як правило, ухиляються від них. У цьому підручнику я розповім кілька прикладів їх використання та, найголовніше, чому ви повинні їх використовувати.

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

Почнемо з нашого першого прикладу, подібного до документації Laravel. Документація Laravel показує отримання адреси користувача, але також використання моделі.Тепер уявіть собі, якби це був стовпець JSON для користувача чи будь-яка модель для цього факту. Ми можемо отримати та встановити деякі дані та додати додаткові, щоб це працювало так, як ми хочемо. Нам потрібно встановити пакет від Jess Archer під назвою Об'єкт передачі даних Laravel Castable.Ви можете встановити це за допомогою такої команди composer:

composer require jessarcher/laravel-castable-data-transfer-object

Тепер ми встановили це, давайте розробимо наш клас Castable:

namespace App\Casts;
 
use JessArcher\CastableDataTransferObject\CastableDataTransferObject;
 
class Address implements CastableDataTransferObject
{
	public string $nameOrNumber,
	public string $streetName,
	public string $localityName,
	public string $town,
	public string $county,
	public string $postalCode,
	public string $country,
}

У нас є клас PHP, який розширює CatableDataTransferObject, що дозволяє нам позначати властивості та їх типи, а потім обробляє всі параметри отримання та налаштування за кадром.Цей пакет використовує пакет Spatie під назвою Data Transfer Object під капотом, який був досить популярний у суспільстві.Тож тепер, якби ми взагалі хотіли розширити це, ми могли б:

namespace App\Casts;
 
use JessArcher\CastableDataTransferObject\CastableDataTransferObject;
 
class Address implements CastableDataTransferObject
{
	public string $nameOrNumber,
	public string $streetName,
	public string $localityName,
	public string $town,
	public string $county,
	public string $postalCode,
	public string $country,
 
	public function formatString(): string
	{
		return implode(', ', [
			"$this->nameOrNumber $this->streetName",
			$this->localityName,
			$this->townName,
			$this->county,
			$this->postalCode,
			$this->country,
		]);
	}
}

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

Давайте перейдемо до іншого прикладу: гроші.Ми всі розуміємо гроші; ми знаємо, що ми можемо використовувати гроші як у найменшій формі монет, так і в більшій формі банкнот. Тож уявіть собі, що у нас є магазин електронної комерції, де ми зберігаємо наші продукти (простий магазин, тому нам не доведеться турбуватися про варіанти тощо), і у нас є стовпець price, який ми зберігаємо у найменшому знаменнику нашої валюти. Я у Великобританії, тому я буду називати цей пенс.Однак у США це центи. Поширений підхід до зберігання грошових значень у нашій базі даних, оскільки він дозволяє уникнути проблем із математикою з плаваючою комою. Тож давайте розробимо перебір для цього стовпця ціни, цього разу використовуючи пакет php moneyphp/money:

namespace App\Casts;
 
use Money\Currency;
use Money\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
 
class Money implements CastsAttributes
{
    public function __construct(
	    protected int $amount,
	) {}
 
	public function get($model, string $key, $value, array $attributes)
	{
	    return new Money(
			$attributes[$this->amount],
			new Currency('GBP'),
		);
	}
 
	public function set($model, string $key, $value, array $attributes)
	{
		return [
			$this->amount => (int) $value->getAmount(),
			$this->curreny => (string) $value->getCurrency(),
		];
	}
}

Отже цей клас не використовує пакет DTO, а повертає новий екземпляр зі своїми власними методами. У нашому конструкторі ми передаємо кількість.Коли ми отримуємо та встановлюємо суму, ми або перетворюємо на масив для зберігання в базі даних, або аналізуємо масив, щоб повернути новий об’єкт money. Звичайно, ми могли б замість цього зробити це об’єктом передачі даних і трохи більше контролювати те, як ми обробляємо гроші. Проте бібліотека грошей php досить добре перевірена та надійна, і якщо чесно, я б не так багато зробив по-іншому.

Давайте перейдемо до нового прикладу. У нас є CRM-додаток, і ми хочемо зберігати робочі години або дні роботи. Кожна компанія повинна мати можливість відзначати дні, коли вони відкриті, але лише простим істинним або хибним способом. Таким чином, ми можемо створити новий приведення, але спочатку ми створимо клас, до якого ми хочемо привести, схожий на клас PHP money вище.

namespace App\DataObjects;
 
class Open
{
    public function __construct(
	    public readonly bool $monday,
		public readonly bool $tuesday,
		public readonly bool $wednesday,
		public readonly bool $thursday,
		public readonly bool $friday,
		public readonly bool $saturday,
		public readonly bool $sunday,
		public readonly array $holidays,
	) {}
}

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

namespace App\Casts;
 
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
 
class OpenDaysCast implements CastsAttributes
{
	public function __construct(
		public readonly array $dates,
	) {}
 
	public function set($model, string $key, $value, array $attributes)
	{
		return $this->dates;
	}
 
	public function get($model, string $key, $value, array $attributes)
	{
		return Open::fromArray(
			dates: $this->dates,
		);
	}
}

Наш конструктор прийматиме масив дат, щоб спростити збереження (однак, вам потрібно буде переконатися, що ви правильно перевірили введені дані тут).Потім, коли ми хочемо повернути дані з бази даних, ми створюємо новий об’єкт Open, передаючи дати.Однак тут ми викликаємо метод fromArray, який нам ще належить створити, тому давайте розробимо це зараз:

public static function fromArray(array $dates): static
{
    return new static(
	    monday: (bool) data_get($dates, 'monday'),
		tuesday: (bool) data_get($dates, 'tuesday'),
		wednesday: (bool) data_get($dates, 'wednesday'),
		thursday: (bool) data_get($dates, 'thursday'),
		friday: (bool) data_get($dates, 'friday'),
		saturday: (bool) data_get($dates, 'saturday'),
		sunday: (bool) data_get($dates, 'sunday'),
		holidays: (array) data_get($dates, 'holidays'),
	);
}

Тож ми вручну створюємо наш об’єкт Open за допомогою допоміжного засобу Laravel data_get, що надзвичайно зручно, щоб переконатися, що ми приведемо до правильного типу.Тепер, коли ми запитуємо, ми маємо доступ:

$business = Business:query()->find(1);
 
// Is this business open on mondays?
$business->open->monday; // true|false
 
// Is the business open on tuesdays?
$business->open->tuesday; // true|false
 
// What are the busines holiday dates?
$business->open->holidays; // array

Як ви бачите, ми можемо зробити це надзвичайно читабельним, щоб розробник був логічним і легко зрозумілим. Чи можемо ми потім розширити це, щоб додати додаткові методи, наприклад, зараз він відкритий?

public function today(): bool
{
    $date = now();
 
	$day = strtolower($date->englishDayOfWeek());
 
	if (! $this->$day) {
	    return false;
	}
 
	return ! in_array(
	    $date->toDateString(),
		$this->holidays,
	);
}
$business = Business:query()->find(1);
 
// Is the business open today?
$business->open->today();

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