Eloquent در لاراول و جادوی کاربردی‌‌اش

Eloquent در لاراول و جادوی کاربردی‌‌اش

نوشته شده توسط: تیم فنی نیک آموز
تاریخ انتشار: ۰۸ شهریور ۱۴۰۳
آخرین بروزرسانی: ۰۹ شهریور ۱۴۰۳
زمان مطالعه: 20 دقیقه
۰
(۰)

Eloquent در لاراول به شما قدرت تسلط بر پیچیدگی‌های دیتابیس را به شیوه‌ای جادویی عطا می‌کند. دیگر نیازی به نوشتن دستورات SQL پیچیده و غیرقابل خواندن نیست. با Eloquent، می‌توانید مدل‌های شیءگرا برای هر جدول در پایگاه داده خود تعریف کرده و با داده‌های خود به روشی شهودی و کارآمد کار کنید. در این مقاله، با مفاهیم کلیدی و کاربردهای Eloquent محبوب در لاراول آشنا خواهیم شد و گام‌به‌گام پرده از راز و رمز این ابزار قدرتمند برمی‌داریم. 

Eloquent ORM چیست؟

فریم‌ورک لاراول در دنیای PHP، با یک راز قدرتمند همراه است: Object Relational Mapper یا همان ORM به نام Eloquent. این ابزار جادویی، ارتباط با پایگاه داده را به امری ساده و لذت‌بخش تبدیل می‌کند. دیگر نیازی نیست نگران ساعت‌ها کدنویسی و دست‌وپنجه نرم کردن با مشکلات ریزودرشت دیتابیس‌ باشید. Eloquent در لاراول به شما کمک می‌کند تا با کدهایی سازمان‌یافته، قابل‌استفاده مجدد، قابل نگهداری و مقیاس‌پذیر سریع‌تر به نتیجه برسید.

این فریم‌ورک قدرتمند، نه‌تنها با انواع دیتابیس سازگار است، بلکه امکان انجام عملیات رایج پایگاه‌داده را نیز به‌سادگی فراهم می‌کند. فرقی نمی‌کند در حال ساخت یک وب‌سایت اختصاصی بوده یا پروژه‌ای با نیازهای خاص طراحی می‌کنید؛ لاراول با آغوش باز سفری لذت‌بخش در دنیای توسعه وب برایتان رقم می‌زند.

مدل‌ها در Eloquent

برای شروع کار با Eloquent در لاراول، ابتدا باید یک مدل بسازیم. مدل‌ها معمولا داخل پوشه app قرار می‌گیرند، اما شما می‌توانید آن‌ها را هر جایی که توسط فایل composer.json قابل شناسایی است، قرار دهید. نکته مهم این است که همه مدل‌های Eloquent در لاراول از کلاس Illuminate\Database\Eloquent\Model ارث‌بری می‌شوند. راحت‌ترین راه برای ساختن یک نمونه مدل، استفاده از دستور Artisan به نام make:model است:

 

php artisan make:model Flight

 

سفارشی‌ سازی مدل Eloquent در Laravel

در این بخش، به بررسی نمونه‌ای از یک مدل با نام Flight می‌پردازیم که برای بازیابی و ذخیره‌سازی اطلاعات از جدول flights در پایگاه داده استفاده می‌شود:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    //
}

 

نامگذاری جداول

تا این قسمت، هنوز به Eloquent در لاراول، نگفتیم برای مدل Flight از کدام جدول استفاده کند. Eloquent به‌صورت خودکار، بر اساس نام مدل شما، نام جدول را حدس می‌زند. به‌این‌صورت که اسم مدل را با حروف کوچک و به‌صورت جمع در نظر می‌گیرد. مثلا برای مدل «Flight»، الاکوئنت به‌طور پیش‌فرض دنبال جدول «flights» می‌گردد.

البته، شما می‌توانید این نام‌گذاری را تغییر دهید و یک اسم دلخواه برای جدولتان انتخاب کنید. کافی‌است در مدل موردنظرتان یک ویژگی به اسم «table» تعریف کنید و اسم جدید رو آن‌جا قرار دهید. برای مثال، در کد زیر، جدول مربوط به مدل «Flight» را به «my_flights» تغییر دادیم:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'my_flights';
}

 

کلید های اصلی در Eloquent (کلید های اولیه)

Eloquent در لاراول فرض می‌کند هر جدولی در دیتابیس شما یک ستون به عنوان کلید اصلی (Primary Key) دارد که به‌طور معمول با نام id شناخته می‌شود. حالا اگر نام Primary Key شما متفاوت است، آن را به‌سادگی می‌توانید تغییر دهید.

برای این کار کافی‌است از خاصیت $primaryKey در مدل Eloquent خود استفاده کنید. مثلا در مثال ما، کلید اصلی جدول Flight ستونی به نام flight_id است:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * The primary key associated with the table.
     *
     * @var string
     */
    protected $primaryKey = 'flight_id';
}

 

