Models & Relationships
LaravelNow we'll set up all our Eloquent models with their relationships, accessors, mutators, and scopes. Good models make everything else much easier.
Post Model
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Str;
class Post extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'user_id', 'category_id', 'title', 'slug',
'excerpt', 'body', 'image', 'published', 'published_at'
];
protected $casts = [
'published' => 'boolean',
'published_at' => 'datetime',
];
// ---- RELATIONSHIPS ----
public function user()
{
return $this->belongsTo(User::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function tags()
{
return $this->belongsToMany(Tag::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function approvedComments()
{
return $this->hasMany(Comment::class)->where('approved', true);
}
// ---- SCOPES ----
// Post::published()->get()
public function scopePublished($query)
{
return $query->where('published', true)
->whereNotNull('published_at')
->where('published_at', '<=', now());
}
// Post::latest()->get() — already built in Laravel
// Post::popular()->get()
public function scopePopular($query)
{
return $query->orderBy('views', 'desc');
}
// Post::inCategory('laravel')->get()
public function scopeInCategory($query, $slug)
{
return $query->whereHas('category', fn($q) => $q->where('slug', $slug));
}
// ---- ACCESSORS ----
// $post->excerpt — auto-generate if empty
public function getExcerptAttribute($value)
{
return $value ?: Str::limit(strip_tags($this->body), 200);
}
// $post->reading_time — calculated
public function getReadingTimeAttribute()
{
$words = str_word_count(strip_tags($this->body));
$minutes = ceil($words / 200); // avg reading speed
return $minutes . ' min read';
}
// ---- MUTATORS ----
// Auto-generate slug when title is set
public function setTitleAttribute($value)
{
$this->attributes['title'] = $value;
if (empty($this->attributes['slug'])) {
$this->attributes['slug'] = Str::slug($value);
}
}
}Category Model
app/Models/Category.php
<?php
class Category extends Model
{
use HasFactory;
protected $fillable = ['name', 'slug', 'description', 'color'];
public function posts()
{
return $this->hasMany(Post::class);
}
public function publishedPosts()
{
return $this->hasMany(Post::class)->published();
}
// Count posts in category
public function getPostCountAttribute()
{
return $this->publishedPosts()->count();
}
}Tag Model
app/Models/Tag.php
<?php
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name', 'slug'];
public function posts()
{
return $this->belongsToMany(Post::class);
}
}Comment Model
app/Models/Comment.php
<?php
class Comment extends Model
{
use HasFactory;
protected $fillable = [
'post_id', 'user_id', 'author_name',
'author_email', 'body', 'approved'
];
protected $casts = ['approved' => 'boolean'];
public function post()
{
return $this->belongsTo(Post::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
// Get display name (user or guest)
public function getDisplayNameAttribute()
{
return $this->user?->name ?? $this->author_name ?? 'Anonymous';
}
// Scope for approved comments only
public function scopeApproved($query)
{
return $query->where('approved', true);
}
}Testing Relationships in Tinker
Terminal — php artisan tinker
# Open Laravel Tinker (interactive PHP console)
php artisan tinker
# Test your models
$post = Post::with(['user', 'category', 'tags'])->first();
$post->title;
$post->user->name;
$post->category->name;
$post->tags->pluck('name');
$post->reading_time;
$post->excerpt;
# Query with scopes
Post::published()->count();
Post::popular()->take(5)->get();
Post::inCategory('laravel')->get();💡
Use Tinker constantly!
php artisan tinker is your best friend for testing queries and relationships without writing a full controller. Just like you test APIs in Postman, use Tinker for database queries.Stuck? Need help?
Review the previous lessons or check the Laravel documentation.