Generating Expressive classes
- Introduction
- Generating a class
- Choosing the target class
- Selecting attributes
- Selecting relationships
- Hidden attributes
- Morph map hints
- Dry runs and overwrites
- Generated types
- Customizing the stub
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:
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:
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:
php artisan make:expressive User --model="App\Models\User" --without-attributesUse --attributes to generate only selected attributes:
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:
php artisan make:expressive User --model="App\Models\User" --without-relationshipsUse --relationships to generate only selected relationships:
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:
php artisan make:expressive User --model="App\Models\User" --exclude-hiddenUse --include-hidden to include hidden attributes when the generator default excludes them:
php artisan make:expressive User --model="App\Models\User" --include-hiddenMorph map hints
MorphTo relationships are generated with a broad PHPDoc type because the related model is resolved at runtime:
/** @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:
php artisan make:expressive Image --model="App\Models\Image" --hint-morph-mapThe 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:
php artisan make:expressive User --model="App\Models\User" --dry-runThe command refuses to overwrite an existing class unless --force is passed:
php artisan make:expressive User --model="App\Models\User" --forceGenerated 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:
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.