علاوه‌براین، Eloquent در لاراول به‌طور پیش فرض کلید اصلی را یک عدد صحیح (Integer) با قابلیت افزایش خودکار (Auto-Increment) می‌شناسد. یعنی هر بار که رکورد جدیدی به جدول اضافه کنید، مقدار کلید اصلی به‌صورت خودکار یک واحد بیشتر می‌شود. اگر می‌خواهید از یک primaryKey غیرعددی یا غیرافزایشی استفاده کنید، کافی‌است ویژگی عمومی $incrementing را در مدل خود روی false تنظیم کنید:

 

<?php
class Flight extends Model
{
    /**
     * Indicates if the IDs are auto-incrementing.
     *
     * @var bool
     */
    public $incrementing = false;
}

 

فراموش نکنید که اگر primaryKey شما یک عدد صحیح (Integer) نیست، باید نوع آن را با استفاده از خاصیت $keyType در مدل خود مشخص کنید. در این مثال، نوع primaryKey ما یک رشته متنی (String) است:

 

<?php
class Flight extends Model
{
    /**
     * The "type" of the auto-incrementing ID.
     *
     * @var string
     */
    protected $keyType = 'string';
}

 

با این تنظیمات ساده، می‌توانید به Eloquent در لاراول بگویید از کدام ستون به عنوان primaryKey استفاده کند و نوع آن را نیز مشخص کنید.

قابلیت Timestamps  

Eloquent در لاراول به‌طور پیش فرض انتظار دارد دو ستون created_at (زمان ایجاد) و updated_at (زمان به‌روزرسانی) در جدول شما وجود داشته باشد. این ستون‌ها به‌صورت خودکار توسط Eloquent مدیریت می‌شوند و زمان ایجاد و بروزرسانی رکورد را ثبت می‌کنند. اگر نمی‌خواهید Eloquent این ستون‌ها را به‌صورت خودکار مدیریت کند، کافی‌است مقدار $timestamps در مدل خود را روی false تنظیم کنید:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;
}

 

اگر می‌خواهید قالب نمایش تاریخچه‌ تغییرات (زمان ایجاد و بروزرسانی) را شخصی‌سازی کنید، از قابلیت $dateFormat در مدل خود می‌توانید استفاده کنید. این خاصیت نحوه ذخیره‌سازی مقادیر تاریخ در پایگاه داده و همچنین قالب خروجی آن‌ها هنگام تبدیل مدل به آرایه یا JSON را تعیین می‌کند.

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * The storage format of the model's date columns.
     *
     * @var string

     */
    protected $dateFormat = 'U';
}

 

درصورتی‌که قصد دارید نام ستون‌های created_at و updated_at را تغییر دهید، از ویژگی‌های CREATED_AT و UPDATED_AT در مدل خود استفاده کنید:

 

<?php
class Flight extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';
}

 

با استفاده از این تنظیمات، می‌توانید نحوه‌ مدیریت تاریخچه‌ تغییرات در مدل‌های Eloquent در لاراول خود را به دلخواه شخصی‌سازی کنید.

اتصال به پایگاه داده در (Eloquent)

به‌طور پیش‌فرض، تمام مدل‌های Eloquent در لاراول از اتصال پیش‌فرض پایگاه داده‌ای استفاده می‌کنند که برای برنامه‌ شما تنظیم شده است. با این حال، اگر می‌خواهید اتصال دیگری را برای یک مدل خاص تعریف کنید، از خاصیت $connection می‌توانید استفاده نمایید. قطعه کد زیر به شما نشان می‌دهد که چطور این کار را انجام دهید:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * The connection name for the model.
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

 

در این مثال، connection-name را با نام واقعی اتصال پایگاه داده‌ای جایگزین کنید که می‌خواهید مدل از آن استفاده کند.

تعیین مقدار پیش‌فرض Attribute در مدل‌ های Eloquent

در لاراول، اگر می‌خواهید برای بعضی از ویژگی‌های مدلتان (Attribute) مقادیر پیش‌فرضی را تعریف کنید، از خاصیت $attributes می‌توانید استفاده کنید. این کار باعث می‌شود هر موقع یک مدل جدید از این کلاس ساخته شد، ویژگی‌های موردنظر به‌صورت خودکار با مقادیر پیش‌فرض شما مقداردهی شوند. برای مثال به کد زیر نگاه کنید:

 

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'delayed' => false,
    ];
}

 

با این کار، هر بار یک مدل جدید از کلاس Flight ساخته می‌شود، ویژگی delayed به‌صورت خودکار روی مقدار false تنظیم می‌شود؛ مگر اینکه موقع ساختن مدل، مقدار دیگری برای آن تعریف کنید.

