آشنایی با فایل‌‎های Migration و ساختار جدول‌ها

Familiarity with Migration Files and Table Structure

25 بهمن 1399
Laravel 7.0: آشنایی با فایل های migration و ساختار جدول ها (قسمت 13)

در جلسه قبل با موفقیت اعتبارسنجی را برای فرم خود پیاده سازی کردیم تا شامل فیلد username نیز بشود اما هنوز کارمان تمام نشده است. اگر یادتان باشد ما پایگاه داده خود را با استفاده از migration ها ساخته بودیم. برای مرور به پوشه database و سپس migrations می رویم و فایل create users table را باز می کنیم (معمولا نامی شبیه به 2014_10_12_000000_create_users_table.php دارد). من در جلسات قبل توضیح دادم که هر فایل migration یک کلاس است که دو متد up و down دارد:

  • متد up مسئول ساخت جدول است (Schema::Create) و همان متدی است که با اجرای php artisan migrate اجرا می شود.
  • متد down دقیقا برعکس متد up است (Schema::dropIfExists) و جدول های ساخته شده را حذف می کند.

به محتوای متد up در فایل Create users table توجه کنید:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

دستور schema::create یک جدول جدید می سازد. واژه schema به معنی «طرح» است و منظور آن مشخص کردن طرح جدول های پایگاه داده است. من صحبت های جلسه 6 را تکرار نمی کنم بلکه می خواهیم این migration را ویرایش کنم. هر کدام از ساختارهای ()X<-table$ نشان دهنده یک ستون در جدول users هستند:

  • id همان id کاربر در پایگاه داده است.
  • name همان نام کاربر است.
  • email همان ایمیل کاربر است.
  • email_verified_at زمانی را مشخص می کند که کاربر ایمیل خود را تایید کرده است. تا زمانی که کاربر ایمیل را تایید نکرده باشد مقدار null در این ستون ثبت می شود.
  • password همان رمز کاربر است.
  • remember_token یک توکن خاص است که مخصوص گزینه remember me (مرا به خاطر بسپار) در فرم login سایت است. این کار معمولا با یک کوکی انجام می شود اما همانطور که می دانید کوکی ها می توانند توسط هکر ها hijack (دزدیده) شوند. لاراول برای جلوگیری از این موضوع این توکن را علاوه بر کوکی در سمت پایگاه داده نیز ذخیره می کند تا جلوی حملات cookie hijacking گرفته شود. این توکن با هر بار login یا logout تغییر می کند و به صورت خوکار توسط لاراول مدیریت می شود.
  • timestamps دو ستون created_at و updated_at را ایجاد می کند که به ترتیب زمان ساخته شدن این ردیف/سند و زمان به روز رسانی آن را ذخیره می کنند.

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

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->string('username')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

من username را در قالب یک رشته اضافه کرده ام که باید یکتا (unique) باشد. فعلا این را در ذهنتان داشته باشید که ما فایل migration را ویرایش کردیم اما پایگاه داده ما قبلا ساخته شده است و تغییرات این فایل را باید روی پایگاه داده نیز پیاده کنیم.

حالا به فایل RegisterController.php برگشته و به متدهای validator و create نگاهی بیندازید:

protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'username' => ['required', 'string', 'max:255', 'unique:users'],
        'password' => ['required', 'string', 'min:8', 'confirmed'],
    ]);
}

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

اگر متد validator بدون خطا اجرا شود و تمام داده های ارسالی معتبر باشند، روند اجرای کدها ادامه پیدا می کند اما اگر خطایی در آن ها پیدا کنیم (مثلا ایمیل تکراری باشد) آنگاه اجرای کدها متوقف شده و خطایی به کاربر برمی گردد. بیایید فرض کنیم که validator اجرا شود و هیچ خطایی نداشته باشیم؛ در این حالت متد create اجرا خواهد شد. این متد مسئول ساخت یک کاربر در پایگاه داده ما است اما در اینجا username را نداریم و فیلد username نیز نمی تواند خالی باشد بنابراین آن را اضافه می کنیم:

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

حالا کدها را ذخیره کرده و به مرورگر بروید و یک کاربر جدید را ثبت نام کنید (با مقادیر دلخواه):

من فیلد های فرم را با داده های دلخواه خودم پُر می کنم.
من فیلدهای فرم را با داده های دلخواه خودم پُر می کنم.

به محض کلیک روی دکمه register با خطای زیر روبرو می شوید:

Illuminate\Database\QueryException

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'username' in 'where clause' (SQL: select count(*) as aggregate from `users` where `username` = newUser)

این خطا می گوید که ستونی به نام username در پایگاه داده شما وجود ندارد! برای تست این موضوع ترمینال جدیدی را در مسیر پروژه خود باز کرده و دستور زیر را در آن اجرا کنید:

php artisan tinker

دستور tinker به شما اجازه می دهد که به صورت مستقیم با برنامه خود در ترمینال تعامل داشته باشید. پس از اجرای این دستور وارد محیط خاصی می شوید که با علامت <<< مشخص شده است. حالا در این محیط دستور زیر را اجرا کنید:

User::all();

با اجرای این دستور تمام کاربران در پایگاه داده برای ما برگردانده می شوند. نتیجه اجرای دستور بالا برای من بدین شکل است:

[!] Aliasing 'User' to 'App\User' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#3858
     all: [
       App\User {#3791
         id: 1,
         name: "Amir",
         email: "myEmail@email.com",
         email_verified_at: null,
         created_at: "2020-06-21 06:18:35",
         updated_at: "2020-06-21 06:18:35",
       },
     ],
   }

طبیعتا فیلد password به صورت خودکار مخفی شده و نمایش داده نمی شود اما بقیه فیلدها حضور دارند. در اینجا می بینیم که کاربر new user وجود ندارد و خبری از ستون username هم نیست. آیا دلیل آن را می دانید؟ بله! ما فایل migration را تغییر دادیم اما هنوز این تغییرات را از فایل روی پایگاه داده اعمال نکرده ایم. برای انجام این کار می گوییم:

php artisan migrate:fresh

با اضافه کردن قسمت Fresh گفته ایم که همه چیز در پایگاه داده ما را حذف کن و سپس migrations ها را دوباره انجام بده. به نظر شما با اجرای این دستور مشکل حل می شود؟

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

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