مدلها در لاراول؛ راهنمای کامل Eloquent Model
مدلها در لاراول یکی از مهمترین بخشهای توسعه نرمافزارهای تحت وب هستند. Eloquent Model به برنامهنویسان کمک میکند بهجای نوشتن مداوم کوئریهای خام SQL، با دیتابیس بهصورت شیءگرا، خوانا و قابل نگهداری کار کنند. در این مقاله، بهصورت کامل و فنی با Eloquent Model در Laravel آشنا میشویم؛ از ساخت Model و ارتباط آن با جدول دیتابیس گرفته تا Mass Assignment، روابط، Casting، Accessor و Mutator، Scope، رویدادهای مدل، بهینهسازی کوئریها، چالشها، بهترین روشها و مثالهای واقعی برای کسبوکارها.
برای شنیدن متن، روی «پخش صوت مقاله» بزنید.
مقدمه: چرا مدلها در لاراول برای توسعه نرمافزارهای تحت وب حیاتی هستند؟
در هر نرمافزار تحت وب، دادهها قلب سیستم هستند. اطلاعات کاربران، سفارشها، محصولات، پرداختها، فاکتورها، پیامها، تنظیمات، گزارشها و دهها موجودیت دیگر باید بهدرستی ذخیره، بازیابی، ویرایش و حذف شوند. اگر ارتباط با دیتابیس بدون ساختار مشخص انجام شود، پروژه خیلی زود پیچیده، کند، پرخطا و سختنگهدار میشود. به همین دلیل، Laravel برای کار با دیتابیس از ابزار قدرتمندی به نام Eloquent ORM استفاده میکند.
مدلها در لاراول یا همان Eloquent Modelها، لایهای شیءگرا بین کدهای برنامه و دیتابیس ایجاد میکنند. بهجای اینکه برای هر عملیات ساده، کوئری SQL بنویسیم، میتوانیم از کلاسهای Model استفاده کنیم و با دادهها مثل آبجکتهای PHP کار کنیم. این رویکرد نهتنها خوانایی کد را بیشتر میکند، بلکه توسعه نرمافزارهای تحت وب را سریعتر، استانداردتر و قابل نگهداریتر میسازد.
برای مثال، در یک سیستم فروش آنلاین، بهجای نوشتن کوئری مستقیم برای دریافت محصولات فعال، میتوانیم بنویسیم:
$products = Product::where('status', 'active')->get();
این کد ساده، خوانا و قابل فهم است. حتی برای برنامهنویسی که تازه وارد پروژه شده، مشخص است که از مدل Product محصولات فعال دریافت میشوند.
در مستندات رسمی Laravel توضیح داده شده که Eloquent یک ORM یا Object-Relational Mapper است و هر جدول دیتابیس معمولاً یک Model متناظر دارد که برای تعامل با همان جدول استفاده میشود. برای مطالعه جزئیات رسمی میتوانید به مستندات رسمی Eloquent ORM در Laravel مراجعه کنید.
در پروژههای شرکتی، مخصوصاً پروژههایی مانند CRM، ERP، سامانه فروش، پورتال مشتریان، پنل مدیریتی یا نرمافزارهای اختصاصی، طراحی درست Modelها اهمیت بسیار زیادی دارد. شرکتهایی مانند اسمارتی اپ (SmartyApp) که در زمینه طراحی سایت، تولید نرمافزار اختصاصی و برنامهنویسی نرمافزارهای تحت وب فعالیت میکنند، هنگام طراحی پروژههای Laravel باید مدلها را نه فقط بهعنوان چند کلاس ساده، بلکه بهعنوان بخشی مهم از معماری نرمافزار در نظر بگیرند.
در این مقاله، مدلها در لاراول را از پایه تا سطح حرفهای بررسی میکنیم و نشان میدهیم چطور Eloquent Model میتواند کیفیت، سرعت توسعه و نگهداری پروژههای تحت وب را افزایش دهد.
Eloquent Model در Laravel چیست؟
Eloquent Model در Laravel یک کلاس PHP است که معمولاً نماینده یک جدول در دیتابیس محسوب میشود. اگر جدولی به نام products داشته باشیم، معمولاً مدلی به نام Product برای آن ساخته میشود. اگر جدولی به نام customers داشته باشیم، مدلی به نام Customer خواهیم داشت.
به بیان ساده، Model پلی است بین دنیای شیءگرای PHP و جدولهای رابطهای دیتابیس.
نمونه یک مدل ساده:
namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { protected $fillable = [ 'name', 'price', 'stock', 'status', ]; }
در این مثال، کلاس Product به جدول products متصل میشود و به ما اجازه میدهد دادههای این جدول را با متدهای Eloquent مدیریت کنیم.
ORM چیست و چرا مهم است؟
ORM مخفف Object-Relational Mapping است. ORM ابزاری است که بین آبجکتهای برنامهنویسی و جدولهای دیتابیس ارتباط برقرار میکند. بهجای اینکه همه چیز را با SQL خام مدیریت کنیم، ORM اجازه میدهد دادهها را با کلاسها و متدها مدیریت کنیم.
مثلاً بهجای این کوئری:
SELECT * FROM products WHERE status = 'active';
در Laravel میتوان نوشت:
Product::where('status', 'active')->get();
مزیت این روش فقط کوتاهتر شدن کد نیست. مزیت اصلی آن، خوانایی، قابلیت نگهداری، قابلیت توسعه و هماهنگی بهتر با معماری شیءگراست.
جایگاه Model در معماری Laravel
Laravel معمولاً بر پایه معماری نزدیک به MVC کار میکند. در این معماری، Model مسئول دادهها و منطق مرتبط با داده است. View مسئول نمایش اطلاعات به کاربر است و Controller درخواستها را مدیریت میکند.
در چنین ساختاری، Model نباید صرفاً یک فایل خالی باشد. Model بخشی مهم از دامنه دادهای پروژه است و میتواند شامل موارد زیر باشد:
- ارتباط با جدول دیتابیس
- تعریف فیلدهای قابل ذخیرهسازی
- تعریف رابطهها بین موجودیتها
- تعریف Scope برای کوئریهای پرتکرار
- تعریف Cast برای تبدیل نوع دادهها
- تعریف Accessor و Mutator
- مدیریت رویدادهای مرتبط با داده
- تعامل با Factoryها برای تست و Seed
- کنترل نمایش یا مخفیسازی فیلدها در خروجی JSON
برای مثال، در یک سامانه مدیریت سفارش، مدل Order فقط نماینده جدول سفارشها نیست؛ بلکه میتواند روابط سفارش با مشتری، آیتمهای سفارش، پرداخت و فاکتور را نیز تعریف کند.
ساخت Model در Laravel
برای ساخت یک Model در Laravel میتوان از Artisan استفاده کرد:
php artisan make:model Product
این دستور فایلی در مسیر زیر ایجاد میکند:
app/Models/Product.php
اگر بخواهیم همزمان Migration نیز ساخته شود، میتوانیم از دستور زیر استفاده کنیم:
php artisan make:model Product -m
برای ساخت Model همراه با Migration، Factory، Seeder، Controller و Policy میتوان از گزینههای مختلف Artisan استفاده کرد. در پروژههای واقعی، این قابلیت سرعت توسعه را بالا میبرد و ساختار پروژه را منظمتر میکند.
نامگذاری Model و جدول
Laravel بهصورت پیشفرض فرض میکند نام جدول، شکل جمع نام Model است. یعنی:
| نام Model | نام جدول پیشفرض |
|---|---|
| Product | products |
| Customer | customers |
| Order | orders |
| Invoice | invoices |
| UserProfile | user_profiles |
اگر نام جدول متفاوت باشد، میتوان آن را بهصورت دستی مشخص کرد:
class Product extends Model { protected $table = 'shop_products'; }
این قابلیت در پروژههایی کاربرد دارد که دیتابیس از قبل طراحی شده یا نام جدولها با قراردادهای Laravel هماهنگ نیست.
اتصال Model به کلید اصلی جدول
Laravel بهصورت پیشفرض فرض میکند کلید اصلی جدول ستونی به نام id است. در بیشتر پروژهها همین قرارداد کافی است. اما اگر جدول شما کلید اصلی متفاوتی داشته باشد، میتوانید آن را مشخص کنید:
class Product extends Model { protected $primaryKey = 'product_id'; }
اگر کلید اصلی عددی و افزایشی نباشد، مثلاً از UUID استفاده کنید، میتوانید تنظیمات زیر را اعمال کنید:
class Product extends Model { public $incrementing = false; protected $keyType = 'string'; }
این موضوع در پروژههای سازمانی، سیستمهای توزیعشده یا سامانههایی که نیاز به شناسههای غیرقابل حدس دارند، بسیار کاربردی است.
Timestamps در Eloquent Model
Laravel بهصورت پیشفرض انتظار دارد هر جدول دو ستون زیر را داشته باشد:
created_at updated_at
این دو ستون بهصورت خودکار توسط Eloquent مدیریت میشوند. هنگام ایجاد رکورد، مقدار created_at و updated_at ثبت میشود و هنگام ویرایش رکورد، مقدار updated_at تغییر میکند.
اگر جدولی این ستونها را نداشته باشد، میتوانید Timestamps را غیرفعال کنید:
class Product extends Model { public $timestamps = false; }
اما در اکثر پروژههای حرفهای، داشتن این دو ستون توصیه میشود؛ چون برای گزارشگیری، بررسی تاریخچه، مرتبسازی و تحلیل دادهها بسیار مفید هستند.
Mass Assignment و فیلدهای Fillable
یکی از مفاهیم بسیار مهم در مدلها در لاراول، Mass Assignment است. Mass Assignment یعنی ثبت یا بهروزرسانی چند فیلد بهصورت همزمان با استفاده از یک آرایه.
مثلاً:
Product::create([ 'name' => 'Laptop', 'price' => 45000000, 'stock' => 10, ]);
برای اینکه Laravel اجازه دهد این فیلدها بهصورت گروهی ذخیره شوند، باید آنها را در ویژگی $fillable تعریف کنیم:
class Product extends Model { protected $fillable = [ 'name', 'price', 'stock', 'status', ]; }
چرا Fillable مهم است؟
فرض کنید در جدول کاربران فیلدی به نام is_admin وجود دارد. اگر بدون کنترل، همه ورودیهای کاربر را ذخیره کنیم، ممکن است کاربر بتواند مقدار is_admin را ارسال کند و دسترسی مدیریتی بگیرد. برای جلوگیری از چنین مشکلاتی، Laravel از Mass Assignment Protection استفاده میکند.
مثلاً در مدل User نباید فیلدهای حساس را داخل $fillable قرار داد:
class User extends Model { protected $fillable = [ 'name', 'email', 'password', ]; }
در مستندات رسمی Laravel، Mass Assignment بهعنوان یکی از بخشهای مهم Eloquent معرفی شده است. برای مطالعه دقیقتر میتوانید به بخش Mass Assignment در مستندات Eloquent مراجعه کنید.
Guarded چیست؟
بهجای تعریف فیلدهای مجاز، میتوان فیلدهای غیرمجاز را با $guarded مشخص کرد:
class Product extends Model { protected $guarded = ['id']; }
در پروژههای حساس، استفاده از $fillable معمولاً شفافتر و امنتر است؛ چون دقیقاً مشخص میکند چه فیلدهایی قابل پر شدن هستند.
عملیات اصلی CRUD با Eloquent Model
یکی از دلایل محبوبیت Eloquent، سادهسازی عملیات CRUD است. CRUD شامل Create، Read، Update و Delete میشود.
ایجاد رکورد جدید
Product::create([ 'name' => 'مانیتور ۲۴ اینچ', 'price' => 8500000, 'stock' => 15, 'status' => 'active', ]);
یا:
$product = new Product(); $product->name = 'کیبورد مکانیکال'; $product->price = 3200000; $product->stock = 20; $product->save();
خواندن دادهها
$products = Product::all();$product = Product::find(1);$activeProducts = Product::where('status', 'active')->get();
بهروزرسانی دادهها
$product = Product::findOrFail(1); $product->price = 9000000; $product->save();
یا:
Product::where('status', 'inactive')->update([ 'status' => 'archived', ]);
حذف دادهها
$product = Product::findOrFail(1); $product->delete();
این عملیات در ظاهر سادهاند، اما در پروژههای واقعی باید همراه با اعتبارسنجی، کنترل دسترسی، مدیریت خطا و گاهی ثبت لاگ انجام شوند.
روابط در Eloquent Model
یکی از مهمترین قابلیتهای مدلها در لاراول، تعریف رابطهها بین موجودیتهاست. در نرمافزارهای واقعی، دادهها معمولاً مستقل نیستند. مشتری سفارش دارد، سفارش چند آیتم دارد، محصول به دستهبندی تعلق دارد و کاربر نقشهای مختلفی دارد.
Laravel انواع رابطههای رایج دیتابیس را در Eloquent پشتیبانی میکند. برای مطالعه منبع رسمی میتوانید به مستندات رسمی روابط Eloquent در Laravel مراجعه کنید.
رابطه One To One
رابطه یکبهیک زمانی استفاده میشود که هر رکورد فقط یک رکورد مرتبط داشته باشد.
مثلاً هر کاربر یک پروفایل دارد:
class User extends Model { public function profile() { return $this->hasOne(Profile::class); } }
و در مدل Profile:
class Profile extends Model { public function user() { return $this->belongsTo(User::class); } }
رابطه One To Many
رابطه یکبهچند بسیار رایج است. مثلاً هر مشتری میتواند چند سفارش داشته باشد:
class Customer extends Model { public function orders() { return $this->hasMany(Order::class); } }
در مدل Order:
class Order extends Model { public function customer() { return $this->belongsTo(Customer::class); } }
حالا میتوان سفارشهای یک مشتری را دریافت کرد:
$orders = Customer::find(1)->orders;
رابطه Many To Many
رابطه چندبهچند زمانی استفاده میشود که هر رکورد میتواند به چند رکورد دیگر وصل باشد و برعکس.
مثلاً هر کاربر میتواند چند نقش داشته باشد و هر نقش میتواند به چند کاربر اختصاص داده شود:
class User extends Model { public function roles() { return $this->belongsToMany(Role::class); } }class Role extends Model { public function users() { return $this->belongsToMany(User::class); } }
در این حالت معمولاً یک جدول واسط مثل role_user وجود دارد.
رابطه Has Many Through
گاهی یک مدل از طریق مدل دیگر به چند رکورد دسترسی دارد. مثلاً یک کشور چند کاربر دارد و هر کاربر چند سفارش دارد. در این حالت، کشور میتواند از طریق کاربران به سفارشها دسترسی داشته باشد.
رابطههای Polymorphic
روابط چندریختی یا Polymorphic زمانی کاربرد دارند که یک مدل بتواند به چند نوع مدل مختلف مرتبط شود. مثلاً سیستم کامنت میتواند برای مقالهها، محصولات و ویدئوها استفاده شود.
class Comment extends Model { public function commentable() { return $this->morphTo(); } }
این قابلیت برای پروژههایی که نیاز به طراحی انعطافپذیر دارند، بسیار ارزشمند است.
جدول کاربردی انواع رابطهها در Eloquent
| نوع رابطه | متد اصلی | مثال کسبوکاری | کاربرد رایج |
| One To One | hasOne / belongsTo | هر کاربر یک پروفایل دارد | پروفایل کاربر، تنظیمات حساب |
| One To Many | hasMany / belongsTo | هر مشتری چند سفارش دارد | سفارشها، پیامها، فاکتورها |
| Many To Many | belongsToMany | هر کاربر چند نقش دارد | نقشها، دسترسیها، برچسبها |
| Has Many Through | hasManyThrough | کشور از طریق کاربران به سفارشها میرسد | ساختارهای چندلایه |
| Polymorphic | morphTo / morphMany | کامنت برای مقاله و محصول | کامنت، فایل، تصویر، لاگ |
| Many To Many Polymorphic | morphToMany | تگ برای مقاله و محصول | سیستم برچسبگذاری پیشرفته |
Eager Loading و حل مشکل N+1 Query
یکی از چالشهای مهم در کار با مدلها در لاراول، مشکل N+1 Query است. این مشکل زمانی رخ میدهد که ابتدا مجموعهای از رکوردها را دریافت میکنیم و سپس برای هر رکورد، رابطهای جداگانه از دیتابیس خوانده میشود.
مثلاً:
$orders = Order::all(); foreach ($orders as $order) { echo $order->customer->name; }
اگر ۱۰۰ سفارش داشته باشیم، ممکن است یک کوئری برای سفارشها و ۱۰۰ کوئری برای مشتریان اجرا شود. این وضعیت در پروژههای بزرگ باعث کندی شدید میشود.
راهحل، استفاده از Eager Loading است:
$orders = Order::with('customer')->get();
حالا Laravel رابطه مشتری را از قبل بارگذاری میکند و تعداد کوئریها کاهش مییابد.
Eager Loading در پروژههای واقعی
در یک پنل مدیریت فروش، صفحه لیست سفارشها معمولاً نام مشتری، وضعیت پرداخت، تعداد آیتمها و مبلغ سفارش را نمایش میدهد. اگر این دادهها بدون Eager Loading دریافت شوند، صفحه ممکن است با افزایش سفارشها بسیار کند شود. اما با طراحی درست Modelها و استفاده از with، عملکرد سیستم بهتر خواهد شد.
Attribute Casting در Eloquent Model
Casting یعنی تبدیل خودکار نوع دادهها هنگام خواندن یا نوشتن در Model. برای مثال، فیلد is_active در دیتابیس ممکن است عدد ۰ یا ۱ باشد، اما در کد بهتر است بهصورت boolean با آن کار کنیم.
class Product extends Model { protected function casts(): array { return [ 'is_active' => 'boolean', 'price' => 'integer', 'published_at' => 'datetime', 'options' => 'array', ]; } }
در این حالت، وقتی options از دیتابیس خوانده میشود، Laravel آن را به آرایه تبدیل میکند. وقتی published_at خوانده میشود، به یک شیء تاریخ تبدیل میشود.
Laravel در مستندات رسمی Mutators و Attribute Casting توضیح میدهد که Accessor، Mutator و Casting برای تغییر مقدار ویژگیها هنگام خواندن یا تنظیم آنها استفاده میشوند.
کاربرد Casting در کسبوکارها
در یک سامانه فروش، ممکن است محصول دارای تنظیمات مختلفی باشد؛ مثل رنگهای قابل انتخاب، ویژگیهای سفارشی، وضعیت انتشار، تاریخ شروع تخفیف و تاریخ پایان تخفیف. Casting کمک میکند این دادهها در کد بهصورت مناسب و قابل فهم استفاده شوند.
Accessor و Mutator در مدلهای Laravel
Accessor برای تغییر مقدار هنگام خواندن استفاده میشود و Mutator برای تغییر مقدار هنگام ذخیرهسازی.
مثال 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}", ); } }
حالا میتوان نوشت:
$user->full_name;
مثال Mutator
فرض کنید میخواهیم ایمیل کاربر همیشه با حروف کوچک ذخیره شود:
use Illuminate\Database\Eloquent\Casts\Attribute; class User extends Model { protected function email(): Attribute { return Attribute::make( set: fn ($value) => strtolower($value), ); } }
این روش باعث میشود قوانین کوچک اما مهم دادهای در جای مناسب قرار بگیرند.
Query Scope در Eloquent Model
Scopeها برای تعریف کوئریهای پرتکرار استفاده میشوند. اگر در چند بخش پروژه نیاز دارید فقط محصولات فعال را دریافت کنید، بهتر است این منطق را بهصورت Scope در Model تعریف کنید.
class Product extends Model { public function scopeActive($query) { return $query->where('status', 'active'); } }
استفاده:
$products = Product::active()->get();
Scope با پارامتر
class Product extends Model { public function scopeMinPrice($query, $price) { return $query->where('price', '>=', $price); } }
استفاده:
$products = Product::active()->minPrice(1000000)->get();
مزیت Scope
Scopeها باعث کاهش کد تکراری، افزایش خوانایی و استانداردسازی کوئریها میشوند. در یک نرمافزار سازمانی، ممکن است مفهوم «فعال»، «قابل نمایش»، «پرداختشده»، «در انتظار بررسی» یا «آرشیوشده» در بخشهای مختلف استفاده شود. Scope بهترین روش برای متمرکز کردن این نوع کوئریهاست.
Soft Delete در مدلها در لاراول
در بسیاری از نرمافزارهای تجاری، حذف دائمی دادهها همیشه کار درستی نیست. مثلاً حذف یک مشتری، فاکتور یا سفارش ممکن است باعث از بین رفتن سوابق مهم شود. Laravel قابلیتی به نام Soft Delete دارد که بهجای حذف واقعی رکورد، مقدار ستون deleted_at را ثبت میکند.
برای استفاده:
use Illuminate\Database\Eloquent\SoftDeletes; class Product extends Model { use SoftDeletes; }
در Migration باید ستون زیر اضافه شود:
$table->softDeletes();
حالا وقتی delete اجرا شود، رکورد از دیتابیس حذف نمیشود، فقط بهعنوان حذفشده علامت میخورد.
بازیابی رکورد حذفشده
Product::withTrashed()->find(1)->restore();
حذف دائمی
Product::withTrashed()->find(1)->forceDelete();
Soft Delete برای پنلهای مدیریتی، CRM، سیستم فروش و نرمافزارهای سازمانی بسیار کاربردی است.
Model Events در Laravel
Eloquent برای مدلها رویدادهای مختلفی ارائه میدهد. این رویدادها هنگام ایجاد، ذخیره، ویرایش یا حذف رکورد اجرا میشوند.
برخی رویدادهای رایج:
- creating
- created
- updating
- updated
- saving
- saved
- deleting
- deleted
مثلاً:
class Product extends Model { protected static function booted() { static::creating(function ($product) { $product->slug = str($product->name)->slug(); }); } }
در این مثال، قبل از ایجاد محصول، slug بهصورت خودکار ساخته میشود.
کاربرد Model Events در کسبوکار
در یک سیستم سفارش، پس از ثبت سفارش میتوان رویدادی اجرا کرد که موجودی کالا کاهش یابد، پیامک ارسال شود یا لاگ ثبت شود. البته برای منطقهای سنگین بهتر است از Event، Listener و Job استفاده شود تا Model بیش از حد شلوغ نشود.
خروجی JSON، Hidden و Visible در Model
در پروژههای API محور، Modelها معمولاً به JSON تبدیل میشوند. گاهی لازم است برخی فیلدها مثل رمز عبور، توکن یا اطلاعات حساس در خروجی نمایش داده نشوند.
class User extends Model { protected $hidden = [ 'password', 'remember_token', ]; }
یا میتوان فقط فیلدهای خاصی را قابل نمایش کرد:
protected $visible = [ 'id', 'name', 'email', ];
در پروژههای حرفهای API، معمولاً بهتر است بهجای خروجی مستقیم Model، از API Resource استفاده شود. Laravel در مستندات رسمی Eloquent API Resources توضیح میدهد که Resourceها یک لایه تبدیل بین مدلهای Eloquent و پاسخهای JSON ایجاد میکنند.
Factory و تستپذیری مدلها
برای تست نرمافزار، نیاز داریم دادههای آزمایشی بسازیم. Laravel Factoryها را برای همین هدف ارائه میدهد.
php artisan make:factory ProductFactory
نمونه Factory:
class ProductFactory extends Factory { public function definition(): array { return [ 'name' => fake()->word(), 'price' => fake()->numberBetween(100000, 5000000), 'stock' => fake()->numberBetween(1, 100), 'status' => 'active', ]; } }
استفاده در تست:
Product::factory()->count(10)->create();
Factoryها در پروژههای حرفهای اهمیت زیادی دارند؛ چون کمک میکنند تستها مستقل، سریع و قابل تکرار باشند.
مثال واقعی اول: مدل Product در فروشگاه اینترنتی
فرض کنید یک کسبوکار میخواهد فروشگاه اینترنتی اختصاصی داشته باشد. مدل محصول میتواند شامل نام، قیمت، موجودی، وضعیت انتشار، دستهبندی و تصویر باشد.
class Product extends Model { protected $fillable = [ 'category_id', 'name', 'slug', 'price', 'stock', 'status', 'description', ]; protected function casts(): array { return [ 'price' => 'integer', 'stock' => 'integer', ]; } public function category() { return $this->belongsTo(Category::class); } public function scopeActive($query) { return $query->where('status', 'active'); } }
در Controller:
$products = Product::with('category') ->active() ->latest() ->paginate(20);
این ساختار ساده اما قدرتمند است. محصول رابطه با دستهبندی دارد، فیلدهای قابل ذخیره مشخص هستند، نوع دادهها Cast شدهاند و کوئری محصولات فعال بهصورت Scope تعریف شده است.
برای تیمی مانند اسمارتی اپ (SmartyApp)، چنین طراحیای کمک میکند فروشگاه اینترنتی یا سامانه فروش اختصاصی در آینده راحتتر توسعه پیدا کند؛ مثلاً اضافه کردن تخفیف، انبار چندگانه، قیمت همکاری یا ویژگیهای فنی محصول سادهتر خواهد بود.
مثال واقعی دوم: مدل Customer در CRM اختصاصی
در یک CRM، مشتریان ممکن است اطلاعات تماس، وضعیت، منبع جذب، پیگیریها و قراردادها داشته باشند.
class Customer extends Model { protected $fillable = [ 'name', 'phone', 'email', 'company_name', 'source', 'status', ]; public function followUps() { return $this->hasMany(FollowUp::class); } public function contracts() { return $this->hasMany(Contract::class); } public function scopePotential($query) { return $query->where('status', 'potential'); } }
در این مدل، رابطه مشتری با پیگیریها و قراردادها مشخص است. همچنین یک Scope برای مشتریان بالقوه تعریف شده است.
در پنل مدیریت فروش، مدیر میتواند مشتریان بالقوه را مشاهده کند:
$customers = Customer::potential() ->with('followUps') ->latest() ->paginate(30);
این نوع طراحی به کسبوکار کمک میکند فرایند فروش خود را دقیقتر مدیریت کند.
مثال واقعی سوم: مدل Order در سامانه سفارش
مدل سفارش در بسیاری از پروژهها یکی از مهمترین مدلهاست. سفارش معمولاً به مشتری، آیتمهای سفارش، پرداخت و فاکتور متصل است.
class Order extends Model { protected $fillable = [ 'customer_id', 'total_price', 'status', 'paid_at', ]; protected function casts(): array { return [ 'total_price' => 'integer', 'paid_at' => 'datetime', ]; } public function customer() { return $this->belongsTo(Customer::class); } public function items() { return $this->hasMany(OrderItem::class); } public function payment() { return $this->hasOne(Payment::class); } public function scopePaid($query) { return $query->whereNotNull('paid_at'); } }
حالا برای دریافت سفارشهای پرداختشده همراه با مشتری و آیتمها:
$orders = Order::paid() ->with(['customer', 'items']) ->latest() ->paginate(20);
در نرمافزارهای اختصاصی، این نوع طراحی باعث میشود گزارشگیری، مدیریت سفارش، کنترل مالی و توسعه امکانات جدید بسیار سادهتر شود.
مزایای استفاده درست از مدلها در لاراول
۱. خوانایی بهتر کد
وقتی مدلها درست طراحی شوند، کدهای پروژه بسیار خواناتر میشوند. عبارت Order::paid()->with('customer')->get() بسیار قابل فهمتر از چندین خط کوئری پیچیده SQL است.
۲. کاهش کدهای تکراری
با تعریف رابطهها، Scopeها، Castها و Accessorها در Model، بسیاری از کدهای تکراری حذف میشوند.
۳. توسعه سریعتر
Eloquent Modelها سرعت توسعه را افزایش میدهند. ساخت عملیات CRUD، رابطهها، فیلترها و خروجی API با Eloquent سریعتر از مدیریت دستی همه کوئریهاست.
۴. نگهداری آسانتر
در پروژههای بلندمدت، نگهداری نرمافزار بسیار مهم است. Modelهای استاندارد باعث میشوند تیم توسعه سریعتر منطق دادهای پروژه را پیدا و اصلاح کند.
۵. تستپذیری بهتر
با استفاده از Factory، Relationship و Scope میتوان تستهای دقیقتری برای منطق دادهای نوشت.
۶. هماهنگی بهتر با معماری MVC
Modelها نقش مهمی در تمیز نگه داشتن Controllerها دارند. اگر منطق دادهای در Model و Serviceهای مناسب قرار بگیرد، Controllerها سبکتر و قابل فهمتر میشوند.
چالشهای کار با Eloquent Model
۱. شلوغ شدن بیش از حد Model
همانطور که Controller نباید بیش از حد بزرگ شود، Model هم نباید محل انباشت همه منطقهای پروژه باشد. اگر تمام قوانین کسبوکار، محاسبات، ارسال پیامک، صدور فاکتور و اتصال به سرویسهای خارجی داخل Model نوشته شود، نگهداری پروژه سخت میشود.
۲. مشکل N+1 Query
اگر رابطهها بدون Eager Loading استفاده شوند، تعداد کوئریها بهشدت افزایش مییابد و عملکرد سیستم کاهش پیدا میکند.
۳. استفاده نادرست از Mass Assignment
اگر فیلدهای حساس در $fillable قرار بگیرند یا ورودی کاربر بدون کنترل ذخیره شود، امنیت پروژه به خطر میافتد.
۴. وابستگی زیاد به ساختار دیتابیس
اگر Modelها بیش از حد به جزئیات دیتابیس وابسته شوند، تغییر ساختار دیتابیس میتواند بخشهای زیادی از کد را تحت تأثیر قرار دهد.
۵. پیچیدگی در پروژههای بزرگ
در پروژههای بزرگ، Model بهتنهایی کافی نیست. باید از Service Layer، Action، DTO، Repository یا ساختارهای دامنهمحور استفاده شود.
بهترین روشها برای طراحی Eloquent Model در Laravel
۱. Model را خوانا و متمرکز نگه دارید
Model باید منطق مرتبط با داده، روابط، Scopeها، Castها و ویژگیهای مرتبط را مدیریت کند، اما نباید به یک کلاس بسیار بزرگ تبدیل شود.
۲. از نامگذاری استاندارد استفاده کنید
نام Model بهتر است مفرد و PascalCase باشد؛ مثل Product یا CustomerOrder. نام جدول نیز معمولاً جمع و snake_case است؛ مثل products یا customer_orders.
۳. همیشه Fillable را با دقت تعریف کنید
فیلدهای قابل ذخیرهسازی گروهی را دقیق مشخص کنید و فیلدهای حساس را وارد $fillable نکنید.
۴. رابطهها را در Model تعریف کنید
اگر دو موجودیت به هم مرتبط هستند، رابطه را در Model تعریف کنید. این کار کد را خواناتر و توسعه را سادهتر میکند.
۵. از Eager Loading استفاده کنید
برای صفحات لیستی، گزارشها و APIهایی که دادههای مرتبط نمایش میدهند، حتماً به مشکل N+1 Query توجه کنید.
۶. Scopeها را برای کوئریهای پرتکرار بنویسید
اگر شرطی در چند جای پروژه تکرار میشود، آن را به Scope تبدیل کنید.
۷. برای خروجی API از Resource استفاده کنید
نمایش مستقیم Model در API همیشه بهترین روش نیست. Resourceها کنترل بهتری روی ساختار خروجی میدهند.
۸. از Soft Delete برای دادههای حساس تجاری استفاده کنید
برای رکوردهایی مثل سفارش، فاکتور، مشتری و پرداخت، حذف دائمی میتواند خطرناک باشد. Soft Delete انتخاب مناسبتری است.
۹. منطق سنگین را به Service منتقل کنید
اگر محاسبه قیمت، مالیات، تخفیف یا صدور فاکتور پیچیده است، بهتر است در Service جداگانه نوشته شود.
۱۰. مدلها را تست کنید
رابطهها، Scopeها و Castهای مهم باید تست شوند؛ مخصوصاً در نرمافزارهای مالی، فروشگاهی و سازمانی.
مدلها در لاراول از نگاه کسبوکار
برای مدیران کسبوکار، Eloquent Model ممکن است یک مفهوم کاملاً فنی به نظر برسد؛ اما نتیجه آن کاملاً تجاری است. طراحی درست مدلها باعث میشود نرمافزار قابل توسعهتر، پایدارتر و کمهزینهتر باشد.
فرض کنید یک شرکت در ابتدا فقط به مدیریت سفارش نیاز دارد، اما بعداً میخواهد امکانات زیر را اضافه کند:
- باشگاه مشتریان
- گزارش فروش ماهانه
- اتصال به حسابداری
- مدیریت انبار
- فاکتور رسمی
- سطحبندی مشتریان
- تخفیفهای هوشمند
- پنل نمایندگان فروش
اگر مدلها از ابتدا درست طراحی نشده باشند، اضافه کردن این امکانات سخت، زمانبر و پرخطا خواهد بود. اما اگر موجودیتهایی مثل Customer، Order، Product، Payment و Invoice با روابط درست طراحی شده باشند، توسعه آینده سادهتر انجام میشود.
به همین دلیل، در پروژههای تولید نرمافزار اختصاصی، تیمهایی مانند اسمارتی اپ (SmartyApp) باید قبل از شروع کدنویسی، تحلیل دقیقی از موجودیتهای اصلی کسبوکار و ارتباط بین آنها داشته باشند.
تفاوت Model، Migration و Controller در Laravel
گاهی برای برنامهنویسان تازهکار این سؤال پیش میآید که تفاوت Model، Migration و Controller چیست.
| مفهوم | وظیفه اصلی | مثال |
| Model | کار با دادهها و جدول دیتابیس | Product |
| Migration | تعریف ساختار جدولها | ایجاد جدول products |
| Controller | مدیریت درخواست کاربر | ProductController |
| Factory | ساخت داده آزمایشی | تولید محصولات تستی |
| Seeder | وارد کردن داده اولیه | ثبت دستهبندیهای پیشفرض |
Migration ساختار دیتابیس را تعریف میکند، Model با دادههای آن جدول کار میکند و Controller درخواستهای کاربر را مدیریت میکند.
آیا همیشه باید از Eloquent استفاده کنیم؟
Eloquent برای اکثر پروژههای Laravel انتخاب بسیار مناسبی است. اما در برخی شرایط خاص، ممکن است Query Builder یا SQL خام عملکرد بهتری داشته باشد؛ مثلاً در گزارشهای بسیار پیچیده، پردازشهای حجیم یا کوئریهای خاص دیتابیس.
Laravel خودش امکان استفاده از Query Builder و Raw Query را هم فراهم میکند. بنابراین انتخاب بین Eloquent، Query Builder و SQL خام باید بر اساس نیاز پروژه، پیچیدگی کوئری و الزامات عملکردی انجام شود.
در حالت کلی:
- برای عملیات رایج CRUD: Eloquent بسیار مناسب است.
- برای روابط و منطق دامنه: Eloquent خوانا و قدرتمند است.
- برای گزارشهای سنگین: Query Builder یا SQL خام گاهی بهتر است.
- برای APIهای استاندارد: Eloquent همراه با Resource انتخاب خوبی است.
نقش مدلها در افزایش کیفیت نرمافزار اختصاصی
نرمافزار اختصاصی معمولاً برای حل یک مسئله خاص در یک کسبوکار ساخته میشود. چنین نرمافزاری باید با فرایندهای واقعی کسبوکار هماهنگ باشد. مدلها در لاراول کمک میکنند مفاهیم واقعی کسبوکار به ساختار فنی قابل مدیریت تبدیل شوند.
مثلاً:
| مفهوم کسبوکار | Model پیشنهادی |
| مشتری | Customer |
| سفارش | Order |
| فاکتور | Invoice |
| پرداخت | Payment |
| تیکت پشتیبانی | Ticket |
| قرارداد | Contract |
| کارمند | Employee |
| شعبه | Branch |
وقتی این موجودیتها درست مدلسازی شوند، توسعه نرمافزار ساختارمندتر میشود. این موضوع برای شرکتهایی که بهدنبال نرمافزار اختصاصی پایدار هستند، اهمیت زیادی دارد.
FAQ: سوالات متداول درباره مدلها در لاراول و Eloquent Model
۱. Eloquent Model در Laravel چیست؟
Eloquent Model یک کلاس PHP در Laravel است که معمولاً نماینده یک جدول دیتابیس است و برای خواندن، ایجاد، ویرایش و حذف دادهها استفاده میشود.
۲. تفاوت Model و Migration چیست؟
Migration ساختار جدول دیتابیس را تعریف میکند، اما Model برای تعامل با دادههای همان جدول استفاده میشود.
۳. آیا هر جدول باید یک Model داشته باشد؟
در بیشتر موارد بله، اما نه همیشه. جدولهای واسط ساده یا جدولهایی که فقط برای ساختار داخلی استفاده میشوند، ممکن است Model مستقل نیاز نداشته باشند.
۴. Fillable در مدل لاراول چیست؟
$fillable مشخص میکند کدام فیلدها اجازه دارند از طریق Mass Assignment مقداردهی شوند. این ویژگی برای امنیت و کنترل ورودیها مهم است.
۵. Guarded چه تفاوتی با Fillable دارد؟
$fillable فیلدهای مجاز را مشخص میکند، اما $guarded فیلدهای غیرمجاز را. در پروژههای حساس، $fillable معمولاً شفافتر است.
۶. رابطهها در Eloquent چه کاربردی دارند؟
رابطهها ارتباط بین مدلها را تعریف میکنند؛ مثل ارتباط مشتری با سفارشها یا محصول با دستهبندی.
۷. مشکل N+1 Query چیست؟
N+1 Query زمانی رخ میدهد که برای هر رکورد، یک کوئری جداگانه برای رابطه اجرا شود. این مشکل با Eager Loading قابل حل است.
۸. Casting در Eloquent Model چیست؟
Casting باعث میشود مقدار فیلدهای مدل هنگام خواندن یا نوشتن به نوع داده مناسب تبدیل شود؛ مثلاً boolean، array، integer یا datetime.
۹. Accessor و Mutator چه تفاوتی دارند؟
Accessor مقدار یک ویژگی را هنگام خواندن تغییر میدهد، اما Mutator مقدار را هنگام ذخیرهسازی یا تنظیم تغییر میدهد.
۱۰. Scope در مدل لاراول چیست؟
Scope یک روش برای تعریف کوئریهای پرتکرار در Model است. مثلاً active() برای دریافت رکوردهای فعال.
۱۱. آیا Model باید شامل منطق کسبوکار باشد؟
Model میتواند بخشی از منطق مرتبط با داده را داشته باشد، اما منطقهای سنگین و پیچیده بهتر است در Service یا کلاسهای جداگانه قرار بگیرند.
۱۲. Soft Delete چه کاربردی دارد؟
Soft Delete بهجای حذف دائمی رکورد، آن را بهعنوان حذفشده علامت میزند. این قابلیت برای حفظ سوابق تجاری بسیار مفید است.
۱۳. آیا میتوان از Eloquent برای API استفاده کرد؟
بله. Eloquent برای API بسیار کاربردی است، اما بهتر است خروجی مدلها با API Resource کنترل شود.
۱۴. آیا Eloquent برای پروژههای بزرگ مناسب است؟
بله، اما در پروژههای بزرگ باید همراه با معماری مناسب، Service Layer، بهینهسازی کوئریها و استانداردهای تیمی استفاده شود.
جمعبندی
مدلها در لاراول یکی از اصلیترین ستونهای توسعه نرمافزارهای تحت وب هستند. Eloquent Model به توسعهدهندگان کمک میکند با دیتابیس بهصورت شیءگرا، خوانا و قابل نگهداری کار کنند. با استفاده درست از Modelها میتوان عملیات CRUD، روابط، Scopeها، Castها، Accessorها، Mutatorها، Soft Delete و خروجی API را بهشکلی استاندارد مدیریت کرد.
اما قدرت Eloquent زمانی ارزش واقعی پیدا میکند که با طراحی درست استفاده شود. Model نباید بیش از حد شلوغ شود، Controller نباید منطق دادهای زیادی داشته باشد، رابطهها باید درست تعریف شوند و برای کوئریهای پرتکرار باید از Scope و Eager Loading استفاده شود.
برای کسبوکارهایی که به نرمافزار اختصاصی، CRM، سامانه فروش، پنل مدیریتی، داشبورد مدیریتی یا پورتال مشتریان نیاز دارند، طراحی درست مدلها در لاراول میتواند تفاوت بزرگی در کیفیت نهایی پروژه ایجاد کند. این طراحی روی سرعت توسعه، هزینه نگهداری، امنیت، عملکرد و امکان توسعه آینده اثر مستقیم دارد.
اگر پروژه Laravel از ابتدا با Modelهای استاندارد، روابط دقیق و معماری مناسب طراحی شود، نرمافزار نهتنها نیازهای امروز کسبوکار را پوشش میدهد، بلکه برای رشد آینده نیز آماده خواهد بود.
CTA: برای طراحی نرمافزار تحت وب با Laravel مشاوره بگیرید
اگر قصد دارید برای کسبوکار خود یک نرمافزار اختصاصی، سامانه فروش، CRM، پنل مدیریتی، پورتال مشتریان یا وباپلیکیشن حرفهای طراحی کنید، معماری داده و طراحی Modelها یکی از اولین تصمیمهای مهم پروژه است.
تیم اسمارتی اپ (SmartyApp) میتواند در تحلیل نیازمندیها، طراحی ساختار نرمافزار، توسعه Backend با Laravel، طراحی سایت و پیادهسازی نرمافزارهای تحت وب به شما کمک کند. برای دریافت مشاوره فنی، بررسی ایده یا برآورد مسیر توسعه، با ما تماس بگیرید.
منابع رسمی
- مستندات رسمی Eloquent ORM در Laravel
- مستندات رسمی روابط Eloquent در Laravel
- مستندات رسمی Mutators و Attribute Casting در Laravel
- مستندات رسمی Eloquent API Resources در Laravel
- مستندات رسمی Eloquent Collections در Laravel
- مستندات رسمی Controllers در Laravel
- مستندات رسمی Migrations در Laravel
- مستندات رسمی Database Testing در Laravel