دریافت داده‌ های Database توسط Model

بعد از اینکه مدل و جدول مرتبط با آن را در دیتابیس ساختید، حالا نوبت به بیرون کشیدن اطلاعات از این مخزن ارزشمند می‌رسد. مدل‌های Eloquent در لاراول را می‌توان به عنوان ابزارهای قدرتمند ساخت کوئری در نظر گرفت که به شما اجازه می‌دهند به‌راحتی از جدول مرتبط با مدل، داده‌ها را بیرون بکشید. با یک مثال ساده بهتر متوجه خواهید شد:

 

<?php
$flights = App\Flight::all();
foreach ($flights as $flight) {
    echo $flight->name;
}

 

محدود کردن نتایج با شرط

متد all در Eloquent تمام اطلاعات موجود در جدول را برمی‌گرداند. البته چون هر مدل Eloquent در لاراول مثل یک سازنده‌ کوئری عمل می‌کند، شما می‌توانید شرط‌هایی هم به کوئری اضافه کنید و بعد با استفاده از متد get نتایج را تحویل بگیرید:

 

$flights = App\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();

 

به‌ روزرسانی اطلاعات مدل‌ ها در Laravel

در لاراول، با استفاده از دو متد fresh و refresh می‌توانید اطلاعات مدل‌ها را به‌روز نگه دارید. این دو متد به شکل‌های مختلفی کار می‌کنند:

  • fresh: این متد مدل را دوباره از پایگاه داده بازیابی می‌کند. در واقع، با استفاده از fresh یک نمونه جدید از مدل با اطلاعات به‌روز شده از پایگاه داده ساخته می‌شود و مدل اصلی تحت تأثیر قرار نمی‌گیرد.

 

$flight = App\Flight::where('number', 'FR 900')->first();
$freshFlight = $flight->fresh();

 

  • refresh: این متد به جای ساختن یک نمونه جدید، مستقیما اطلاعات مدل موجود را با داده‌های تازه از پایگاه داده به‌روز می‌کند. علاوه‌براین، هر رابطه‌ای (Relationship) که برای این مدل بارگذاری شده باشد نیز به‌روز می‌شود.

 

$flight = App\Flight::where('number', 'FR 900')->first();
$flight->number = 'FR 456';
$flight->refresh();
$flight->number; // "FR 900"

 

عملیات پایه‌ ای با Eloquent 

منظور از عملیات پایه‌ای، ایجاد، به‌روزرسانی و حذف داده‌های یک مدل است. در ادامه، به بررسی هرکدام می‌پردازیم.

ایجاد داده‌ های جدید در مدل 

برای اضافه کردن یک رکورد جدید به دیتابیس مراحل زیر را دنبال کنید:

  • ایجاد یک نمونه جدید از مدل: تصور کنید مدل شما مانند یک قالب عمل می‌کند. با ایجاد یک نمونه جدید از مدل، در واقع فضایی برای ثبت اطلاعات جدید در بانک اطلاعاتی فراهم می‌کنید.
  • تنظیم مقادیر برای ویژگی‌های مدل: حالا نوبت به تکمیل اطلاعات است. ویژگی‌های مدل همانند ستون‌های یک جدول در بانک اطلاعاتی عمل می‌کنند. با استفاده از داده‌های دریافتی از کاربر (مثلا از طریق فرم)، مقادیر مربوطه را به هر ویژگی مدل اختصاص دهید.
  • ذخیره اطلاعات: پس از تنظیم مقادیر برای ویژگی‌های مدل، فقط یک مرحله نهایی باقی مانده است. با فراخوانی متد save، اطلاعات جدید به‌طور خودکار در بانک اطلاعاتی ذخیره می‌شوند.

به مثال زیر دقت کنید که به‌سادگی روند اضافه کردن یک رکورد جدید به مدل Flight را نشان می‌دهد:

 

