Expressive від Wendell Adriel перетворює моделі Eloquent на типізовані PHP-об’єкти та дозволяє конвертувати їх назад для збереження даних. Мета інструменту — забезпечити чіткі межі типів для сервісів, екшенів та тестів, водночас залишаючи за Eloquent роботу із запитами, зв’язками, кастингом, правилами видимості та записом у базу.
Замість передачі важких моделей Eloquent через усю кодову базу, ви працюєте з легкими об’єктами з публічними властивостями. Це дозволяє відокремити бізнес-логіку від шару бази даних, не відмовляючись від функціоналу Eloquent.
# Підключення до моделей
Для активації функціоналу в моделях використовується trait IsExpressive. Атрибути #[Fillable] та #[Hidden] визначають, як модель відображатиметься у типізованому об’єкті:
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use WendellAdriel\Expressive\Concerns\IsExpressive;
#[Fillable(['name', 'email', 'role', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
use IsExpressive;
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function address(): HasOne
{
return $this->hasOne(Address::class);
}
protected function displayName(): Attribute
{
return Attribute::make(
get: fn (): string => "{$this->name} ({$this->role->value})",
);
}
}
# Генерація класів Expressive
Пакет містить команду Artisan для швидкого створення типізованого класу на основі моделі:
php artisan make:expressive User --model="App\Models\User"
За замовчуванням згенеровані класи зберігаються в App\Expressive. Кожен клас розширює базовий Expressive і містить типізовані властивості, що відповідають колонкам бази, зв’язкам та аксесорам моделі:
use App\Enums\UserRole;
use App\Expressive\Address;
use App\Expressive\Post;
use Carbon\CarbonInterface;
use Illuminate\Support\Collection;
use WendellAdriel\Expressive\Attributes\Relationship;
use WendellAdriel\Expressive\Attributes\Virtual;
use WendellAdriel\Expressive\Expressive;
final class User extends Expressive
{
public ?int $id = null;
public string $name;
public string $email;
public UserRole $role;
public ?CarbonInterface $createdAt = null;
#[Relationship]
public ?Address $address = null;
/** @var Collection<int, Post>|null */
#[Relationship]
public ?Collection $posts = null;
#[Virtual]
public ?string $displayName = null;
}
Атрибут #[Relationship] позначає властивості для зв’язків Eloquent, а #[Virtual] — віртуальні значення (наприклад, displayName), яких немає в таблиці бази даних.
# Конвертація моделей у типізовані об'єкти
Метод expressive() можна викликати для моделі, колекції або Query Builder. Ви також можете вибірково додавати аксесори та зв’язки:
// Окремо взята модель із віртуальним атрибутом
$user = User::findOrFail(1)->expressive(attributes: ['display_name']);
// Колекція із завантаженими зв’язками
$users = User::query()->get()->expressive(relationships: ['posts']);
// Прямо через Query Builder
$users = User::query()
->where('active', true)
->expressive(relationships: ['posts']);
Зв’язки конвертуються рекурсивно: HasOne стає об’єктом Expressive, а HasMany — колекцією об’єктів Collection.
# Збереження типізованих об'єктів
Процес працює і у зворотному напрямку. Метод model() створює незбережений екземпляр Eloquent, а save() — записує дані в базу:
// Створення моделі в пам’яті без запису в БД
$model = (new App\Expressive\User([
'name' => 'Wendell',
'email' => 'wendell@example.com',
]))->model();
// Збереження моделі та її основних зв’язків
$saved = (new App\Expressive\User([
'name' => 'Wendell',
'email' => 'wendell@example.com',
]))->save();
Метод save() підтримує збереження кореневої моделі разом із прямими зв’язками, як-от BelongsTo, HasOne, HasMany, MorphOne та MorphMany. Обидва методи враховують правила масового заповнення (mass-assignment) та ігнорують не дозволені для заповнення атрибути.
# Встановлення
Встановити пакет можна через Composer:
composer require wendelladriel/laravel-expressive
Після цього опублікуйте файл конфігурації:
php artisan vendor:publish --tag="expressive"
Пакет потребує PHP 8.3 або новішої версії та підтримує Laravel 12 і 13. Більше деталей доступно в документації або в репозиторії на GitHub.