مدلها در لاراول؛ راهنمای کامل Eloquent Model
در لاراول، مدلها قلب ارتباط برنامه با دیتابیس هستند. هر Model در Eloquent معمولاً نماینده یک جدول دیتابیس است و به توسعهدهنده اجازه میدهد عملیات خواندن، ایجاد، ویرایش، حذف، تعریف رابطهها، مدیریت ویژگیها، اعتبارسنجی ساختار داده، Cast کردن مقادیر، استفاده از Scope، Factory، Observer و بسیاری قابلیتهای دیگر را بهصورت شیگرا و تمیز پیادهسازی کند. این مقاله یک راهنمای کامل، فنی و کاربردی درباره مدلها در Laravel است و برای تیمهای نرمافزاری، برنامهنویسان Backend و شرکتهایی که با لاراول محصول سازمانی توسعه میدهند آماده شده است.
برای شنیدن متن، روی «پخش صوت مقاله» بزنید.
مقدمه
در معماری برنامههای مدرن، ارتباط تمیز، قابل نگهداری و امن با دیتابیس یکی از مهمترین بخشهای توسعه نرمافزار است. در فریمورک Laravel، این مسئولیت تا حد زیادی بر عهده Eloquent ORM و بهطور مشخص Modelها قرار دارد. مدلها در لاراول فقط یک کلاس ساده برای اتصال به جدول دیتابیس نیستند؛ آنها لایهای هوشمند برای نمایش داده، تعریف قوانین دامنه، مدیریت رابطهها، کنترل دسترسی به ستونها، تبدیل نوع دادهها، اجرای Queryهای قابل استفاده مجدد و حتی مدیریت رخدادهای چرخه حیات داده محسوب میشوند.
طبق مستندات رسمی Laravel، هنگام استفاده از Eloquent، هر جدول دیتابیس معمولاً یک مدل متناظر دارد که برای تعامل با همان جدول استفاده میشود و علاوه بر خواندن رکوردها، امکان ایجاد، بهروزرسانی و حذف دادهها را نیز فراهم میکند. این تعریف نشان میدهد که Model در لاراول یک نقطه مرکزی برای کار با دادههاست، نه صرفاً یک کلاس کمکی ساده.
برای یک شرکت تولید نرمافزار، درک عمیق مدلها در لاراول اهمیت زیادی دارد؛ زیرا بخش بزرگی از کیفیت کد، توسعهپذیری، امنیت و سرعت تولید محصول به طراحی صحیح Modelها وابسته است. اگر مدلها بد طراحی شوند، پروژه در آینده با مشکلاتی مانند Queryهای تکراری، وابستگی زیاد Controllerها به دیتابیس، ضعف در تستنویسی، کاهش امنیت Mass Assignment و پیچیدگی در توسعه قابلیتهای جدید مواجه خواهد شد.
در این مقاله، بهصورت کامل و فنی بررسی میکنیم که مدلها در لاراول چه هستند، چگونه ساخته میشوند، چه تنظیماتی دارند، چطور با دیتابیس ارتباط برقرار میکنند، چگونه رابطهها را مدیریت میکنند و در پروژههای حرفهای چه Best Practiceهایی باید برای آنها رعایت شود. 🚀
مدل در لاراول چیست؟
Model در Laravel یک کلاس PHP است که معمولاً داخل مسیر app/Models قرار میگیرد و از کلاس پایه Illuminate\Database\Eloquent\Model ارثبری میکند. این کلاس نقش نماینده یک موجودیت یا Entity در سیستم را دارد. برای مثال، اگر در نرمافزار شما جدول users وجود داشته باشد، مدل User نماینده آن جدول است. اگر جدول products داشته باشید، مدل Product نماینده محصولات خواهد بود.
نمونه ساده یک مدل:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
//
}
در ظاهر، این کلاس بسیار ساده است؛ اما لاراول پشت صحنه امکانات زیادی به آن اضافه میکند. با همین مدل ساده میتوانید رکوردهای جدول را بخوانید، رکورد جدید بسازید، دادهها را ویرایش کنید، رکورد حذف کنید، رابطهها را تعریف کنید و Queryهای پیچیده بنویسید.
مثلاً:
$products = Product::where('status', 'active')->get();
$product = Product::create([
'title' => 'CRM Software',
'price' => 2500000,
]);
در اینجا Product فقط یک کلاس نیست؛ بلکه یک نقطه ورود قدرتمند به جدول مرتبط در دیتابیس است.
چرا مدلها در لاراول مهم هستند؟
مدلها باعث میشوند منطق مرتبط با دادهها از Controllerها و Routeها جدا شود. در یک پروژه حرفهای لاراول، Controller نباید پر از Queryهای خام، شرطهای پیچیده و منطق مستقیم دیتابیس باشد. این کار باعث کثیف شدن کد، سخت شدن تستنویسی و کاهش قابلیت نگهداری پروژه میشود.
مدلها مزایای مهمی دارند:
- افزایش خوانایی کد
بهجای نوشتن Queryهای خام، از متدهای شیگرا و خوانا استفاده میکنید. - کاهش تکرار کد
Queryهای پرکاربرد را میتوان در Scopeها یا متدهای مدل قرار داد. - مدیریت بهتر روابط دیتابیس
روابطی مانند یکبهیک، یکبهچند، چندبهچند و Polymorphic بهصورت مستقیم در مدلها تعریف میشوند. - افزایش امنیت
با تنظیم $fillable یا $guarded میتوان از آسیبپذیریهای مربوط به Mass Assignment جلوگیری کرد. - تستپذیری بهتر
مدلها با Factory، Seeder و تستهای Feature و Unit بهتر هماهنگ میشوند. - هماهنگی با معماری تمیزتر
Modelها در کنار Serviceها، Repositoryها، Policyها و Resourceها میتوانند یک ساختار حرفهای برای پروژههای سازمانی ایجاد کنند.
ساخت مدل در لاراول
برای ساخت مدل در Laravel میتوان از Artisan استفاده کرد:
php artisan make:model Product
این دستور یک فایل به نام Product.php در مسیر app/Models ایجاد میکند.
اگر بخواهید همزمان Migration هم ساخته شود:
php artisan make:model Product -m
اگر بخواهید Model، Migration، Factory، Seeder و Controller را یکجا بسازید:
php artisan make:model Product -mfsc
در پروژههای واقعی، بهتر است هنگام ایجاد مدل، ساختارهای موردنیاز آن مانند Migration و Factory هم از ابتدا طراحی شوند؛ زیرا Model بدون ساختار دیتابیس و داده تستی، در فرآیند توسعه و تست ارزش کمتری دارد.
نامگذاری مدلها و جدولها در لاراول
لاراول بر اساس Convention کار میکند. یعنی اگر از الگوهای نامگذاری استاندارد استفاده کنید، نیاز به تنظیمات اضافی ندارید.
بهصورت پیشفرض:
| نام مدل | نام جدول پیشفرض |
|---|---|
| User | users |
| Product | products |
| Order | orders |
| Category | categories |
| BlogPost | blog_posts |
لاراول معمولاً نام مدل را به حالت جمع و snake_case تبدیل میکند و آن را بهعنوان نام جدول در نظر میگیرد. اگر نام جدول شما متفاوت باشد، میتوانید آن را در مدل مشخص کنید:
class Product extends Model
{
protected $table = 'shop_products';
}
این قابلیت در پروژههایی کاربرد دارد که دیتابیس قدیمی دارند یا نامگذاری جدولها بر اساس استاندارد لاراول انجام نشده است.
کلید اصلی در مدلها
بهصورت پیشفرض، لاراول فرض میکند کلید اصلی جدول id است. اگر جدول شما از کلید دیگری استفاده میکند، میتوانید مقدار $primaryKey را تغییر دهید:
class Product extends Model
{
protected $primaryKey = 'product_id';
}
اگر کلید اصلی شما Auto Increment نیست:
public $incrementing = false;
اگر نوع کلید اصلی رشتهای است:
protected $keyType = 'string';
این تنظیمات مخصوصاً در پروژههایی مهم هستند که از UUID، ULID یا ساختارهای دیتابیس Legacy استفاده میکنند.
Timestamp در مدلها
لاراول بهصورت پیشفرض انتظار دارد هر جدول دارای دو ستون زیر باشد:
created_at
updated_at
این ستونها بهصورت خودکار هنگام ایجاد و بهروزرسانی رکورد مدیریت میشوند. اگر جدول شما این ستونها را ندارد، میتوانید قابلیت Timestamp را غیرفعال کنید:
public $timestamps = false;
یا اگر نام ستونها متفاوت است:
const CREATED_AT = 'created_date';
const UPDATED_AT = 'modified_date';
در پروژههای شرکتی، نگهداری created_at و updated_at بسیار مهم است؛ چون برای گزارشگیری، Audit، تحلیل رفتار کاربران و بررسی خطاها کاربرد دارد.
Mass Assignment و اهمیت $fillable
یکی از مهمترین مباحث امنیتی در مدلهای لاراول، Mass Assignment است. Mass Assignment زمانی رخ میدهد که شما یک آرایه از دادهها را مستقیم به Model ارسال میکنید:
Product::create($request->all());
این روش اگر کنترل نشده باشد، میتواند خطرناک باشد؛ زیرا ممکن است کاربر فیلدهایی را ارسال کند که نباید اجازه تغییر آنها را داشته باشد؛ مثلاً is_admin، user_id یا status.
برای کنترل این موضوع از $fillable استفاده میشود:
class Product extends Model
{
protected $fillable = [
'title',
'description',
'price',
'status',
];
}
با این کار فقط فیلدهای مشخصشده قابل مقداردهی گروهی هستند.
روش دیگر استفاده از $guarded است:
protected $guarded = ['id'];
در پروژههای حرفهای بهتر است با دقت تصمیم بگیرید که از $fillable یا $guarded استفاده کنید. برای تیمهایی که امنیت و کنترل دقیق برایشان مهم است، $fillable معمولاً گزینه شفافتری است، زیرا دقیقاً مشخص میکند چه فیلدهایی مجاز هستند.
عملیات CRUD با مدلها در لاراول
مدلها در لاراول عملیات اصلی دیتابیس را بسیار ساده میکنند.
ایجاد رکورد
$product = Product::create([
'title' => 'Accounting Software',
'price' => 5000000,
'status' => 'active',
]);
یا:
$product = new Product();
$product->title = 'CRM Software';
$product->price = 7500000;
$product->status = 'active';
$product->save();
خواندن رکوردها
$products = Product::all();
$product = Product::find(1);
$product = Product::where('status', 'active')->first();
ویرایش رکورد
$product = Product::findOrFail(1);
$product->update([
'price' => 8000000,
]);
حذف رکورد
$product = Product::findOrFail(1);
$product->delete();
این ساختار ساده باعث میشود کدهای مربوط به دیتابیس خوانا، کوتاه و قابل نگهداری باشند.
Query Builder در Eloquent Model
مدلهای Eloquent فقط برای عملیات ساده نیستند. شما میتوانید Queryهای پیچیدهتری هم بنویسید:
$products = Product::where('status', 'active')
->where('price', '>', 1000000)
->orderBy('created_at', 'desc')
->limit(10)
->get();
یا:
$products = Product::whereBetween('price', [1000000, 5000000])->get();
یا:
$products = Product::whereIn('status', ['active', 'pending'])->get();
در مستندات رسمی Laravel، Eloquent بهعنوان ORM لاراول معرفی شده که تعامل با دیتابیس را لذتبخشتر و شیگراتر میکند و هر جدول را از طریق یک مدل مرتبط مدیریت میکند.
روابط در مدلهای لاراول
یکی از قدرتمندترین قابلیتهای Modelها در Laravel، تعریف Relationship است. در دیتابیسهای واقعی، جدولها مستقل از هم نیستند. کاربر سفارش دارد، سفارش آیتم دارد، محصول دستهبندی دارد، مقاله نویسنده دارد و نقشها به کاربران متصل هستند.
در لاراول، رابطهها بهعنوان متد در مدل تعریف میشوند. طبق مستندات رسمی Laravel، رابطههای Eloquent بهصورت متدهایی روی کلاسهای مدل تعریف میشوند و خود رابطهها نیز مانند Query Builder عمل میکنند؛ بنابراین میتوان روی آنها شرط و زنجیره Query اعمال کرد.
رابطه یکبهیک؛ hasOne
مثال: هر کاربر یک پروفایل دارد.
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
استفاده:
$user = User::find(1);
$profile = $user->profile;
رابطه یکبهچند؛ hasMany
مثال: هر کاربر چند سفارش دارد.
class User extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
}
استفاده:
$orders = User::find(1)->orders;
رابطه معکوس؛ belongsTo
مثال: هر سفارش متعلق به یک کاربر است.
class Order extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
رابطه چندبهچند؛ belongsToMany
مثال: هر کاربر چند نقش دارد و هر نقش میتواند به چند کاربر متصل باشد.
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
در این حالت معمولاً یک جدول واسط مانند role_user وجود دارد.
رابطه Polymorphic
در پروژههای پیشرفته، گاهی یک مدل باید به چند مدل مختلف متصل شود. مثلاً سیستم کامنت ممکن است برای مقاله، محصول و ویدئو استفاده شود. در این حالت، رابطه Polymorphic کاربرد دارد.
class Comment extends Model
{
public function commentable()
{
return $this->morphTo();
}
}
این نوع رابطه در سیستمهای محتوایی، فروشگاهی، تیکتینگ و نرمافزارهای سازمانی بسیار کاربردی است.
Eager Loading و مشکل N+1 Query
یکی از خطاهای رایج در استفاده از Modelها، ایجاد مشکل N+1 Query است. فرض کنید لیست سفارشها را دریافت میکنید و برای هر سفارش، نام کاربر را نمایش میدهید:
$orders = Order::all();
foreach ($orders as $order) {
echo $order->user->name;
}
اگر 100 سفارش داشته باشید، ممکن است یک Query برای سفارشها و 100 Query برای کاربران اجرا شود. این یعنی کاهش شدید Performance.
راهحل استفاده از Eager Loading است:
$orders = Order::with('user')->get();
یا برای چند رابطه:
$orders = Order::with(['user', 'items.product'])->get();
در پروژههای شرکتی که تعداد رکوردها بالاست، رعایت Eager Loading بسیار مهم است. استفاده نادرست از رابطهها میتواند باعث کندی صفحات، افزایش فشار روی دیتابیس و نارضایتی کاربران شود.
Accessor و Mutator در مدلها
گاهی لازم است هنگام خواندن یا ذخیره داده، مقدار یک فیلد تغییر کند. در لاراول این کار با Accessor و Mutator انجام میشود.
طبق مستندات رسمی Laravel، Accessor، Mutator و Attribute Casting امکان تغییر مقدار ویژگیها را هنگام دریافت یا تنظیم آنها روی Model فراهم میکنند؛ برای مثال تبدیل مقدار JSON به آرایه یا رمزنگاری و رمزگشایی مقدارها.
Accessor چیست؟
Accessor هنگام خواندن مقدار اجرا میشود.
use Illuminate\Database\Eloquent\Casts\Attribute;
class User extends Model
{
protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => "{$this->first_name} {$this->last_name}",
);
}
}
استفاده:
echo $user->full_name;
Mutator چیست؟
Mutator هنگام ذخیره یا تنظیم مقدار اجرا میشود.
protected function email(): Attribute
{
return Attribute::make(
set: fn ($value) => strtolower($value),
);
}
در این مثال، ایمیل قبل از ذخیره به حروف کوچک تبدیل میشود.
Accessor و Mutator برای تمیز نگه داشتن کد بسیار مفید هستند، اما نباید منطق سنگین تجاری داخل آنها قرار دهید. این بخش باید بیشتر برای تبدیل داده، فرمتدهی و نرمالسازی مقدارها استفاده شود.
Cast در مدلهای لاراول
گاهی مقدار ذخیرهشده در دیتابیس با نوع دادهای که در برنامه نیاز داریم متفاوت است. مثلاً مقدار is_active در دیتابیس عددی است، اما در برنامه بهتر است Boolean باشد. یا مقدار settings بهصورت JSON ذخیره شده، اما در کد باید آرایه باشد.
نمونه Cast:
class Product extends Model
{
protected function casts(): array
{
return [
'is_active' => 'boolean',
'price' => 'integer',
'published_at' => 'datetime',
'settings' => 'array',
];
}
}
مزیت Cast این است که دیگر لازم نیست در بخشهای مختلف پروژه، نوع داده را دستی تبدیل کنید. Model خودش مسئول تبدیل مقدار خواهد بود.
انواع رایج Cast:
| نوع Cast | کاربرد |
|---|---|
| boolean | تبدیل مقدار به true یا false |
| integer | تبدیل مقدار به عدد صحیح |
| float | تبدیل مقدار به عدد اعشاری |
| array | تبدیل JSON به آرایه |
| object | تبدیل JSON به Object |
| datetime | تبدیل مقدار تاریخ به Carbon |
| encrypted | ذخیره مقدار بهصورت رمزنگاریشده |
در پروژههای سازمانی، Castها باعث کاهش خطاهای نوع داده و تمیزتر شدن منطق برنامه میشوند.
Scope در مدلهای لاراول
Scopeها برای تعریف Queryهای قابل استفاده مجدد به کار میروند. فرض کنید در بخشهای مختلف پروژه نیاز دارید فقط محصولات فعال را دریافت کنید. بهجای تکرار شرط where('status', 'active') میتوانید یک Scope تعریف کنید.
class Product extends Model
{
public function scopeActive($query)
{
return $query->where('status', 'active');
}
}
استفاده:
$products = Product::active()->get();
Scopeها دو نوع کلی دارند:
Local Scope
همان Scopeهایی هستند که داخل مدل تعریف میشوند و با نام مشخص فراخوانی میشوند.
Product::active()->latest()->get();
Global Scope
Global Scope بهصورت خودکار روی تمام Queryهای مدل اعمال میشود. مثلاً اگر همیشه فقط رکوردهای مربوط به شرکت فعلی نمایش داده شوند، میتوان Global Scope تعریف کرد.
البته در استفاده از Global Scope باید دقت کرد؛ چون ممکن است باعث شود بعضی Queryها دادههای مورد انتظار را برنگردانند. در پروژههای چندمستاجری یا Multi-Tenant، Global Scope بسیار کاربردی اما حساس است.
Soft Delete در مدلها
در بسیاری از سیستمهای شرکتی، حذف واقعی داده از دیتابیس کار درستی نیست. ممکن است بعداً برای گزارش، بازیابی، بررسی خطا یا مسائل حقوقی به داده حذفشده نیاز داشته باشیم. در لاراول، قابلیت Soft Delete باعث میشود رکورد واقعاً حذف نشود، بلکه مقدار ستون deleted_at پر شود.
برای فعالسازی:
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes;
}
Migration:
$table->softDeletes();
حذف:
$product->delete();
بازیابی:
Product::withTrashed()->find(1)->restore();
دریافت فقط رکوردهای حذفشده:
Product::onlyTrashed()->get();
Soft Delete در نرمافزارهای مالی، CRM، ERP، فروشگاهی و سامانههای سازمانی بسیار مهم است؛ زیرا حذف کامل دادهها میتواند مشکلات جدی ایجاد کند.
Model Factory در لاراول
Factoryها برای تولید داده تستی و Seed کردن دیتابیس استفاده میشوند. در مستندات رسمی Laravel آمده است که هنگام تست یا Seed کردن دیتابیس، میتوان بهجای تعیین دستی مقدار هر ستون، مجموعهای از ویژگیهای پیشفرض برای مدلها تعریف کرد.
ساخت Factory:
php artisan make:factory ProductFactory --model=Product
نمونه Factory:
class ProductFactory extends Factory
{
public function definition(): array
{
return [
'title' => fake()->sentence(3),
'price' => fake()->numberBetween(100000, 5000000),
'status' => 'active',
];
}
}
استفاده:
Product::factory()->count(50)->create();
Factoryها برای تستنویسی حرفهای ضروری هستند. تیمهایی که میخواهند محصول پایدار و قابل توسعه بسازند، باید از همان ابتدا Factoryها را کنار Modelها طراحی کنند.
Observer و رویدادهای مدل
Modelها در لاراول در طول چرخه حیات خود رویدادهای مختلفی دارند؛ مثلاً هنگام ایجاد، ذخیره، بهروزرسانی یا حذف. با Observer میتوان به این رویدادها واکنش نشان داد.
ساخت Observer:
php artisan make:observer ProductObserver --model=Product
نمونه:
class ProductObserver
{
public function created(Product $product): void
{
// Send notification or clear cache
}
public function updated(Product $product): void
{
// Log changes
}
}
Observer برای کارهایی مثل ثبت لاگ، پاک کردن Cache، ارسال اعلان، ایجاد Activity Log یا اجرای کارهای جانبی بسیار مناسب است. البته نباید منطق پیچیده و سنگین مستقیماً داخل Observer قرار گیرد؛ بهتر است از Service Class یا Job استفاده شود.
تفاوت Model با Migration، Controller و Resource
درک مرز مسئولیتها در لاراول بسیار مهم است.
| بخش | مسئولیت اصلی |
|---|---|
| Model | نمایش Entity، ارتباط با دیتابیس، رابطهها، Scopeها، Castها |
| Migration | تعریف ساختار جدول و تغییرات Schema |
| Controller | دریافت Request، فراخوانی منطق برنامه، بازگرداندن Response |
| Resource | تبدیل داده مدل به خروجی API |
| Factory | تولید داده تستی برای مدل |
| Seeder | وارد کردن داده اولیه یا نمونه |
| Observer | واکنش به رخدادهای مدل |
| Policy | کنترل مجوزهای دسترسی به مدل |
اشتباه رایج این است که همه منطقها داخل Model قرار داده شوند. Model نباید به یک کلاس بسیار بزرگ و غیرقابل مدیریت تبدیل شود. در پروژههای بزرگ، بهتر است منطق تجاری پیچیده به Serviceها، Actionها یا Domain Classها منتقل شود.
بهترین روشها برای طراحی مدل در لاراول
1. مدل را بیش از حد سنگین نکنید
Model باید منطق مرتبط با داده و Entity را نگه دارد، اما نباید همه چیز را در خود جای دهد. اگر متدهای مدل زیاد و پیچیده شدند، احتمالاً باید بخشی از منطق به Service یا Action منتقل شود.
2. از $fillable با دقت استفاده کنید
هیچوقت بدون فکر از این ساختار استفاده نکنید:
protected $guarded = [];
این کار ممکن است در پروژههای کوچک سریع باشد، اما در نرمافزارهای شرکتی میتواند خطر امنیتی ایجاد کند.
3. رابطهها را واضح نامگذاری کنید
نام رابطه باید مفهوم تجاری را منتقل کند:
public function orders()
public function invoices()
public function activeSubscriptions()
نامهای مبهم باعث سخت شدن توسعه در تیم میشوند.
4. از Eager Loading استفاده کنید
برای جلوگیری از N+1 Query، رابطههای لازم را با with دریافت کنید.
Order::with(['user', 'items.product'])->get();
5. Queryهای پرتکرار را به Scope تبدیل کنید
بهجای تکرار شرطها در Controller:
Product::where('status', 'active')->where('stock', '>', 0)->get();
از Scope استفاده کنید:
Product::available()->get();
6. Castها را فراموش نکنید
اگر فیلدی Boolean، JSON، تاریخ یا عددی است، Cast مناسب برای آن تعریف کنید. این کار از خطاهای پنهان جلوگیری میکند.
7. برای تست از Factory استفاده کنید
مدل بدون Factory در پروژه حرفهای ناقص است. Factory باعث میشود تستها سریعتر، تمیزتر و قابل اطمینانتر نوشته شوند.
8. حذف دادههای مهم را Soft Delete کنید
برای دادههای حساس، مالی، سفارشها، کاربران، مشتریان و اسناد، حذف فیزیکی معمولاً انتخاب مناسبی نیست.
9. از نامگذاری استاندارد لاراول پیروی کنید
تا حد امکان نام مدلها، جدولها، کلیدها و رابطهها را مطابق Conventionهای لاراول انتخاب کنید. این کار کد را سادهتر و قابل فهمتر میکند.
10. منطق گزارشگیری سنگین را داخل Model نگذارید
برای Queryهای تحلیلی، گزارشهای پیچیده و پردازشهای سنگین، بهتر است از Query Object، Service، Repository یا حتی Viewهای دیتابیس استفاده شود.
مثال کاربردی: مدل Product در یک پروژه شرکتی
فرض کنید یک شرکت تولید نرمافزار، سیستم فروش آنلاین محصولات نرمافزاری دارد. مدل Product میتواند به شکل زیر طراحی شود:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Product extends Model
{
use SoftDeletes;
protected $fillable = [
'title',
'slug',
'description',
'price',
'status',
'settings',
'published_at',
];
protected function casts(): array
{
return [
'price' => 'integer',
'settings' => 'array',
'published_at' => 'datetime',
];
}
protected function title(): Attribute
{
return Attribute::make(
set: fn ($value) => trim($value),
);
}
public function scopeActive($query)
{
return $query->where('status', 'active');
}
public function scopePublished($query)
{
return $query->whereNotNull('published_at');
}
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
در این مدل چند اصل مهم رعایت شده است:
- فیلدهای مجاز با $fillable مشخص شدهاند.
- نوع دادهها با casts کنترل شدهاند.
- مقدار title قبل از ذخیره Trim میشود.
- Scopeهای active و published برای Queryهای پرتکرار تعریف شدهاند.
- رابطه محصول با دستهبندیها مشخص شده است.
- قابلیت Soft Delete فعال شده است.
این مدل برای یک پروژه واقعی بسیار قابل نگهداریتر از مدلی است که همه Queryها و منطقها در Controller نوشته شده باشند.
خطاهای رایج در کار با مدلهای لاراول
استفاده مستقیم از $request->all()
Product::create($request->all());
این روش میتواند خطرناک باشد. بهتر است دادهها اعتبارسنجی شوند:
$data = $request->validate([
'title' => ['required', 'string', 'max:255'],
'price' => ['required', 'integer'],
]);
Product::create($data);
فراموش کردن Eager Loading
اگر در یک حلقه به رابطهها دسترسی دارید، احتمال N+1 Query وجود دارد.
قرار دادن منطق زیاد در Model
Model نباید به یک فایل چند هزار خطی تبدیل شود. این نشانه ضعف معماری است.
تعریف نکردن Cast
اگر فیلدهای JSON، Boolean یا Date را Cast نکنید، در بخشهای مختلف پروژه مجبور به تبدیل دستی مقدارها میشوید.
استفاده نادرست از Global Scope
Global Scope اگر درست مستند و کنترل نشود، ممکن است باعث شود توسعهدهندگان دادههای مورد انتظار را نبینند و زمان زیادی برای Debug صرف شود.
مدلها در معماری حرفهای لاراول
در پروژههای کوچک، استفاده مستقیم از Model داخل Controller ممکن است قابل قبول باشد. اما در پروژههای متوسط و بزرگ، بهتر است Model بخشی از یک معماری تمیزتر باشد.
یک ساختار حرفهای میتواند شامل این بخشها باشد:
app/
Models/
Services/
Actions/
Policies/
Observers/
Http/
Controllers/
Resources/
Requests/
در این معماری:
- Model مسئول داده و رابطههاست.
- Form Request مسئول اعتبارسنجی است.
- Service مسئول منطق تجاری است.
- Policy مسئول مجوزهاست.
- Resource مسئول خروجی API است.
- Observer مسئول واکنش به رویدادهاست.
- Controller نقش هماهنگکننده دارد.
این تفکیک مسئولیتها باعث میشود پروژه در طول زمان قابل توسعه، قابل تست و قابل نگهداری بماند.
جدول مقایسه قابلیتهای مهم مدل در لاراول
| قابلیت | هدف | کاربرد در پروژه واقعی | نکته مهم |
|---|---|---|---|
| $fillable | کنترل Mass Assignment | جلوگیری از تغییر فیلدهای غیرمجاز | برای امنیت بسیار مهم است |
| $table | تعیین نام جدول | دیتابیس Legacy یا نام سفارشی | فقط در صورت نیاز استفاده شود |
| $primaryKey | تعیین کلید اصلی | جدولهایی با کلید غیر از id | برای UUID هم تنظیمات دیگر لازم است |
| casts() | تبدیل نوع داده | Boolean، JSON، Date، Integer | کد را تمیز و امنتر میکند |
| Relationship | تعریف ارتباط مدلها | سفارشها، کاربران، نقشها | پایه طراحی دیتابیس رابطهای |
| Scope | Query قابل استفاده مجدد | فیلتر فعال، منتشرشده، قابل فروش | از تکرار شرطها جلوگیری میکند |
| SoftDeletes | حذف نرم | حفظ دادههای مهم | نیازمند ستون deleted_at است |
| Factory | تولید داده تستی | تست و Seeder | برای تستنویسی ضروری است |
| Observer | واکنش به رویداد مدل | لاگ، اعلان، Cache | منطق سنگین را به Job/Service منتقل کنید |
| Accessor/Mutator | تغییر مقدار هنگام خواندن/نوشتن | فرمت نام، نرمالسازی ایمیل | برای منطق ساده مناسب است |
نکات سئو و محتوایی برای استفاده از مدلها در سایتهای لاراولی
اگر با Laravel یک وبسایت شرکتی، فروشگاهی یا محتوایی توسعه میدهید، Modelها میتوانند نقش مهمی در SEO هم داشته باشند. برای مثال:
- مدل Post میتواند فیلدهای meta_title، meta_description و canonical_url داشته باشد.
- مدل Product میتواند slug یکتا و خوانا داشته باشد.
- مدل Category میتواند ساختار URL قابل فهم ایجاد کند.
- Scopeها میتوانند فقط محتوای منتشرشده و قابل ایندکس را برگردانند.
- Castها میتوانند دادههای ساختاریافته مثل Schema Markup را به آرایه تبدیل کنند.
نمونه:
class Post extends Model
{
protected $fillable = [
'title',
'slug',
'body',
'meta_title',
'meta_description',
'published_at',
];
protected function casts(): array
{
return [
'published_at' => 'datetime',
];
}
public function scopePublished($query)
{
return $query->whereNotNull('published_at')
->where('published_at', '<=', now());
}
}
این طراحی باعث میشود فقط مقالات منتشرشده در خروجی سایت نمایش داده شوند و محتوای پیشنویس یا زمانبندیشده به اشتباه ایندکس نشود.
FAQ؛ سوالات متداول درباره مدلها در لاراول
1. مدل در لاراول چه کاربردی دارد؟
مدل در لاراول نماینده یک جدول دیتابیس یا یک Entity در سیستم است. با استفاده از Model میتوان دادهها را خواند، ایجاد کرد، ویرایش کرد، حذف کرد، رابطهها را تعریف کرد و Queryهای قابل استفاده مجدد ساخت.
2. تفاوت Model و Migration چیست؟
Migration ساختار جدول دیتابیس را تعریف میکند، اما Model برای تعامل با دادههای همان جدول استفاده میشود. Migration میگوید جدول چه ستونهایی دارد؛ Model میگوید برنامه چگونه با دادههای آن جدول کار کند.
3. آیا هر جدول باید یک مدل داشته باشد؟
معمولاً برای هر جدول اصلی که در منطق برنامه استفاده میشود، یک مدل ساخته میشود. اما برای جدولهای واسط ساده، مانند جدول Pivot در رابطه چندبهچند، همیشه نیاز به مدل جداگانه نیست؛ مگر اینکه جدول واسط خودش منطق یا فیلدهای مهم داشته باشد.
4. $fillable بهتر است یا $guarded؟
برای پروژههای حساس و شرکتی، $fillable معمولاً شفافتر و امنتر است؛ چون دقیقاً مشخص میکند چه فیلدهایی اجازه Mass Assignment دارند. $guarded هم کاربرد دارد، اما باید با دقت استفاده شود.
5. رابطهها در مدل لاراول کجا تعریف میشوند؟
رابطهها بهصورت متد داخل کلاس Model تعریف میشوند. برای مثال، رابطه کاربر با سفارشها معمولاً داخل مدل User با متد orders() تعریف میشود.
6. Scope در مدل چه کاربردی دارد؟
Scope برای تعریف Queryهای پرتکرار استفاده میشود. مثلاً بهجای تکرار شرط فعال بودن محصول در چند جای پروژه، میتوان یک Scope به نام active ساخت و همهجا از Product::active() استفاده کرد.
7. Cast در مدل لاراول چیست؟
Cast باعث میشود مقدار یک ستون هنگام خواندن یا نوشتن به نوع داده مناسب تبدیل شود؛ مثلاً JSON به آرایه، عدد به Boolean یا تاریخ به شیء DateTime/Carbon.
8. Soft Delete چه زمانی استفاده میشود؟
وقتی نمیخواهید داده واقعاً از دیتابیس حذف شود، از Soft Delete استفاده میکنید. این قابلیت برای دادههای مهم مانند سفارشها، کاربران، فاکتورها و اسناد بسیار مناسب است.
9. آیا باید منطق تجاری را داخل Model بنویسیم؟
منطق ساده مرتبط با Entity میتواند داخل Model باشد، اما منطق پیچیده تجاری بهتر است در Service، Action یا کلاسهای جداگانه قرار گیرد. مدلهای بسیار بزرگ معمولاً نشانه معماری ضعیف هستند.
10. Factory چه ارتباطی با Model دارد؟
Factory برای تولید داده تستی مربوط به یک مدل استفاده میشود. با Factory میتوان رکوردهای نمونه ساخت و تستهای قابل اطمینانتری نوشت.
جمعبندی
مدلها در لاراول یکی از مهمترین اجزای توسعه حرفهای با این فریمورک هستند. Modelها فقط یک راه ساده برای اتصال به دیتابیس نیستند؛ بلکه بخش مرکزی مدیریت داده، رابطهها، Queryها، تبدیل نوع داده، امنیت Mass Assignment، رخدادها و تستپذیری برنامه محسوب میشوند.
اگر مدلها درست طراحی شوند، پروژه تمیزتر، امنتر، سریعتر و قابل توسعهتر خواهد بود. اما اگر همه منطقها بدون ساختار داخل Model یا Controller نوشته شوند، پروژه بهمرور پیچیده، شکننده و سختنگهداری میشود.
برای تیمهای نرمافزاری و شرکتهایی که با Laravel محصول حرفهای تولید میکنند، تسلط بر Eloquent Model یک مهارت پایه و ضروری است. طراحی صحیح مدلها باعث میشود کدها خواناتر باشند، ارتباط با دیتابیس بهینهتر انجام شود، تستها سادهتر نوشته شوند و توسعه قابلیتهای جدید با ریسک کمتری انجام شود.
CTA
اگر قصد دارید یک نرمافزار تحت وب حرفهای، مقیاسپذیر و قابل توسعه با Laravel طراحی کنید، معماری صحیح مدلها یکی از اولین قدمهای موفقیت پروژه است. تیم ما میتواند در طراحی دیتابیس، پیادهسازی Eloquent Modelها، بهینهسازی Queryها، توسعه API، تستنویسی و بازطراحی پروژههای لاراولی به شما کمک کند. برای مشاوره فنی یا بررسی ساختار پروژه لاراول خود، با تیم ما تماس بگیرید و مسیر توسعه نرمافزار خود را حرفهایتر آغاز کنید. 💼
منابع رسمی
- مستندات رسمی Eloquent در Laravel 12؛ برای آشنایی با مفهوم Model، ارتباط مدل با جدول دیتابیس و عملیات اصلی روی دادهها.
- مستندات رسمی روابط Eloquent در Laravel 12؛ برای مطالعه انواع Relationship مانند hasOne، hasMany، belongsTo و belongsToMany.
- مستندات رسمی Accessor، Mutator و Casting در Laravel 12؛ برای مدیریت تبدیل مقدار ویژگیها هنگام خواندن و نوشتن داده.
- مستندات رسمی Factory در Laravel 12؛ برای تولید داده تستی، Seed کردن دیتابیس و آمادهسازی مدلها در تستها.