<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Flight;
use Illuminate\Http\Request;
class FlightController extends Controller
{
    /**
     * Create a new flight instance.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate the request...
        $flight = new Flight;
        $flight->name = $request->name;
        $flight->save();
    }
}

 

در مثال بالا، مقدار پارامتر name که ازطریق درخواست ارسالی (احتمالا از یک فرم) دریافت شده، به فیلد name در نمونه مدل Flight اختصاص می‌دهیم. سپس با فراخوانی متد save، یک رکورد جدید با این اطلاعات در بانک اطلاعاتی ایجاد می‌شود. جالب است بدانید زمان ایجاد و به‌روزرسانی رکورد (created_at و updated_at) به‌صورت خودکار مدیریت می‌شوند و نیازی به تنظیم دستی آن‌ها نیست.

به‌ روزرسانی داده‌ ها در مدل‌

علاوه‌بر ایجاد داده‌های جدید، متد save برای به‌روزرسانی اطلاعات موجود در دیتابیس هم کاربرد دارد. برای این کار، ابتدا باید مدل موردنظر را با استفاده از متد find پیدا کنید، سپس مقادیر فیلدهایی را که می‌خواهید تغییر دهید، به‌روزرسانی کنید. درنهایت، با فراخوانی مجدد متد save تغییرات را ذخیره کنید.

فرض کنید می‌خواهیم نام یک پرواز را در مدل Flight به‌روزرسانی کنیم. مراحل به‌صورت زیر است:

  • با استفاده از App\Flight::find(1) پرواز با شناسه ۱ رو پیدا می‌کنیم.
  • مقدار فیلد name رو به «New Flight Name» تغییر می‌دهیم.
  • با فراخوانی $flight->save() تغییرات را ذخیره می‌کنیم.
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();

 

به‌ روزرسانی‌ های یک‌ جا در Eloquent۶

علاوه‌بر به‌روزرسانی تک‌تک مدل‌ها، Eloquent در لاراول به شما این امکان را می‌دهد تا تعداد زیادی از مدل‌ها را که با یک کوئری خاص مطابقت دارند، به‌روزرسانی کنید.

به عنوان مثال، فرض کنید می‌خواهیم تمام پروازهای فعال با مقصد سن‌دیگو را با تاخیر علامت‌گذاری کنیم. با استفاده از Eloquent به‌سادگی می‌توانیم این کار را انجام دهیم:

 

App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]); 

 

همانطور که مشاهده می‌کنید، متد update انتظار دریافت یک آرایه از جفت‌های ستون و مقدار را دارد. این آرایه مشخص می‌کند که کدام ستون‌ها و با چه مقادیری باید به‌روز شوند.

درنظر داشته باشید هنگام انجام به‌روزرسانی دسته‌جمعی در Eloquent رویدادهای مربوط به ذخیره‌سازی مدل‌ها (saving, saved, updating, updated) برای مدل‌های به‌روزرسانی‌شده اجرا نمی‌شوند. زیرا در این روش، مدل‌ها به‌صورت جداگانه فراخوانده نمی‌شوند، بلکه کل عملیات به‌صورت یکجا روی پایگاه داده انجام می‌شود.

حذف داده‌ ها در مدل‌ ها 

برای حذف داده‌های مدل، کافی‌است از متد delete استفاده کنید:

 

$flight = App\Flight::find(1);
$flight->delete();

 

کوئری های پیشرفته با Eloquent

Eloquent قابلیتی فوق‌العاده به نام ساب‌کوئری (Subquery) در اختیار شما قرار می‌دهد که به کمک آن می‌توانید اطلاعاتی را از جداول مرتبط، تنها با یک کوئری بیرون بکشید.

فرض کنید جدولی از «مقصدهای پرواز یا destinations» و جدولی از «پروازها یا flights به مقصدها» دارید. جدول پروازها ستونی به نام «arrived_at» است که نشان می‌دهد پرواز در چه زمانی به مقصد رسیده است. با استفاده از قابلیت ساب‌کوئری در متدهای select و addSelect، می‌توانیم تمام مقاصد و نام آخرین پروازی را که به مقصد رسیده، فقط با یک کوئری به‌دست بیاوریم:

 

use App\Destination;
use App\Flight;
return Destination::addSelect(['last_flight' => Flight::select('name')
    ->whereColumn('destination_id', 'destinations.id')
    ->orderBy('arrived_at', 'desc')
    ->limit(1)
])->get();

 

مرتب‌ سازی داده‌ ها براساس Subquery

فرض کنید می‌خواهیم لیستی از تمام مقصدهای پرواز را تهیه کنیم، اما به ترتیب زمانی که آخرین پرواز به هر مقصد رسیده است. با استفاده از قابلیت مرتب‌سازی براساس ساب‌کوئری (Subquery Ordering) می‌توانیم این کار را فقط با یک کوئری ساده به پایگاه داده انجام دهیم.

در این روش، یک Subquery تعریف می‌کنیم که آخرین زمان رسیدن پرواز به هر مقصد را پیدا می‌کند. سپس، براساس این زمان، کل لیست مقصدها را مرتب می‌کنیم. به‌عنوان مثال، کد زیر لیست مقصدها را براساس آخرین زمان رسیدن پرواز (از جدیدترین به قدیمی‌ترین) برمی‌گرداند:

 

return Destination::orderByDesc(
    Flight::select('arrived_at')
        ->whereColumn('destination_id', 'destinations.id')
        ->orderBy('arrived_at', 'desc')
        ->limit(1)
)->get();

 

با استفاده از این قابلیت قدرتمند، می‌توانیم بدون نیاز به اجرای چندین کوئری مجزا، داده‌ها را براساس نتایج حاصل از یک زیرمجموعه مرتب‌ کنیم. این کار باعث بهبود کارایی و خوانایی کد می‌شود.

روابط در Eloquent

در دنیای دیتابیس‌ها، جداول معمولا با هم ارتباط دارند. مثلا، یک پست وبلاگ ممکن است چندین کامنت داشته باشد، یا یک سفارش به کاربری که آن را ثبت کرده، مرتبط است. Laravel به لطف قابلیت جذاب «Eloquent»، مدیریت و کار با این روابط را برای شما آسون می‌کند. لاراول از انواع مختلفی از روابط بین جداول پشتیبانی می‌کند و به شما اجازه می‌دهد به شکل بهینه‌ با داده‌های خود کار کنید. این روابط شامل موارد زیر هستند:

  • یک به یک (One To One): هر ردیف در یک جدول فقط به یک ردیف خاص در جدول دیگر مرتبط است.
  • یک به چند (One To Many): یک ردیف در یک جدول به چندین ردیف در جدول دیگر مرتبط است.
  • چند به چند (Many To Many): چندین ردیف در یک جدول به چندین ردیف در جدول دیگر مرتبط هستند .
  • روابط ازطریق واسطه (Has Many Through): دو تا جدول که به‌طور مستقیم با هم ارتباط ندارند، ازطریق یک جدول واسطه می‌توانند با هم ارتباط برقرار کنند.
  • روابط چندشکلی (Polymorphic Relations): این نوع روابط انعطاف‌پذیری بیشتری را برای ارتباط دادن مدل‌ها با هم، صرف‌نظر از نوع خاص آن‌ها فراهم می‌کند.

با استفاده از این روابط، می‌توانید ساختار پایگاه داده را سازماندهی کنید، به اطلاعات دسترسی راحت‌تری داشته باشید و در نهایت، برنامه‌های کاربردی پیچیده‌تر و کارآمدتری بسازید.

One To One

فرض کنید هر کاربر (User) فقط می‌تواند یک شماره تلفن (Phone) داشته باشد. Eloquent در لاراول این ارتباط را به‌سادگی تعریف می‌کند.

 

class User extends Model {
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

 

در این کد، با استفاده از متد hasOne ارتباط یک‌به‌یک بین مدل کاربر و مدل شماره تلفن تعریف می‌شود. آرگومان اول، نام کامل مدل مرتبط (در اینجا Phone) است.

پس از تعریف ارتباط، می‌توانیم به‌راحتی با استفاده از خصوصیات پویای Eloquent در لاراول، به اطلاعات مرتبط دسترسی پیدا کنیم. برای مثال، برای به‌دست آوردن شماره تلفن کاربری با شناسه ۱، کد زیر را می‌نویسیم:

 

$phone = User::find(1)->phone;

 

این کد به صورت زیر ترجمه می‌شود:

 

select * from users where id = 1
select * from phones where user_id = 1

 

به‌طور پیش‌فرض، Eloquent در لاراول نام مدل (در اینجا Phone) را برای تشخیص کلید خارجی (foreign key) درنظر می‌گیرد. یعنی Eloquent فرض می‌کند در جدول Phone یک ستون با نام user_id وجود دارد که کاربر مربوطه را مشخص می‌کند.

در‌صورتی‌که نام foreign key در جدول شما متفاوت است، با ارسال آرگومان دوم به متد hasOne می‌توانید آن را اصلاح کنید. همچنین آرگومان سوم، امکان تعیین ستون محلی (local key) در مدل User را فراهم می‌کند که برای ارتباط استفاده می‌شود.

 

return $this->hasOne('App\Phone', 'foreign_key');
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

 

برای تعریف رابطه معکوس روی مدل Phone، از متد belongsTo استفاده می‌کنیم:

 

class Phone extends Model {
    public function user()
    {
        return $this->belongsTo('App\User');
    }

 

در این مثال، Eloquent به دنبال ستون user_id در جدول phones می‌گردد. اگر نام کلید خارجی در جدول شما متفاوت است، می‌توانید آن را به عنوان آرگومان دوم به متد belongsTo ارسال کنید.

 

class Phone extends Model {
    public function user()
    {
        return $this->belongsTo('App\User', 'local_key');
    }
}

 

علاوه‌ بر این، امکان ارسال آرگومان سوم برای تعیین نام ستون مرتبط در جدول User (جدول والد) وجود دارد.

 

class Phone extends Model {
    public function user()
    {
        return $this->belongsTo('App\User', 'local_key', 'parent_key');
    }
}

 

One To Many

فرض کنید یک پست وبلاگ دارید که قابلیت کامنت گذاشتن دارد. در این مثال، یک پست ممکن است «چندین» کامنت داشته باشد. این نوع ارتباط را می‌توانیم به‌صورت «یکی به چند» (One-to-Many) در PHP مدل‌سازی کنیم.

 

class Post extends Model {
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }
}

 

با این کار، به‌سادگی می‌توانیم به کامنت‌های یک پست خاص ازطریق یک ویژگی پویا (dynamic property) دسترسی پیدا کنیم. کافی‌است شناسه‌ (ID) پست را داشته باشیم و از این دستور استفاده کنیم:

 

$comments = Post::find(1)->comments;

 

با اجرای این کد، لیستی از تمام کامنت‌های مربوط به پستی که شناسه‌ ۱ دارد، دریافت می‌کنیم. 

اگر بخواهیم کامنت‌های دریافتی را براساس یک معیار خاص فیلتر کنیم، با استفاده از متد comments و زنجیره‌وار کردن شروط، می‌توانیم کامنت‌های مورد نظر را پیدا کنیم: 

 

$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();

 

به‌طور پیش‌فرض، لاراول از یک ستون خاص برای مدیریت ارتباطات «یکی به چند» استفاده می‌کند. اگر بخواهیم از یک ستون دیگر استفاده کنیم، آن را می‌توانیم به عنوان آرگومان دوم به تابع hasMany دهیم. همچنین، می‌توانیم ستونی را که در کلاس «پست» برای این ارتباط استفاده می‌شود، تغییر دهیم. برای این کار، سه آرگومان به تابع hasMany می‌دهیم.

 

$this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');

 

در این بخش، نحوه تعریف معکوس رابطه در مدل Comment را با استفاده از روش belongsTo بررسی می‌کنیم:

 

class Comment extends Model {
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

 

Many To Many

فرض کنید در یک سیستم، کاربران می‌توانند نقش‌های مختلفی داشته باشند. هر نقشی هم ممکن است به چندین کاربر اختصاص داده شود. برای نمونه، نقش «مدیر» را می‌توان به چند کاربر مختلف اختصاص داد. برای مدیریت چنین ارتباطی در پایگاه داده، به سه جدول نیاز داریم:

۱. جدول کاربران (users)

۲. جدول نقش‌ها (roles)

۳. جدول واسط (role_user)

جدول واسط با ترکیب نام مدل‌های مرتبط به ترتیب حروف الفبا (در این مثال role_user) ساخته می‌شود و شامل دو ستون با عناوین «شناسه کاربر» (user_id) و «شناسه نقش» (role_id) است. برای تعریف ارتباط چندبه‌چند در فریم‌ورک‌های نرم‌افزاری، از متدهایی مانند belongsToMany استفاده می‌کنیم. در اینجا یک نمونه با زبان PHP خواهید دید:

 

class User extends Model {
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }

}

 

با استفاده از این کد، می‌توانیم نقش‌های مرتبط با یک کاربر خاص را به‌راحتی بازیابی کنیم:

 

$roles = User::find(1)->roles;

 

در این مثال، User::find(1) کاربر با شناسه‌ ۱ را از جدول کاربران بازیابی می‌کند. سپس با استفاده از متد roles نقش‌های مرتبط با آن کاربر را به دست می‌آوریم.

این قابلیت، انعطاف‌پذیری بالایی دارد. اگر نام دلخواهی برای جدول واسط خود درنظر دارید، آن را می‌توانید به عنوان آرگومان دوم به متد belongsToMany دهید. 

 

return $this->belongsToMany('App\Role', 'user_roles');

 

همچنین، امکان تغییر ستون‌های کلیدی پیش‌فرض نیز وجود دارد.

 

return $this->belongsToMany('App\Role', 'user_roles', 'user_id', 'foo_id');

 

شما می‌توانید رابطه‌ معکوس را هم روی مدل نقش تعریف کنید:

 

class Role extends Model {
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

 

Has_many Through

گاهی اوقات می‌خواهیم به اطلاعاتی که به‌طور مستقیم به هم مرتبط نیستند، دسترسی پیدا کنیم. تصور کنید در یک سیستم اطلاعاتی، مدل «کشور» (Country) وجود دارد که به مدل «پست» (Post) به‌طور مستقیم ارتباط ندارد. برای پیدا کردن ارتباط میان آن‌ها می‌توانیم بگوییم معمولا پست‌ها توسط کاربران (User) نوشته می‌شوند و کاربران هم در کشورهایی زندگی می‌کنند.

اینجاست که رابطه‌ (Has Many Through) به کمک ما می‌آید. این رابطه یک میانبر عالی برای دسترسی به اطلاعات مرتبط از طریق یک مدل واسطه است.

 

countries
    id - integer
    name - string
users
    id - integer
    country_id - integer
    name - string
posts
    id - integer
    user_id - integer
    title - string

 

به مثال بالا برگردیم. با اینکه جدول «پست» ستونی به نام (country_id) ندارد، رابطه‌ Has Many Through به ما این امکان را می‌دهد تا با استفاده از دستور $country->posts به همه‌ پست‌های مرتبط با یک کشور خاص دسترسی پیدا کنیم.

برای تعریف این رابطه در کد، به سراغ مدل (Country) می‌رویم:

 

class Country extends Model {
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User');
    }
}

 

Polymorphic Relations

اگر بخواهیم با مدل‌های دیگر از انواع مختلف ارتباط برقرار کنیم، روابط چندشکلی یا Polymorphic به کمکمان می‌آید.

فرض کنید یک مدل عکس (Photo) داریم که می‌خواهیم با دو مدل دیگر یعنی مدل کارمند (Staff) و مدل سفارش (Order) ارتباط داشته باشد. به بیان دیگر، هر عکس متعلق به یک کارمند خاص یا یک سفارش خاص باشد. برای تعریف این ارتباط پویا Eloquent در لاراول، سراغ روابط چندشکلی می‌رویم. در اینجا مثالی از نحوه‌ پیاده‌سازی آن را مشاهده می‌کنید:

 

class Photo extends Model {
    public function imageable()
    {
        return $this->morphTo();
    }
}
class Staff extends Model {
    public function photos()
    {
        return $this->morphMany('App\Photo', 'imageable');
    }
}
class Order extends Model {
    public function photos()
    {
        return $this->morphMany('App\Photo', 'imageable');
    }
}

 

استفاده از Mutators و Accessors

Eloquent در لاراول قابلیتی جذاب برای Laravel ارائه می‌کند و به شما امکان می‌دهد کنترل بیشتری روی اطلاعات مدل‌ها داشته باشید. با استفاده از این قابلیت می‌توانید نحوه‌ نمایش یا حتی ذخیره‌سازی اطلاعات را تغییر دهید.

تعریف Accessors

فرض کنید می‌خواهید اسم کوچک کاربران را همیشه با حرف بزرگ نمایش دهید. کافی‌است روی مدل کاربرتان یک متد به اسم getFirstNameAttribute تعریف کنید. جادوی کار همین است که اسم این متد باید با حروف بزرگ شروع شود. (camelCase) حتی اگر اسم ستون در دیتابیس با حروف کوچک و خط تیره نوشته شده باشد (snake_case).

مثلا ببینید در کد زیر چگونه می‌توانید اسم کوچک را همیشه با حرف بزرگ نمایش دهید:

 

class User extends Model {
    public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }
}

 

تعریف Mutators

Mutatorها به روشی مشابه Accessorها در Laravel تعریف می‌شوند. برای نمونه، فرض کنید می‌خواهیم نام کوچک یک کاربر را به حروف کوچک تبدیل کنیم. برای این کار، می‌توانیم از یک Mutator به‌شکل زیر استفاده کنیم:

 

class User extends Model {
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = strtolower($value);
    }
}

 

در این کد، متغیر Mutator setFirstNameAttribute نام دارد و وظیفه‌اش تبدیل نام کوچک کاربر به حروف کوچک قبل از ذخیره‌سازی آن در پایگاه داده است.

Eager Loading و Lazy  Loading

تا به حال برایتان پیش آمده در برنامه‌ بخواهید اطلاعات کتاب‌ها و نویسنده‌هایشان را نمایش دهید، اما با حجم زیادی از کوئری‌های پایگاه داده مواجه شوید؟ اینجاست که Eager Loading به کمک شما می‌آید.

Eager Loading راه‌حلی کارآمد برای رفع مشکل کوئری‌های N+1 در Laravel است. فرض کنید مدلی به نام Book داریم که با مدل Author مرتبط است. این رابطه به شکل زیر تعریف می‌شود:

 

class Book extends Model {
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

 

حالا کد زیر را در نظر بگیرید:

 

foreach (Book::all() as $book)
{
    echo $book->author->name;
}

 

این حلقه برای بازیابی تمام کتاب‌های موجود در جدول، یک کوئری اجرا می‌کند و سپس برای بازیابی نویسنده‌ هر کتاب، کوئری دیگری می‌فرستد. بنابراین، اگر ۲۵ کتاب داشته باشیم، این حلقه ۲۵+۱ کوئری اجرا خواهد کرد.

خوشبختانه، می‌توانیم با استفاده از Eager Loading، تعداد کوئری‌ها را به‌طور چشمگیری کاهش دهیم. روابطی که باید با Eager Loading دریافت شوند، از طریق متد with مشخص می‌شوند:

 

foreach (Book::with('author')->get() as $book)
{
    echo $book->author->name;
}

 

در حلقه‌ بالا، فقط دو کوئری اجرا می‌شود:

 

select * from books
select * from authors where id in (1, 2, 3, 4, 5, …)

 

استفاده‌ هوشمندانه از Eager Loading عملکرد برنامه‌ شما را به‌طور چشمگیری بهبود می‌بخشد. البته، شما می‌توانید همزمان چندین رابطه را با Eager Loading دریافت کنید:

 

$books = Book::with('author', 'publisher')->get();

 

حتی می‌توانید روابط تودرتو را نیز با Eager Loading دریافت کنید:

 

$books = Book::with('author.contacts')->get();

 

در مثال بالا، رابطه‌ نویسنده با Eager Loading دریافت می‌شود و همچنین رابطه‌ مخاطبین نویسنده نیز بارگذاری می‌شود.

Eager Loading با محدودیت در Laravel

ممکن است در عین حال که از Eager Loading استفاده می‌کنید، شرایط خاصی را بخواهید برای روابط اعمال کنید. به بیان دیگر، می‌خواهید فقط بخش خاصی از روابط را به همراه مدل اصلی بازیابی کنید. مثال زیر را ببینید:

 

$users = User::with(['posts' => function($query)
{
    $query->where('title', 'like', '%first%');
}])->get();

 

در این مثال، ما در حال Eager Loading  پست‌های کاربر هستیم، اما فقط درصورتی‌که عنوان پست حاوی کلمه (first) باشد. به‌عبارت‌دیگر، با اعمال این محدودیت، فقط پست‌های خاصی از کاربر همراه با اطلاعات کاربر بازیابی می‌شوند. البته، محدودیت‌های Eager Loading فقط به اعمال شرایط (where) محدود نمی‌شوند. شما همچنین می‌توانید عملیات مرتب‌سازی را روی روابط اعمال کنید:

 

$users = User::with(['posts' => function($query)
{
    $query->orderBy('created_at', 'desc');
}])->get();

 

بهینه سازی عملکرد با Lazy Eager Loading

گاهی اوقات نیاز دارید تا اطلاعات مرتبط با یک رکورد (داده‌ یک ردیف در جدول) را همزمان با فراخوانی آن رکورد، به‌دست بیاورید. این کار باعث صرفه‌جویی در زمان و بهبود کارایی برنامه می‌شود. اما همیشه لزومی به فراخوانی همه‌ داده‌های مرتبط نیست. اینجاست که Lazy Eager Loading به کمکتان می‌اید. Lazy Eager Loading روشی است که به شما این امکان را می‌دهد تا به‌صورت هوشمندانه تصمیم بگیرید چه اطلاعات مرتبطی را به همراه رکورد اصلی بارگذاری کنید.

فرض کنید می‌خواهیم لیستی از کتاب‌ها را نمایش دهیم. در کنار هر کتاب، اطلاعات نویسنده و ناشر آن هم باید نمایش داده شود. با استفاده از بارگذاری Lazy Eager می‌توانیم به جای اینکه برای هر کتاب یک درخواست جداگانه به پایگاه داده ارسال کنیم، ابتدا لیست کتاب‌ها را به همراه اطلاعات نویسنده و ناشر آن‌ها در یک درخواست واحد، فراخوانی کنیم.

 

$books = Book::all();
$books->load('author', 'publisher');

 

علاوه‌براین، می‌توانید با استفاده از یک قطعه کد (Closure) محدودیت‌هایی را برای کوئری مرتبط تعیین کنید. به عنوان مثال، می‌توان نویسندگان را براساس تاریخ انتشار مرتب کنید:

 

$books->load(['author' => function($query)
{
    $query->orderBy('published_date', 'asc');
}]);

 

با استفاده از این تکنیک Eloquent در لاراول می‌توانید ضمن حفظ کارایی برنامه، مدیریت بهتری بر داده‌های مرتبط داشته باشید و فقط اطلاعاتی را دریافت کنید که واقعا به آن‌ها نیاز دارید.

جمع بندی: Eloquent در لاراول ، ابزار قدرتمند شما در دنیای Laravel

Eloquent در لاراول به شما امکان می‌دهد با دیتابیس خود به روش شیءگرا، کارآمد و لذت‌بخش تعامل داشته باشید. به کمک Eloquent می‌توانید:

  • مدل‌های داده خود را به‌راحتی تعریف و مدیریت کنید
  • کوئری‌های پیچیده را با چند خط کد انجام دهید
  • روابط بین مدل‌ها را به‌طور موثر برقرار کنید. 

با استفاده از تکنیک‌های معرفی شده در این مقاله، می‌توانید عملکرد Eloquent را به‌طور قابل توجهی ارتقا دهید و برنامه‌های Laravel خود را به سطحی جدید از سرعت و کارایی برسانید.

چه رتبه ای می‌دهید؟

میانگین ۰ / ۵. از مجموع ۰

اولین نفر باش

title sign
معرفی نویسنده
تیم فنی نیک آموز
مقالات
366 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
تیم فنی نیک آموز
title sign
دیدگاه کاربران