پرش به محتوای اصلی
مفاهیم شبکه

آموزش laravel eloquent با مثال

Ali Majidi Ali Majidi — دقیقه مطالعه ۹,۷۴۸ بازدید
آموزش laravel eloquent با مثال
همیشه برای برنامه نویسان ایجاد ارتباط بین یک برنامه و Database آن کمی دردسر ساز بوده است. فریم ورک لاراول نسبت به سایر رقبای خود، همان طور که در مقاله "فریم ورک لاراول چیست" گفتیم، یک ویژگی منحصر به فرد یعنی Eloquent ORM دارد. با بهره گیری از قابلیت laravel eloquent ، ایجاد ارتباط بین هر برنامه ای با Database مربوط به آن، تنها چند ثانیه زمان می برد. [note] اگر شما هم به فریم ورک لاراول علاقه مندید و تمایل دارید از این فریم ورک کسب درآمد کنید پیشنهاد میکنیم در دوره آموزش لاراول شرکت نمایید و از مزایای پشتیبانی دوره بهره مند شوید. [/note] eloquent چیست

نحوه کارکرد laravel eloquent

هر کدام از جدول های Database با Model هایی نظیر آن در برنامه ارتباط برقرار می کند. به طور مثال اگر ما در Database یک جدول به نام Flights بسازیم، برای ایجاد ارتباط بین برنامه ی خود و این Database، کافی است یک Model به نام Flight بسازیم. در این صورت به طور خودکار برنامه بین جدول Flights از Database و Model نظیر آن، یعنی Flight یک ارتباط ایجاد می کند. با استفاده از این Model ها می توانیم تمام Query هایی که می خواهیم را بر روی جدول هایمان اعمال کنیم.

ساخت و سفارشی سازی Model

همان طور که گفتیم برای ایجاد ارتباط با جدول های Database لازم است برای هر کدام از از جدول های موجود در Database یک Model بسازیم.

ساخت Model

Model ها به صورت پیش فرض در پوشه app قرار دارند و اگر Model جدیدی توسط دستور artisan ایجاد کنیم، به طور خودکار در این پوشه قرار می گیرد. البته شما می توانید که این Model ها را در پوشه دیگری نیز قرار دهید. ساده ترین راه ایجاد یک Model، استفاده از دستور make:model در Artisan می باشد.
php artisan make:model Flight
دستور بالا یک Model به نام Flight در همان پوشه ی پیش فرض، یعنی app ایجاد می کند. اگر می خواهید هم زمان با ساخت Model، یک Migration به Database آن ایجاد کنید، به جای دستور بالا از یکی از دستورات زیر استفاده کنید.
php artisan make:model Flight --migration

php artisan make:model Flight -m

سفارشی سازی Model

پس از ساخت Model، امکان دارد که نتوانید به صورت صحیح با Database ارتباط برقرار کنید و به یک سری از خطاها برخورد کنید. در لاراول و Model های آن به طور مثال id ،Primary Key در نظر گرفته می شود، حال اگر به جای id در Flight Number ،Database داشته باشیم، لاراول به صورت خودکار نمی تواند آن را شناسایی کند. بنابراین لازم است پس از ساخت Model برخی از تغییرات را در آن اعمال کنیم. به طور مثال در این جا Flight Model را مشاهده می کنید.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    //
}

نام جدول

همان طور که مشاهده می کنید، ما به Model نگفته ایم که به کدام جدول از Database دسترسی داشته باشد یا با داده های آن ارتباط برقرار کند. در این جا نیز مانند همیشه با یکی از مزایای لاراول روبرو می شویم. در لاراول تمام Model ها از یک قرارداد خاصی پیروی می کنند که اگر این قرارداد را به صورت کاملا ساده بخواهیم بررسی کنیم، به این شکل است که تمام Model ها به صورت پیش فرض یک ارتباط با جدولی از Database ایجاد می کنند، که نام آن جدول مانند نام Class در Model ما یا به زبان ساده تر نام Model ما باشد. به طور مثال در دستور بالا نام Class ما در Flight ,Model است، پس به صورت پیش فرض Model ما با جدول Flights در Database یک ارتباط برقرار می کند. حال اگر به جای جدول Flights یک جدول به نام My_Flights داشته باشیم، دیگر این ارتباط به صورت خودکار برقرار نمی شود و لازم است تا Model را سفارشی سازی کنیم. برای این کار می توانیم مانند دستور زیر عمل کنیم.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'My_Fflights';
}

Primary Keys

