• Czas czytania ~5 min
  • 10.07.2022

Elokwentne atrybuty rzucane są jedną z potężniejszych cech Laravela; niektórzy ludzie używają ich religijnie, podczas gdy inni mają tendencję do unikania ich. W tym samouczku omówię kilka różnych przykładów ich używania i, co najważniejsze, dlaczego powinieneś ich używać.

Możesz utworzyć nowy projekt Laravel lub użyć istniejącego w tym samouczku.Zapraszam do śledzenia razem ze mną lub jeśli chcesz przeczytać i zapamiętać - to też jest w porządku. Najważniejszą rzeczą, którą należy od tego odjąć, jest to, jak dobre mogą być elokwentne rzuty.

Zacznijmy od naszego pierwszego przykładu, podobnego do tego w dokumentacji Laravela. Dokumentacja Laravela pokazuje pobranie adresu użytkownika, ale także użycie Modelu.Teraz wyobraź sobie, że zamiast tego była to kolumna JSON użytkownika lub dowolny model tego faktu. Możemy pobierać i ustawiać niektóre dane oraz dodawać dodatkowe, aby działały tak, jak chcemy. Musimy zainstalować pakiet przez Jess Archer o nazwie Laravel Castable Data Transfer Object.Możesz zainstalować to za pomocą następującego polecenia kompozytora:

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

Teraz mamy to zainstalowane, zaprojektujmy naszą klasę 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,
}

Mamy klasę PHP, która rozszerza CastableDataTransferObject, która pozwala nam oznaczyć właściwości i ich typy, a następnie obsługuje wszystkie opcje pobierania i ustawiania za kulisami.Ten pakiet używa pakietu Spatie o nazwie Data Transfer Object pod maską, co było dość popularne w społeczności.Więc teraz, gdybyśmy chcieli to w ogóle rozszerzyć, moglibyśmy:

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,
		]);
	}
}

Mamy klasę Address, która rozszerza klasę CastableDataTransferObject z pakietu, która obsługuje wszystkie nasze pobieranie i ustawianie danych w bazie danych. Mamy wtedy wszystkie nieruchomości, które chcemy przechowywać - jest to adres w formacie brytyjskim, ponieważ tam mieszkam.Wreszcie mamy dodaną metodę, która pomaga nam sformatować ten adres jako ciąg - jeśli chcemy wyświetlić go w dowolnej formie interfejsu użytkownika. Moglibyśmy pójść o krok dalej dzięki walidacji kodu pocztowego za pomocą wyrażenia regularnego lub interfejsu API – ale może to przekreślić sens samouczka.

Przejdźmy do innego przykładu: pieniędzy.Wszyscy rozumiemy pieniądze; wiemy, że możemy używać pieniędzy w jego najmniejszej formie monet i większej formie banknotów. Wyobraź sobie więc, że mamy sklep e-commerce, w którym przechowujemy nasze produkty (prosty sklep, więc nie musimy się martwić o warianty itp.) i mamy kolumnę o nazwie cena, którą przechowujemy w najmniejszym mianowniku naszej waluty. Jestem w Wielkiej Brytanii, więc zadzwonię do tego pensa.Jednak w USA to centy. Powszechne podejście do przechowywania wartości pieniężnych w naszej bazie danych, ponieważ pozwala uniknąć problemów z matematyką zmiennoprzecinkową. Zaprojektujmy więc rzut dla tej kolumny ceny, tym razem używając pakietu 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(),
		];
	}
}

Więc ta klasa nie używa pakietu DTO, ale zamiast tego zwraca nową instancję z własnymi metodami. W naszym konstruktorze przekazujemy w ilości.Kiedy otrzymujemy i ustawiamy kwotę, wykonujemy rzutowanie na tablicę w celu przechowywania w bazie danych lub analizujemy tablicę, aby zwrócić nowy obiekt pieniędzy. Oczywiście zamiast tego moglibyśmy uczynić z tego obiekt przesyłania danych i trochę bardziej kontrolować sposób, w jaki obchodzimy się z pieniędzmi. Jednak biblioteka php money jest całkiem nieźle przetestowana i niezawodna, a jeśli mam być szczery - niewiele zrobiłbym inaczej.

Przejdźmy do nowego przykładu. Mamy aplikację CRM i chcemy przechowywać godziny lub dni otwarcia firmy. Każda firma musi być w stanie oznaczyć dni, w których są otwarte, ale tylko w prosty, prawdziwy lub fałszywy sposób. Możemy więc utworzyć nowy rzut, ale najpierw stworzymy klasę, na którą chcemy rzutować, podobnie jak powyższa klasa 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,
	) {}
}

Na początek wszystko jest w porządku; chcemy tylko przechowywać, jeśli firma jest otwarta każdego dnia i mieć szereg dni, które liczą się jako święta. Następnie możemy zaprojektować naszą obsadę:

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,
		);
	}
}

Nasz konstruktor zaakceptuje tablicę dat, aby uprościć zapisywanie (musisz jednak upewnić się, że poprawnie zweryfikowałeś dane wejściowe).Następnie, gdy chcemy odzyskać dane z bazy danych, tworzymy nowy obiekt Open, przekazując daty.Jednak tutaj wywołujemy metodę fromArray, której jeszcze nie stworzyliśmy, więc zaprojektujmy ją teraz:

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'),
	);
}

Więc ręcznie tworzymy nasz obiekt Open za pomocą pomocnika Laravel data_get, co jest niezwykle przydatne, upewniając się, że rzutujemy na właściwy typ.Teraz, gdy pytamy, mamy dostęp:

$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

Jak widać, możemy sprawić, że będzie to niezwykle czytelne, aby środowisko programisty było logiczne i łatwe do naśladowania. Czy możemy to rozszerzyć, aby dodać dodatkowe metody, takie jak jest to otwarte dzisiaj?

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

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297