Skip to content

Generating Expressive classes

Introduction

The make:expressive command generates an Expressive class from an Eloquent model. It inspects the model table, casts, relationships, and accessors, then writes a class with public typed properties.

The generator is a starting point. You may edit the generated class when your application needs a different boundary than the model's full shape.

Generating a class

Generate an Expressive class by passing the class name and model:

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

With the default configuration, the generated file is written to app/Expressive/User.php and uses the App\Expressive namespace.

If the model option is omitted, the command asks which model should be mapped.

Choosing the target class

You may override the namespace or suffix for a single generation run:

shell
php artisan make:expressive User \
    --model="App\Models\User" \
    --namespace="App\Data" \
    --suffix="Expressive"

This writes App\Data\UserExpressive. These options override expressive.namespace and expressive.suffix only for the current command.

Selecting attributes

By default, the generator includes model table columns and detected virtual accessors. Use --without-attributes to generate only relationships:

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

Use --attributes to generate only selected attributes:

shell
php artisan make:expressive User \
    --model="App\Models\User" \
    --attributes="name,email,display_name"

The selected list may include table columns and detected virtual accessors. The command fails if a requested attribute cannot be found.

Selecting relationships

By default, the generator includes public model methods with no parameters that return an Eloquent relationship type. Use --without-relationships to skip relationship properties:

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

Use --relationships to generate only selected relationships:

shell
php artisan make:expressive User \
    --model="App\Models\User" \
    --relationships="posts,address"

The command fails if a requested relationship does not exist on the model.

Hidden attributes

Hidden model attributes are generated by default. This keeps the generated Expressive class aligned with the model's shape while serialization still respects the model's hidden rules.

Use --exclude-hidden to skip hidden attributes:

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

Use --include-hidden to include hidden attributes when the generator default excludes them:

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

Morph map hints

MorphTo relationships are generated with a broad PHPDoc type because the related model is resolved at runtime:

php
/** @var Expressive<Model>|null */
#[Relationship]
public ?Expressive $imageable = null;

Use --hint-morph-map when your application has a morph map and you want the generator to add confident related Expressive classes to the PHPDoc:

shell
php artisan make:expressive Image --model="App\Models\Image" --hint-morph-map

The generator only adds a mapped model when it can find a matching inverse morph relationship.

Dry runs and overwrites

Use --dry-run to print the generated class without writing a file:

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

The command refuses to overwrite an existing class unless --force is passed:

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

Generated types

The generator uses Eloquent casts before falling back to column metadata. It understands common Laravel casts such as booleans, integers, floats, decimals, dates, datetimes, arrays, JSON, collections, enums, encrypted values, AsArrayObject, AsCollection, AsEnumArrayObject, AsEnumCollection, AsFluent, AsStringable, and AsUri.

Custom casts may generate a concrete type when the cast implements CastsAttributes with an analyzable @implements CastsAttributes<Inbound, Outbound> annotation. Otherwise, the generator falls back to mixed.

Customizing the stub

Publish the generator stub when you need to change the generated class template:

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

Expressive reads stubs/expressive.stub when it exists. If the file is not published, the command uses the bundled stub.