همان طور که گفتیم، laravel eloquent به صورت پیش فرص Primary Key را id در نظر می گیرد. اگر بخواهیم Primary Key را عوض کنیم، از دستور زیر استفاده می کنیم.
<?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';
}
هم چنین به صورت پیش فرض نوع Primary Key یک Integer با روند صعودی در نظر گرفته می شود. اگر بخواهید که نوع آن Integer نباشد، می توانید از دستور زیر استفاده کنید و به طور مثال نوع آن را به String تغییر دهید.
<?php

class Flight extends Model
{
    /**
     * The "type" of the auto-incrementing ID.
     *
     * @var string
     */
    protected $keyType = 'string';
}
اگر بخواهید که Primary Key روند صعودی نداشته باشد، کافی است incrementing$ را به صورت زیر false کنید.
<?php

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

Timestamps

به صورت پیش فرض laravel eloquent انتظار دارد که دو ستون با نام های created_at و updated_at درون جدول Database وجود داشته باشد که به صورت خودکار هنگام ساخت یک داده، ستون created_at و هنگام بروزرسانی و تغییر آن، ستون updated_at مقدار زمانی را می گیرد و ذخیره می کند. اگر بخواهیم این ستون ها در جدول ما وجود نداشته باشد، باید 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;
}
اگر می خواهید که این ستون ها، مقدار زمانی را با Format دلخواه شما ذخیره کنند، می توانید از دستور زیر استفاده کنید.
<?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';
}
هم چنین اگر بخواهید نام این ستون ها را تغییر دهید، باید از دستور زیر استفاده کنید.
<?php

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

ارتباط با Database

به طور پیش فرض تمام Model ها به Database یا پایگاه داده ای که در تنظیمات برنامه خود وارد کرده ایم متصل می شود. حال اگر بخواهیم یکی از این Model ها به یک Database دیگر متصل شود، از دستور زیر استفاده می کنیم.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The connection name for the model.
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

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

اگر بخواهید برای Attribute ها، یک مقدار پیش فرض در نظر بگیریم، از دستور زیر استفاده می کنیم.
<?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,
    ];
}
در دستور بالا می توانیم مقدار پیش فرض هر تعداد دیگر Attribute را در آرایه attributes$ وارد کنیم.

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

زمانی که یک Model را ساختیم و متناظر با Database آن تغییرات مورد نیازی که در بالا گفتیم را بر روی آن اعمال کردیم. می توانیم داده های دل خواهمان را از آن دریافت کنیم. به طور مثال به دستور زیر توجه کنید:
<?php

$flights = App\Flight::all();

foreach ($flights as $flight) {
    echo $flight->name;
}
در این دستور ابتدا از مدل Fight تمام داده ها را گرفتیم. سپس توسط حلقه foreach، اسم تمام آن ها را echo کردیم. همان طور که در بالا دیدید، اگر از ()all استفاده کنیم، تمام داده ها در اختیار ما قرار می گیرند. اما اگر تمام آن ها را نخواهیم و تنها به تعدادی از آن ها با یک شرط خاص نیاز داشته باشیم، می توانیم از where استفاده کنیم.
$flights = App\Flight::where('active', 1)
      ->orderBy('name', 'desc')
      ->take(10)
      ->get();

Refresh کردن Model

با استفاده از دستورات fresh یا refresh می توانیم Model ها را دوباره مرتب کنیم و داده های Database مربوط به آن را دوباره دریافت کنیم. به طور دقیق تر با استفاده از ()fresh، داده ها از Model پس از یک refresh سریع، دریافت می شود.
$flight = App\Flight::where('number', 'FR 900')->first();
$freshFlight = $flight->fresh();
هم چنین همان طور که در دستور زیر آمده است، پس از تغییر یک داده Database می توانیم مانند همان دستور بالا، از دستور ()refresh نیز استفاده کنیم.
$flight = App\Flight::where('number', 'FR 900')->first();

$flight->number = 'FR 456';

$flight->refresh();

$flight->number; // "FR 900"

Collection ها

هنگام دریافت داده ها می توانیم از Collection های مختلف موجود در لاراول نیز استفاده کنیم. به طور مثال فرض کنید می خواهید تمام داده در یک آرایه دریافت شوند، که این آرایه دارای چند Index و هر کدام از این Index ها، دارای ۲۰۰ مقدار یا Value باشد، یا به عبارتی دیگر، به طور مثال اگر ۱۱۵۰ داده بخواهد دریافت شود و بخواهیم آن ها را در بخش های ۲۰۰ تایی قرار دهیم، کافی است از Chunk Collection استفاده کنیم.
Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});
اگر داده های ما ۱۰۰۰ تا باشد، آن داده ها به صورت دقيق در ۵ دسته یا Index قرار می گیرند. حال اگر مانند مثال بالا ۱۱۵۰ داده داشته باشیم، ۵ Index که هر کدام ۲۰۰ مقدار یا Value دارند و ۱ Index که ۱۵۰ مقدار دارد، دریافت می شود. در دستور بالا ما داده ها را در بخش های ۲۰۰ تایی دریافت می کنیم و بر روی هر کدام از آن ها توسط حلقه foreach می توانیم یک عمل انجام دهیم.

