آشنایی با مفهوم Mass Assignment در Model

Introduction to the Concept of Mass Assignment in Model

25 بهمن 1399
Laravel 7.0: آشنایی با مفهوم mass assignment در Model (قسمت 14)

اگر یادتان باشد در قسمت قبل دستور migrate:fresh را اجرا کرده ایم اما قبل از تست آن باید نکته ای را برایتان توضیح بدهم. ما در همان قسمت از کلاس User متد create را صدا زده بودیم (کنترلر RegisterController.php):

protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'username' => $data['username'],
        'password' => Hash::make($data['password']),
    ]);
}

ما می دانیم که User::create یک کاربر را در پایگاه داده می سازد و این موضوع را در جلسه قبل بررسی کرده بودیم اما آیا می دانید کار با پایگاه داده در معماری MVC وظیفه چه عنصری است؟ View های ما که در پوشه views و Controller های ما هم در پوشه app->Http->Controllers قرار دارند اما Model های ما کجا هستند؟ Model های ما در پوشه app قرار دارند و فعلا یک Model بیشتر نداریم که همان فایل User.php است. بنابراین در کد بالا User::create در حال صدا زدن کلاس User است که همان Model ما و مسئول ارتباط با پایگاه داده می باشد.

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

public function store(Request $request)
    {
        // Validate the request...

        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();
    }

یعنی از یک Model به نام Flight یک نمونه (instance) ساخته ایم، سپس خصوصیات مد نظر خود (name) را برایش تعریف کرده ایم. مثلا اگر کاربر بالا ایمیل نیز داشته باشد باید email را به صورت جداگانه برایش تنظیم می کردیم:

$flight->name = $request->name;

$flight->email = $request->email;

این کار را برای تک تک فیلدهای فرم خود انجام خواهیم داد. یادتان باشد که flight همان Model و request$ شیء ای است که شامل کل درخواست کاربر می شود (تمام فیلدهای فرم) و به صورت خودکار به متد های ما در کنترلر پاس داه می شود. بنابراین flight->email$ یعنی تعریف یک خصوصیت برای کاربر جدید و request->email$ یعنی دریافت مقدار فیلد email از درخواست کاربر. احتمالا شما هم متوجه شده اید که این کار دردسر دارد. فرض کنید فرم ما 10 فیلد داشته باشد؛ ما باید 10 فیلد را جداگانه برای کاربر خود تنظیم کنیم و در نهایت متد save را صدا بزنیم تا کاربر ساخته شده و در پایگاه داده ذخیره شود. به نظر شما چرا لاراول این کار را کرده است؟

کاربران می توانند فرم های HTML را تغییر بدهند و فیلدهای جدیدی را به درخواست های شما اضافه کنند. این نوع از حملات معمولا بدین صورت انجام می شوند که کاربر فیلد جدیدی مثل is_admin را از هر طریقی به درخواست HTTP اضافه می کند و شما بدون بررسی آن را به پایگاه داده ارسال می کنید. حالا فرض کنید که ما ستونی به این نام داشته باشیم! آنگاه کاربر با ارسال این فیلد جدید و قرار دادن مقدار آن روی 1 یا true می تواند خودش را ادمین کند! لاراول برای جلوگیری از این نوع حملات شما را وادار می کند که فیلدها را تک تک مشخص کنید تا فیلدهای اضافی اصلا پردازش نشوند.

احتمالا می پرسید پس متد User::create چه بود؟ ما با این متد مجبور به چنین کاری نبودیم. حرفتان درست است! متد create برای راحتی کار شما به لاراول اضافه شده است و ما هم در کل دوره از همان متد استفاده خواهیم کرد چرا که می تواند تمام فیلدها را سریعا و بدون دخالت سر هم کرده و کاربر را در پایگاه داده ذخیره کند. سوالی که پیش می آید این است که پس جلوگیری از حملات ذکر شده چه می شود؟ برای پاسخ به این سوال به فایل Model خود بروید:

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

هر model نماینده یک ردیف در پایگاه داده ما است. اگر به کد بالا نگاه کنید متوجه حضور خصوصیتی به نام fillable$ (به معنای «پُر شدنی») می شوید. این خصوصیت مشخص می کند که چه فیلدهایی از فرم های ارسالی به سمت سرور پردازش شوند. هر فیلدی به غیر از این فیلدها نادیده گرفته خواهد شد بنابراین در حال حاضر که username بین این خصوصیات نیست اگر بخواهیم یک کاربر جدید بسازیم با خطا روبرو می شویم چرا که username به عنوان یک فیلد مطمئن و تایید شده ثبت نشده است. به فیلدهایی که در fillable$ مشخص کرده ایم mass assignable می گویند. mass یعنی «دسته جمعی» و assignable یعنی «قابل انتساب» بنابراین mass assignable یعنی فیلدهایی که می توانند به صورت دسته جمعی تعریف و ثبت شوند.

البته به جای fillable$ می توانید خصوصیت دیگری به نام guarded$ را تعریف کنید که دقیقا برعکس fillable$ عمل می کند:

    protected $guarded = ['price'];

در این حالت تمام فیلدهای ارسالی به سمت سرور mass assignable هستند به غیر از price! شما بنابر نیاز برنامه خود باید یا از fillable$ یا از guarded$ استفاده کنید ولی نمی توانید از هر دو به صورت همزمان استفاده نمایید.

من به شخصه از fillable$ استفاده می کنم چرا که با آن راحت تر هستم و برای برنامه ما تنها منطق صحیح است:

protected $fillable = [
    'name', 'email', 'username', 'password',
];

حالا که username را اضافه کرده ایم همه مشکلات حل شده اند. یادتان باشد که در جلسه قبل دستور php artisan migrate:fresh را اجرا کردیم که باعث حذف تمام داده های پایگاه داده و ساخت دوباره آن می شود بنابراین اگر الان به مرورگر رفته و صفحه را refresh کنید دیگر login نیستید چرا که کاربری وجود ندارد. بنابراین دوباره به فرم رفته و فرم را پر کنید. با این کار وارد حساب کاربری خود می شوید!

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری ساخت اینستاگرام با Laravel 7 توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.