Relationships
In addition to fields, CRUD Templates for Laravel also supports relationships. When you define a relationship field, the package automatically creates the necessary migration columns, relationship methods, and validation rules.
Relationships are declared along with fields, like below:
php artisan crud:generate Post \
--fields="title:string,content:text,published:boolean,category:belongsTo,author:belongsTo,tags:belongsToMany,comments:morphMany"Related Models Must Exist
When generating relationships, the related models must already exist in the app/Models directory. For example, if you're creating a Post model with a category:belongsTo relationship, the Category model must be created first.
Relationship Types
belongsTo
Creates a many-to-one relationship. The current model belongs to another model.
Syntax:
--fields="category:belongsTo"Migration:
$table->foreignId('category_id')->constrained();This creates:
- A
category_idcolumn - A foreign key constraint to the
categoriestable (note: the categories table must already exist)
Model Relationship:
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}Validation:
'category_id' => ['required', 'exists:categories,id']Example:
php artisan crud:generate Post --fields="title:string,category:belongsTo"Naming Convention
The field name determines the related model. A field named category will relate to the Category model and create a category_id column.
hasMany
Creates a one-to-many relationship. The current model has many of another model.
Syntax:
--fields="posts:hasMany"Migration: No migration column is created (the foreign key is on the related model).
Model Relationship:
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}Example:
php artisan crud:generate Category --fields="name:string,posts:hasMany"belongsToMany
Creates a many-to-many relationship with a pivot table.
Syntax:
--fields="tags:belongsToMany"Migration: No migration column is created (requires a separate pivot table).
Model Relationship:
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}Example:
php artisan crud:generate Post --fields="title:string,content:text,tags:belongsToMany"Pivot Table
You'll need to manually create the pivot table migration (e.g., post_tag). Follow Laravel's naming conventions: alphabetically ordered, singular model names.
morphTo
Creates a polymorphic relationship where the current model can belong to multiple other models.
Syntax:
--fields="commentable:morphTo"Migration:
$table->morphs('commentable');This creates:
commentable_typecolumn (string)commentable_idcolumn (unsignedBigInteger)
Model Relationship:
public function commentable(): MorphTo
{
return $this->morphTo();
}Example:
php artisan crud:generate Comment --fields="body:text,commentable:morphTo"morphMany
Creates a one-to-many polymorphic relationship where the current model has many of a polymorphic model.
Syntax:
--fields="comments:morphMany"Migration: No migration column is created.
Model Relationship:
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}Example:
php artisan crud:generate Post --fields="title:string,content:text,comments:morphMany"morphToMany
Creates a many-to-many polymorphic relationship.
Syntax:
--fields="tags:morphToMany"Migration: No migration column is created.
Model Relationship:
public function tags(): MorphToMany
{
return $this->morphToMany(Tag::class, 'taggable');
}Example:
php artisan crud:generate Post --fields="title:string,tags:morphToMany"Custom Model Paths
By default, relationship field names determine the related model (e.g., category relates to Category model). You can specify a custom model with namespace depth using a third parameter:
Syntax:
fieldName:relationshipType:Namespace/ModelNameThe forward slash (/) separates namespace segments and maps to App\Models\Namespace\ModelName.
Supported relationship types:
belongsTohasManybelongsToManymorphManymorphToMany
Examples:
# Using default naming (field name determines model)
--fields="category:belongsTo" # → App\Models\Category
# Using custom model path
--fields="category:belongsTo:Content/PostCategory" # → App\Models\Content\PostCategory
# Multiple relationships with custom paths
php artisan crud:generate Post \
--fields="category:belongsTo:Content/PostCategory,author:belongsTo:Users/Author,tags:belongsToMany:Taxonomy/Tag"Real-world example:
php artisan crud:generate Article \
--fields="title:string,content:text,blog:belongsTo:Content/Blog,author:belongsTo:Users/Author,comments:morphMany:Social/Comment"This creates relationships to:
App\Models\Content\BlogApp\Models\Users\AuthorApp\Models\Social\Comment
Nullable Relationships
Make a relationship optional by adding ?:
php artisan crud:generate Post --fields="title:string,category?:belongsTo"This makes the foreign key nullable:
$table->foreignId('category_id')->nullable()->constrained();And updates validation:
'category_id' => ['nullable', 'exists:categories,id']API Resources with Relationships
When relationships are defined, they're automatically included in the API resource:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'category' => new CategoryResource($this->whenLoaded('category')),
'tags' => TagResource::collection($this->whenLoaded('tags')),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}Next Steps
- Learn about Generate from Schema to generate from existing database schemas
- Understand the API Template structure
- Explore Customizing Field Types to create custom relationship types