Query های پیشرفته

هنگام استفاده از laravel eloquent می توانیم Query های پیشرفته ای به سمت Database ارسال کنیم. به طور مثال فرض کنید که ما یک جدول برای مقصد پروازهایمان به نام destinations و یک جدول برای خود پروازهایمان به نام flights داریم. هم چنین فرض کنید در جدول flights یک ستون به نام arrived_at داریم که زمانی را نشان می دهد که پرواز به مقصد رسید. حال می توانیم تمام دستوراتی که در ادامه به آن ها می پردازیم را بر روی این داده ها اعمال کنیم.

انتخاب داده ها

فرض کنید می خواهید تمام مقصد ها را از جدول destinations دریافت کنید و آن پرواز هایی که به تازگی به مقصد رسیده اند را نشان دهید. برای این کار می توانیم از ()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')
])->get();

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

فرض کنید می خواهید تمام مقصد ها را به ترتيب تاریخ رسیدنشان، به صورت صعودی مرتب کنیم. برای این کار باید از جدول flight که پرواز ها را نشان می دهد، تمام پرواز ها را به ترتیب زمان رسیدنشان دریافت کنیم و آن ها را به جدول destination ارسال کنیم، سپس تمام داده هایی که در جدول destination قرار می گیرد را به صورت صعودی، توسط orderByDesc می توانیم نشان دهیم.
return Destination::orderByDesc(
    Flight::select('arrived_at')
        ->whereColumn('destination_id', 'destinations.id')
        ->orderBy('arrived_at', 'desc')
        ->limit(1)
)->get();

دریافت یک داده از Database

گاهی اوقات به جای دریافت همه یا چند داده، تنها یکی از آن ها را می خواهیم دریافت کنیم. برای دریافت یک داده می توانیم از first ،firstWhere و find استفاده کنیم. به مثال های زیر توجه کنید:
// Retrieve a model by its primary key...
$flight = App\Flight::find(1);
دستور بالا داده ای را برمی گرداند که id یا Primary Key آن برابر با 1 است.
$flights = App\Flight::find([1, 2, 3]);
این دستور همانند دستور اول است با این تفاوت که علاوه بر دریافت داده ای که id یا Primary Key آن برابر با 1 است، داده هایی که Primary Key آن ها برابر با 2 و 3 هست را نیز بر می گرداند.
// Retrieve the first model matching the query constraints...
$flight = App\Flight::where('active', 1)->first();
دستور بالا تمام داده هایی که ستون active آن برابر با 1 باشد را دریافت می کند و توسط ()first اولین داده را نشان می دهد.
// Shorthand for retrieving the first model matching the query constraints...
$flight = App\Flight::firstWhere('active', 1);
این دستور، کوتاه شده ی دستور سوم یعنی استفاده از ()first است. حال امکان دارد داده ای با مشخصاتی که وارد کردیم وجود نداشته باشد. در این صورت اگر بخواهیم هنگامی که این اتفاق افتاد، یک داده ی دیگر، یک متن یا هر چیز دیگری نمایش داده شود، می توانیم از firstOr استفاده کنیم.
$model = App\Flight::where('legs', '>', 100)->firstOr(function () {
        // ...
});
درون تابعی که در firstOr قرار دارد، می توانیم هر Query قرار دهیم تا در صورتی که در جدول Flights هیچ داده ای با legs بزرگتر از ۱۰۰ وجود نداشت، آن Query اجرا شود. هم چنین firstOr می تواند یک آرایه دریافت کند تا بر روی تمام Index های آن آرایه، یک Query اجرا کند.
$model = App\Flight::where('legs', '>', 100)
            ->firstOr(['id', 'legs'], function () {
                // ...
            });

نمایش Exception

اگر بخواهیم در صورت پیدا نشدن Model، یک exception یا یک Error به کاربر نشان دهیم، می توانیم از findOrFail و firstOrFail استفاده کنیم.
$model = App\Flight::findOrFail(1);

$model = App\Flight::where('legs', '>', 100)->firstOrFail();
اگر در دستورات بالا Model پیدا نشود، برای کاربر یک Error 404 نمایش داده می شود.

Collection های عددی

هنگامی که داده ها را از Database، توسط Model دریافت می کنیم می توانیم به جای دریافت به طور مثال نام داده ها، تعداد آن ها، بزرگترین داده یا جمع داده ها را دریافت کنیم. برای همین می تواینم از count ,sum و max استفاده کنیم.
$count = App\Flight::where('active', 1)->count();

