wendelladriel/laravel-expressive

Typed Objects for Eloquent

Maintainers

Package info

github.com/WendellAdriel/laravel-expressive

Homepage

pkg:composer/wendelladriel/laravel-expressive

Statistics

Installs: 29

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-05-28 11:03 UTC

This package is auto-updated.

Last update: 2026-05-28 11:09:04 UTC


README

Expressive

Expressive

Typed Objects for Eloquent

Packagist PHP from Packagist Laravel versions GitHub Workflow Status (main) Total Downloads

Installation

You can install the package via composer:

composer require wendelladriel/laravel-expressive

You can publish the config file with:

php artisan vendor:publish --tag="expressive"

Usage

Add the IsExpressive trait to models that should convert to typed Expressive objects:

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use WendellAdriel\Expressive\Concerns\IsExpressive;

#[Fillable(['name', 'email', 'role', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
    use IsExpressive, Notifiable;

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    public function address(): HasOne
    {
        return $this->hasOne(Address::class);
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'role' => UserRole::class,
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    protected function displayName(): Attribute
    {
        return Attribute::make(
            get: fn (): string => "{$this->name} ({$this->role->value})",
        );
    }
}

Generate an Expressive class from a model:

php artisan make:expressive User --model="App\Models\User"

The generated class will live in App\Expressive by default:

use App\Enums\UserRole;
use App\Expressive\Address;
use App\Expressive\Post;
use App\Models\User as UserModel;
use Carbon\CarbonInterface;
use Illuminate\Support\Collection;
use WendellAdriel\Expressive\Attributes\Relationship;
use WendellAdriel\Expressive\Attributes\Virtual;
use WendellAdriel\Expressive\Expressive;

/**
 * @extends Expressive<UserModel>
 */
final class User extends Expressive
{
    public ?int $id = null;

    public string $name;

    public string $email;

    public UserRole $role;

    public string $password;

    public ?string $rememberToken = null;

    public ?CarbonInterface $emailVerifiedAt = null;

    public ?CarbonInterface $createdAt = null;

    public ?CarbonInterface $updatedAt = null;

    #[Relationship]
    public ?Address $address = null;

    /** @var Collection<int, Post>|null */
    #[Relationship]
    public ?Collection $posts = null;

    #[Virtual]
    public ?string $displayName = null;
}

Loaded relationships are converted recursively. A HasOne relation becomes the related model's Expressive object, and a HasMany relation becomes a Collection of Expressive objects.

Convert models, collections, and builders:

$user = User::findOrFail(1)->expressive(attributes: ['display_name']);
$users = User::query()->get()->expressive(relationships: ['posts']);
$users = User::query()
    ->where('active', true)
    ->expressive(relationships: ['posts']);

Access the full documentation here.

Changelog

Please see the changelog for more information on what has changed recently.

Contributing

Thank you for considering contributing to Expressive! You can read the contribution guide here.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

Expressive is open-sourced software licensed under the MIT license.