$max = App\Flight::where('active', 1)->max('price');
از count برای دریافت تعداد داده ها، max برای دریافت بزرگترین داده و sum برای دریافت جمع داده ها استفاده می کنیم.

اضافه کردن داده ها به Database توسط Model

برای ایجاد یک داده جدید در Database، می توانیم آن داده را در Model ایجاد کنیم و سپس توسط ()save آن را در Database ذخیره نماییم.
<?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();
    }
}
در دستور بالا ابتدا یک متغیر به نام flight ایجاد می کنیم. سپس name را از طریق Http Request کاربر دریافت می کنیم و آن را برابر با نام متغیر flight قرار می دهیم. حال توسط ()save این درخواست به Database ارسال شده و در ستون name پایگاه داده (Database) ذخیره می شود.
در صورتی که timestamps$ را false نکرده باشیم، پس از ()save یک داده در Database، به طور خودکار ستون های created_at و updated_at آن، مقداری برابر با زمان Server می گیرد.
هم چنین برای ایجاد یک داده می توانیم از create که همانند save عمل می کند نیز استفاده کنیم.
$flight = App\Flight::create(['name' => 'Flight 10']);

بروزرسانی داده ها در Database توسط Model

از ()save علاوه بر ایجاد و ذخیره کردن یک داده، می توانیم برای بروزرسانی داده هایی که از قبل در Database وجود داشتند نیز استفاده کنیم. برای بروزرسانی یک داده باید ابتدا آن را دریافت کنیم، سپس تغییرات دلخواه را بر روی آن داده اعمال کنیم و پس از آن توسط ()save آن داده را در Database ذخیره کنیم.
$flight = App\Flight::find(1);

$flight->name = 'New Flight Name';

$flight->save();
در صورتی که timestamps$ را false نکرده باشیم، پس از ()save یک داده ای که از قبل در Database وجود داشته است، به طور خودکار ستون updated_at آن، مقداری برابر با زمان Server می گیرد. هم چنین برای بروزرسانی چند داده با مشخصاتی خاص، می توانیم آن ها را با یک Query که تنها داده هایی که آن مشخصات خاص را دارند برمی گرداند، دریافت کنیم و پس از آن از update استفاده کنیم.
App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);
در دستور بالا، تمام پرواز هایی که مقدار active آن برابر با 1 و مقدار destination یا مقصد آن برابر با San Diego است شناسایی شده و توسط update، مقدار delayed آن ها برابر با 1 می شود.

بررسی Attribute ها

برای بررسی Attribute ها می توانیم از isDirty ,isClean و wasChanged استفاده کنیم.
  • isDirty : از این method زمانی استفاده می کنیم که بخواهیم بدانیم آیا هیچ کدام از Attribute های یک Model از زمان ایجاد آن یا بروزرسانی کامل آن یعنی save کردن، تغییری داشته است یا خیر.
  • isClean : دقیقا برعکس isDirty عمل می کند.
$user = User::create([
    'first_name' => 'Taylor',
    'last_name' => 'Otwell',
    'title' => 'Developer',
]);

$user->title = 'Painter';

$user->isDirty(); // true
$user->isDirty('title'); // true
$user->isDirty('first_name'); // false

$user->isClean(); // false
$user->isClean('title'); // false
$user->isClean('first_name'); // true

$user->save();

$user->isDirty(); // false
$user->isClean(); // true
  • wasChanged : معمولا از این method زمانی استفاده می کنیم که می خواهیم بدانیم آیا یک Attribute، پس از ارسال از طریق HTTP Request توسط کاربر، تغییر داده شده است یا خیر.
$user = User::create([
    'first_name' => 'Taylor',
    'last_name' => 'Otwell',
    'title' => 'Developer',
]);

$user->title = 'Painter';
$user->save();

$user->wasChanged(); // true
$user->wasChanged('title'); // true
$user->wasChanged('first_name'); // false
  • getOriginal : این method تمام اطلاعات و Attribute های اولیه یک model را، حتی اگر مقدار آن ها را هزاران بار عوض کرده باشیم، بر می گرداند.
$user = User::find(1);

$user->name; // John
$user->email; // john@example.com

$user->name = "Jack";
$user->name; // Jack

$user->getOriginal('name'); // John
$user->getOriginal(); // Array of original attributes...

Mass Assignment

Mass Assignment یکی از مهم ترین بخش های این آموزش است که رعایت نکردن آن باعث به خطر افتادن جدی امنیت سایت می شود. فرض کنید یک form با بخش های نام و نام خانوادگی، شماره همراه، آدرس و رمز عبور داریم که کاربر باید آن را تکمیل کنید. حال برای همین form در Database علاوه بر بخش های بالا چند بخش دیگر مانند نقش کاربری که شامل Admin یا User، دسترسی ها و بخش های امنیتی مهم دیگری می شود داریم. در این صورت هر کاربری که دانش برنامه نویسی داشته باشد، می تواند هنگام تکمیل form با اعمال چند تغییر کوچک نقش کاربری خود را Admin وارد کند و به تمام اطلاعات سایت دسترسی پیدا کند. برای جلوگیری از این Bug های امنیتی، باید در همان ابتدا تعیین کنیم که چه field هایی می تواند مقدار بگیرد. بدین منظور می توانیم از guarded یا fillable استفاده کنیم.
  • fillable : در آرایه fillable تمام Attribute هایی که می خواهیم بتواند از طرف کاربر مقدار بگیرد را وارد می کنیم.
  • guarded : در آرایه guarded تمام Attribute هایی که نمی خواهیم از طرف کاربر مقدار بگیرد را وارد می کنیم.
هنگامی که یک Attribute را در fillable وارد کنیم، به طور خودکار تمام Attribute های دیگر guarded می شوند. هم چنین اگر یک Attribute را در guarded وارد کنیم، به طور خودکار تمام Attribute های دیگر fillable می شوند.
در مثال بالا که تنها می خواهیم ۲ Attribute غیر قابل پر کردن باشند، بهتر است به جای وارد کردن Attribute هایی که قابل پر کردن می باشند در fillable، آن Attribute هایی که غیر قابل پر کردن هستند را در guarded وارد کنیم.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];
}
در دستور بالا Attribute که می تواند مقدار بگیرد را در fillable وارد کردیم، پس تمام Attributes ها به جز name که fillable است، guarded می باشند.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['price'];
}
در دستور بالا Attribute که نمی تواند مقدار بگیرد را در guarded وارد کردیم، پس تمام Attributes ها به جز price که guarded است، fillable می باشند.

اضافه کردن داده ها به Database همراه با Mass Assignment

برای ایجاد مستقیم یک داده در Database همراه با قابلیت Mass Assignment، می توانیم از firstOrCreate و firstOrNew استفاده کنیم.
  • firstOrCreate: این method ابتدا تلاش می کند تا با توجه به مقداری که به آن دادیم یک record از Database و از طریق Model پیدا کند. در صورتی که این record در Database پیدا نشود، به صورت خودکار یک داده با همان اطلاعاتی که وارد کردیم، در Database ایجاد می شود.
  • firstOrNew: این method همانند firstOrCreate عمل می کند، با فرق اینکه در صورت پیدا نشدن record، به جای ایجاد آن record، یک record از نمونه یا instance آن Model را برمی گرداند.
// Retrieve flight by name, or create it if it doesn't exist...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);

// Retrieve flight by name, or create it with the name, delayed, and arrival_time attributes...
$flight = App\Flight::firstOrCreate(
    ['name' => 'Flight 10'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

// Retrieve by name, or instantiate...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

// Retrieve by name, or instantiate with the name, delayed, and arrival_time attributes...
$flight = App\Flight::firstOrNew(
    ['name' => 'Flight 10'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);
  • updateOrCreate : این method زمانی برای بروزرسانی یک داده استفاده می شود که بخواهیم در صورت وجود نداشتن آن داده برای بروزرسانی، به صورت خودکار همان داده در Database ایجاد شود.
// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99, 'discounted' => 1]
);

حذف Model

برای حذف یک Model از Database می توانیم یک instance از آن Model را توسط ()delete حذف کنیم.
$flight = App\Flight::find(1);

$flight->delete();

حذف تنها یک یا چند داده ی Model

اگر بخواهیم به جای حذف کلی Model، تنها چند داده ی آن را حذف نماییم، می توانیم از ()destroy استفاده کنیم. برای همین باید Primary Key تمام داده هایی که می خواهیم حذف کنیم را به صورت یک آرایه در ()destroy وارد کنیم.
App\Flight::destroy(1);

App\Flight::destroy(1, 2, 3);

App\Flight::destroy([1, 2, 3]);

App\Flight::destroy(collect([1, 2, 3]));

حذف یک یا چند داده ی خاص از Model توسط Query

برای حذف یک یا چند داده ی خاص از Model می توانیم از Query، به شکل زیر استفاده کنیم.
$deletedRows = App\Flight::where('active', 0)->delete();
در دستور بالا، تمام پرواز هایی که غیرفعال هستند را از Database حذف می کنیم.

Soft Deleting

برای حذف داده های مهم از Database، قطعا حذف کلی و بدون بازگشت آن ها راهی پرخطر است. برای حذف این نوع داده ها از Soft Deleting استفاده می کنیم. eloquent laravel در این صورت پس حذف نرم یا همان Soft Delete کردن یک داده، یک ستون جدید به نام deleted_at به Database اضافه می شود، که این ستون مقداری برابر با زمان Soft Delete کردن داده را می گیرد. برای فعال سازی این قابلیت، Trait آن یعنی SoftDeletes را در use ,Model می کنیم.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model
{
    use SoftDeletes;
}
پس از use کردن SoftDeletes باید ستون deleted_at را به جدول Database اضافه کنیم. این ستون به صورت پیش فرض از نوع DateTime و با پشتیبانی از Carbon است.
Schema::table('flights', function (Blueprint $table) {
    $table->softDeletes();
});
حال وقتی از delete برای حذف داده استفاده کنیم، به صورت خودکار ستون deleted_add مقداری برابر با زمان Soft Delete کردن داده را می گیرد و پس از آن وقتی یک Query بر روی آن Model بزنیم، می بینیم که آن Model مانند حذف کردن های معمولی، دیگر وجود ندارد با این تفاوت که با استفاده از trashed می توانیم همان Model که Soft Delete شده بود را بررسی کنیم.
if ($flight->trashed()) {
    //
}

Query زدن برروی Model های Soft Delete شده

همان طور که در بالا گفتیم، Model های Soft Delete شده، به طور خودکار از Database به صورت غیر دائم حذف می شوند و هنگام زدن Query های معمولی، هیچ نتیجه ای را به ما برنمی گرداند. حال اگر بخواهیم از این Model در جایی استفاده کنیم، می توانیم از withTrashed استفاده کنیم.
$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();
هم چنین از withTrashed می توانیم در Query های ارتباطی یا relationship Query ها نیز استفاده کنیم.
$flight->history()->withTrashed()->get();

Restore کردن Model های Soft Delete شده

برای این که Model هایی که Soft Delete کردیم، دوباره قابل دسترسی باشد می توانیم از ()restore استفاده کنیم.
$flight->restore();
هم چنین برای restore کردن چند داده ی خاص از Model، می توانیم به شکل زیر عمل کنیم.
App\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

حذف کردن دائم Model های Soft Delete شده

اگر بخواهیم یک داده Soft Delete شده را به صورت دائم از Database حذف کنیم، می توانیم از forceDelete استفاده کنیم.
// Force deleting a single model instance...
$flight->forceDelete();

// Force deleting all related models...
$flight->history()->forceDelete();

کپی برداری از Model ها

اگر بخواهیم تعدادی Model که بعضی از Attribute های آن یکسان است، ایجاد کنیم، می توانیم از یکی از آن ها کپی بگیریم و بقیه Model ها را با توجه به Model اصلی که کپی شده است ایجاد کنیم. برای این کار از replicate استفاده می کنیم.
$shipping = App\Address::create([
    'type' => 'shipping',
    'line_1' => '123 Example Street',
    'city' => 'Victorville',
    'state' => 'CA',
    'postcode' => '90001',
]);

$billing = $shipping->replicate()->fill([
    'type' => 'billing'
]);

$billing->save();

Scope Queries

برای Query ها می توانیم یک دامنه، حریم یا همان Scope تعریف کنیم. به طور مثال Scope های جهانی یا Global، محلی یا Local و پویا یا Dynamic، که در ادامه به شرح کامل هر کدام از آن ها می پردازیم. scope query - eloquent laravel

Global Scopes

هنگامی که از Global Scope ها استفاده می کنیم، می توانیم بر روی Query هایی که به سمت Model، برای دریافت داده ها ارسال می کنیم، یک محدودیت خاصی اعمال کنیم. عملکرد Soft Deleting یا همان حذف نرم در لاراول، زمانی که از Global Scope ها استفاده می کنیم، تنها Model های پاک نشده را به ما برمی گرداند. هم چنین می توانیم یک Global Scope خاص و سفارشی را، که در ادامه به آموزش ایجاد این Scope می پردازیم، برای خود ایجاد کنیم، که ایجاد این Scope باعث می شود که به راحتی محدودیت هایی که می خواهیم را بر روی همه ی Model ها، همزمان اعمال کنیم.

ایجاد Global Scope ها :

ایجاد یک Global Scope بسیار ساده است. برای این کار باید در ابتدا Illuminate\Database\Eloquent\Scope را use کنیم. سپس این interface، که ابتدای دستوراتمان use کردیم، از ما می خواهد که یک method به نام apply را مانند دستورات زیر پیاده سازی یا implement کنیم.
<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class AgeScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('age', '>', 200);
    }
}

استفاده از Global Scope ها

برای اختصاص دادن یک Global Scope به یک Model، باید در تابع booted از آن Model، از addGlobalScope استفاده کنیم.
<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::addGlobalScope(new AgeScope);
    }
}
در این صورت به طور مثال، درخواست دریافت تمام کاربران یک سایت یا همان ()User::all برابر با کد SQL زیر می شود.
select * from `users` where `age` > 200

Global Scope های ناشناس :

laravel eloquent به شما این امکان را می دهد که یک Global Scope را توسط Closure ها ایجاد کنید. از این روش هنگام ایجاد Scope های ساده ای که از یک Class که کلاس های دیگر را warrant یا تضمین نمی کند تشکیل شده است، می توانیم استفاده کنیم.
<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::addGlobalScope('age', function (Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

حذف Global Scope ها

اگر بخواهید یک Global Scope را حذف کنید، باید از withoutGlobalScope استفاده کنید. این Method تنها یک Argument که نام Class هست را می پذیرد.
User::withoutGlobalScope(AgeScope::class)->get();
اگر Global Scope را توسط Closure ایجاد کردید، برای حذف آن باید به شکل زیر عمل کنید.
User::withoutGlobalScope('age')->get();
هم چنین اگر می خواهید به جای حذف تنها یک Global Scope، همه یا چند تا از آن ها را حذف کنید، می توانید از دستورات زیر استفاده کنید.
// Remove all of the global scopes...
User::withoutGlobalScopes()->get();

// Remove some of the global scopes...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();

Local Scopes

هنگامی که از Local Scope ها استفاده می کنیم، می توانیم بر روی Query هایی که به سمت Model، برای دریافت داده ها ارسال می کنیم، محدودیت های خاصی که امکان دارد در برنامه چندین بار استفاده کنیم را اعمال کنیم. به طور مثال ممکن است بخواهید در قسمت های مختلفی از برنامه، کاربرانی که "Popular"هستند را ده ها بار دریافت کنید. برای این نوع عملیات و کار ها از Local Scope ها می توانیم استفاده کنیم و برای تعریف یک Local Scope باید در ابتدای Method ها از پیشوند scope استفاده کنیم.
Scope ها همیشه باید یک instance از query builder را return کنند.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include popular users.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * Scope a query to only include active users.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

استفاده از Local Scope ها

هنگامی که Scope را در Model تعریف کردیم، برای استفاده از آن، هنگام Query زدن باید آن Method را فراخوانی کنیم.
$users = App\User::popular()->active()->orderBy('created_at')->get();
هم چنین برای ترکیب چند Local Scope از or به شکل زیر در ابتدای Query استفاده می کنیم.
$users = App\User::popular()->orWhere(function (Builder $query) {
    $query->active();
})->get();
با این حال، از آن جا که این روش می تواند کمی دشوار باشد، لاراول یک روش بهتر یعنی orWhere را ارائه می دهد که از طریق این Method بدون استفاده از Closure ها، می توانید این Scope ها را مانند زنجیر به هم متصل کنید.
$users = App\User::popular()->orWhere->active()->get();

Dynamic Scopes

گاهی اوقات ممکن است بخواهید یک Scope تعریف کنید که پارامترهای مختلف را بپذیرد. برای این کار کافی است پارامترهای مورد نظر خود را به Scope اضافه کنید. توجه کنید که پارامترهای یک Scope باید مانند دستورات زیر، پس از query$ تعریف شوند.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include users of a given type.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @param  mixed  $type
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}
حال می توانید هنگام فراخوانی Scope، به شکل زیر به آن یک پارامتر اختصاص دهید.
$users = App\User::ofType('admin')->get();

مقایسه Model ها

گاهی اوقات ممکن است بخواهید تعیین کنید که آیا دو Model یکسان هستند یا خیر. متد is برای این استفاده می شود که شناسایی کنید آیا این دو Model دارای Primary Key، جدول ها و Database مشترکی هستند یا خیر.
if ($post->is($anotherPost)) {
    //
}

Events

Model های laravel eloquent شامل Event های زیادی می شوند که این Event ها به شما این امکان را می دهند تا در Model ها به جست و جو بپردازید. بعضی از این موارد شامل retrieved ,creating ,created ,updating ,saving ,saved ,deleting ,deleted ,restoring ,restored می شوند. علاوه بر این Event ها به شما این امکان را می دهد که هر بار که یک model class در Database ذخیره یا بروزرسانی شود، به راحتی یک کد دل خواه را اجرا کنید. هم چنین تمام Event ها instance یک Model را از طریق Constructor آن دریافت می کنند.
  • Event : retrieved یا رویداد retrieved زمانی اجرا می شود که Model از Database بازیابی یا همان retrieved شود.
  • creating / created:  زمانی که یک Model جدید برای اولین بار Save می شود، Event های creating و created اجرا می شوند.
  • updating / updated : اگر یک Model از قبل در Database وجود داشته باشد و برای آن Model متد save فرا خوانده شود، Event های updating و updated اجرا می شوند. هم چنین برای هر دوی این Event ها، saving و saved نیز اجرا می شوند.
برای شروع، ابتدا یک Property به نام dispatchesEvents$ را در Model تعریف می کنیم.
<?php

namespace App;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The event map for the model.
     *
     * @var array
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}
حال مانند دستور بالا، Index های دل خواهی را در آرایه dispatchesEvents$ همراه با Value هایی برابر با Class های نظیر آن تعریف می کنیم. پس از آن شما می توانید از event listnere ها برای مدیریت Event های خود استفاده کنید.

استفاده از Closure ها

به جای استفاده از Event Class های سفارشی ،می توانید از Closure ها استفاده کنید. این Closure ها را باید در متد booted وارد کنیم.
<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::created(function ($user) {
            //
        });
    }
}

ناظران (Observers)

زمانی در یک Model خاص در حال listening رویدادها یا Event های زیادی هستید، می توانید از Observer ها برای گروه بندی همه listener های خود در یک Class واحد استفاده کنید. Class های Observer دارای Method هایی با نام های مختلف هستند، که این  Method ها نمایانگر همان Event هایی هستند که می توانید listen کنید. همه ی این Method ها تنها یک Argument، یعنی Model را می توانند به عنوان پارامتر ورودی دریافت کنند.

ایجاد Observer ها

برای ایجاد Observer ها از دستور زیر استفاده می کنیم.
php artisan make:observer UserObserver --model=User
دستور بالا یک Observer جدید به نام UserObserver در App/Observers ایجاد می کند. در صورتی که پوشه ی Observers از قبل موجود نباشد، با اجرای دستور بالا این پوشه به صورت خودکار ایجاد می شود. Observer ها در ابتدا به شکل زیر هستند:
<?php

namespace App\Observers;

use App\User;

class UserObserver
{
    /**
     * Handle the User "created" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Handle the User "updated" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the User "deleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the User "forceDeleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}
برای register کردن یک Observer، از متد observe در Model استفاده می کنیم. برای این کار باید به شکل زیر دستور observe را در متد boot یکی از Service Provider ها، به طور مثال AppServiceProvider تعریف کنیم.
<?php

namespace App\Providers;

use App\Observers\UserObserver;
use App\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }
}
جمع بندی همیشه یکی از اصلی ترین دغدغه های برنامه نویسانی که با زبان PHP کار می کردند، ایجاد ارتباط بین برنامه و Database، زدن Query های مختلف برای اضافه کردن، حذف کردن، بروزرسانی و اعمال تغییراتی هر چند کوچک بر روی داده های Database و مشکلاتی از این دست بود. همان طور که در مقدمه این مقاله گفتیم، یکی از بزرگترین مزایای فریم ورک لاراول، استفاده از Eloquent ORM است که به تمام دغدغه هایی که گفتیم پایان داده است. آشنا بودن هر چه بهتر با laravel eloquent ، سرعت کار ما را چندین برابر افزایش و کیفیت برنامه های ما را به مراتب بهتر می کند.
اگر به یادگیری بیشتر لاراول علاقه داری می تونی در دوره آموزش لاراول کاربردی (بسته پروژه محور) شرکت کنی، این دوره شامل ۱۲ پروژه کاربردی و پر استفاده در دنیای واقعی است، که تمامی پروژه ها به صورت کامل برنامه نویسی خواهند شد، تا دانشجو بتواند با روند ایجاد و تکمیل پروژه به صورت کامل آشنا شود.
اشتراک‌گذاری:
۱۰ دیدگاه
Ali Majidi
نویسنده Ali Majidi
۵

دیدگاه‌ها

۸ نفر تجربه‌شان را نوشته‌اند.

M
MAHDI7 ۱۳۹۸/۱۱/۲۲

خیلی ممنون که اینقدر واضح توضیح دادید.

۱۴۰۱/۴/۲۷

یه مقاله بسیار عالی و کاربردی بود. واقعا لذت بردم و خوشحالم که همچین مقاله کاملی به زبان فارسی در سون‌لرن منتشر شده.

ن
نازنین کریمی مقدم ۱۴۰۱/۴/۲۸

ممنون بابت حسن نظرتون :)

۱۴۰۱/۱۰/۹

واقعا مطالب بسیار کاربردی و عالی ، سپاس گذارم...

s
sajjad hosseinzadeh ۱۴۰۱/۱۱/۱۵

داکیومنت Eloquent لاراول. اون هم به زبان فارسی و اینقدر با جزییات و دقت!! کمال تشکر رو دارم از تیم حرفه‌ای 7learn

۱۴۰۲/۶/۵

سپاس فراوان

۱۴۰۲/۶/۶

سپاس

۱۴۰۲/۶/۷

عالی