فصل سوم: شروع واقعی با دیتابیس

درک مفهوم مایگرشن

مایگرشن‌ها اختراع لاراول نیستند و خیلی پیش از آن به وجود آمده‌اند.

لاراول، دنیایی است با ابزارهایی رنگ و وارنگ و اسم‌های جذاب، که اغلب از قبل وجود داشته‌اند و حیاتشان را مدیون لاراول نیستند، اما زیبایی در کنار هم بودنشان را چرا.

فلسفه‌ی مایگرشن

کدهای برنامه‌ی خود را روی یکی از سیستم‌های کنترل ورژن مثل گیت نگه می‌داریم و خوشحالیم که اگر اتفاق ناگواری افتاد، به عقب بازمی‌گردیم و دقیقاً می‌دانیم هر تغییر چه تأثیری بر مخلوق ما داشته، اما افسوس که دیتابیس ما از این قافله جداست.

مایگرشن برای همین روزها ساخته شده است!

داستان از این قرار است که ما باید دیتابیس خودمان را در یک برنامه و ابزار جداگانه بسازیم و مدیریت کنیم، و هر بار که می‌خواهیم فایل‌های پروژه را به کسی بدهیم، باید یک بکاپ دستی هم از دیتابیس بگیریم و برایش بفرستیم.

بهتر نبود تهیه‌ی زیرساخت‌های اطلاعاتی را هم می‌توانستیم در ویرایشگر کد خود انجام دهیم و طراحی دیتابیس هم مثل بقیه چیزها، همان جا باشد تا هم انتقالش به دیگران راحت باشد و هم تحت نظارت سیستم کنترل نسخه‌ی ما عمل کند؟

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

کار با مایگریشن منطق ساده‌ای دارد:

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

لاراول با آن‌ها چه می‌کند؟‌

لاراول، تا وقتی که خودمان از او نخواهیم، هیچ کاری نمی‌کند.

اجازه دهید آسیاب به نوبت!

آماده‌های داخل جعبه

لاراول، درست بعد از نصب، دو فایل مایگرشن حاضر و آماده به استفاده در خود دارد که در پوشه‌ای به نام migrations در پوشه‌ی database قرار دارند:

2014_10_12_000000_create_users_table
2014_10_12_100000_create_password_resets_table

فلسفه حضور

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

اگر جدول کاربران پروژه‌ی شما به چیزهایی بیش از این نیاز دارد، فایل را باز کرده و آن‌ها را تغییر دهید.

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

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

الگوی نام‌گذاری

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

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

ساختار داخلی

فایل‌های مایگریشن، کلاس‌هایی هستند که از کلاس والدی به نام Migration نشأت گرفته‌اند و هر کدام دو متد دارند: یک متد up که طرحی را می‌سازند و یک متد down که طرح ساخته‌شده را خراب می‌کنند‌.

عنوان کلاس‌ها، صورت Studly Caps از همان نام فایل هستند.

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

عملکرد مایگرشن

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

عملکرد مایگرشن را شبیه یک نوار زمان در نظر بگیرید که ما می‌توانیم آن را به جلو یا به عقب برانیم.

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

فرآیند مایگرشن، به زبان ساده، همین است که گفتم. اما اجازه بدهید کمی دقیق‌تر شویم.

به جلو برانیم

برای اجرای مایگرشن‌ها از کنسول آرتیزان کمک می‌گیریم.

php artisan migrate

با اولین اجرای این دستور، لاراول به سراغ پوشه‌ی مایگرشن‌ها می‌رود و فایل‌های موجود در آن را به ترتیب تاریخی که در ابتدای اسمشان هست، مرتب می‌کند و متد up آن‌ها را، مثل هر تابع پی‌اچ‌پی دیگر، یکی‌یکی اجرا می‌نماید.

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

لاراول یادش می‌ماند!

لاراول بعد از هر اجرای مایگرشن (یعنی هر بار که به جلو راندیم)، نام مایگرشن‌های اجراشده را در جدولی به نام migrations ذخیره می‌کند.

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

طبیعتاً اگر چنین جدولی وجود نداشت، لاراول خودش آن را می‌سازد و شما لازم نیست نگران چیزی باشید.

اگر دوباره به جلو برانیم...

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

حالا به عقب برگردیم

گفتیم که عملکرد مایگریشن شبیه یک نوار زمان است که می‌توانیم در آن جلو و عقب بریم.

آرتیزان برای عقبگرد هم کمکمان می‌کند.

php artisan migrate:rollback

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

گفتیم متد down برعکس همان کاری را می‌کند که متد up انجام داده. اگر در متد up جدولی ساختیم، در متد down آن را نابود می‌کنیم و اگر در متد up چیزی را تغییر دادیم، در متد down تغییرات را به حالت اول بازمی‌گردانیم.

آنچه در متدهای up و down نوشته می‌شوند، دستورهای پی‌اچ‌پی هستند. این که متد down حتماً برعکس متد up عمل کند، وظیفه‌ی ماست. هرچند آرتیزان بیشتر وقت‌ها به ما کمک می‌کند تا متد down متناسبی داشته باشیم. این نکته را بیشتر خواهیم شکافت.

یک بار اجرای دستور migrate:rollback، مایگرشن‌های آخرین حرکت رو به جلوی ما را شناسایی می‌کند و آن‌ها را به عقب می‌راند و نتیجه را در جدول migrations می‌نویسد.

اجرای مجدد دستور migrate:rollback، همین بلا را سر اجرای قبل از اجرای آخر هم می‌آورد. ‌

این کار را می‌توانید آن قدر ادامه دهید که دیگر جدولی باقی نماند.

به صورت پیش‌فرض، با هر بازگشت یک لایه به عقب می‌روید، اما می‌توانید این روند را تغییر دهید و یکباره چند لایه به عقب بروید.

php artisan migrate:rollback --step=5

پارامتر دل‌خواه step، تعداد لایه‌هایی که می‌بایست به عقب بروند را تعیین ‌می‌کند.

بازگشت به ابتدا

php artisan migrate:reset

با این دستور، لاراول تمام مایگرشن‌های اجراشده را تا انتها به عقب برمی‌گرداند و چیزی به جز جدول migrations که برای کارهای خودش لازم دارد، باقی نمی‌گذارد.

برپایی مجدد

php artisan migrate:refresh

این دستور، همه‌ی جدول‌ها را از بین می‌برد و دوباره از نو می‌سازد و عملاً ترکیبی از دو دستور بازگشت به ابتدا، و اجرای دوباره است.

نوسازی کامل

php artisan migrate:fresh

این دستور نیز مثل دستور قبلی همه‌ی جدول‌ها را از بین می‌برد و دوباره از نو می‌سازد، اما این کار را بدون فرآیند بازگشت انجام می‌دهد.

به بیان فنی‌تر، همه‌ی جدول‌های موجود را بدون توجه به متدهای down موجود در مایگرشن‌ها، به یکباره drop می‌کند و سپس دوباره دستور migrate را اجرا می‌کند.

چه بر سر داده‌ها می‌آید؟

اجرای مایگرشن، کاری نیست که معمولاً در فاز بهره‌برداری برنامه انجام شود و معمولاً همه چیز در فاز توسعه (چه برپایی و چه بهبود) صورت می‌گیرد. اما پرسش اساسی پابرجاست.

چه بر سر داده‌ها می‌آید؟

پاسخ این سؤال به کاری که می‌کنید بستگی دارد. اگر مایگرشنی نوشته‌اید که جدولی را از بین می‌برد، داده‌های آن هم از بین می‌روند. اگر دستوری مثل بازگشت یا نوسازی را صادر کنید، آن بخش از داده‌هایی که بستر آن‌ها را نابود می‌کنید، از بین می‌روند. اما اگر صرفاً جدول‌های جدیدی در پروژه ایجاد کرده‌اید و چیزهایی را تغییر داده‌اید، دستور migration به اطلاعات صدمه‌ای نمی‌زند.

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

ایجاد فایل مایگریشن

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

مشکلات لاراولی راه‌حل‌هایی لاراولی دارند و کنسول آرتیزان برای همین کارها ساخته شده.

php artisan make:migration create_missions_table

این دستور، فرمت تاریخی درست را متناسب با زمان اجرای دستور، در ابتدای نامی که خواسته‌ایم می‌نهد و فایلی را در جای درست می‌سازد و نامش را به ما می‌گوید:

کار به همین جا ختم نمی‌شود و لاراول، کلاس و متدهای داخل فایل تازه را نیز تعریف می‌کند و تنها کاری که باقی می‌ماند این است که دستورهایی را که می‌خواهیم، برای دو متد up و down آن تعریف کنیم.

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

حاصل دستور بالا، فایلی است به این شکل:

<?php // 2018_02_12_185321_create_missions_table

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateMissionsTable extends Migration
{
    /**
    *Run the migrations.
    *@return void
    */
    public function up()
    {
        Schema::create('missions', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
    * Reverse the migrations.
    * @return void
    */
    public function down()
    {
        Schema::dropIfExists('missions');
    }
}

همان طور که ملاحظه می‌فرمایید، حتی درون متدهای up و down را نیز تا حدودی که حدس می‌زده چه می‌خواهیم بکنیم، پر کرده است و فقط باید زحمت بکشیم و دستور اضافه کردن فیلدهایی که می‌خواهیم، در متد up بنویسیم و ساختار موجود را تکمیل کنیم.

برای ویرایش

همیشه که نمی‌خواهیم جدولی را بسازیم. گاهی هم می‌خواهیم در مایگرشن، جدولی که از قبل وجود داشته را ویرایش کنیم.

برای ماگریشن ویرایشی هم از آرتیزان کمک می‌گیریم و باز هم از همان دستوری که قبلاً آموختیم استفاده می‌کنیم.

php artisan make:migration add_folan_to_missions_table

فایلی که این بار لاراول می‌سازد نیز همان رنگ و بو و ساختار قبلی را دارد، با اندکی تفاوت.

می‌توانید این تفاوت را تشخیص دهید؟‌

<?php // 2018_02_12_185929_add_folan_to_missions_table

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddDescriptionToMissionsTable extends Migration
{
    /**
    * Run the migrations.
    * @return void
    */
    public function up()
    {
        //
    }

    /**
    * Reverse the migrations.
    * @return void
    */
    public function down()
    {
        //
    }
}

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

داستان از این قرار است که این بار متدهای up و down خالی هستند و عرصه را به ما واگذاشته‌اند و این در حالی است که ما هیچ کار خاصی نکردیم، جز این که از کلمه‌ی create در نام فایلی که می‌خواستیم بسازیم استفاده نکردیم.

و حالا کمی بهتر...

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

php artisan make:migration add_description_to_missions_table --table=missions

در این دستور، به لاراول می‌گوییم که قصد داریم فایلی با عنوان add_description_to_missions_table بسازیم و در آن تغییراتی در جدول جدول missions ایجاد کنیم.

فایلی که به این ترتیب ایجاد می‌شود، به اندازه‌ی فایل قبلی خالی نیست، چرا که این بار لاراول می‌داند با کدام جدول کار داریم و کمی هم از متدهای up و down ما را کامل کرده است.

<?php // 2018_02_12_190431_add_description_to_missions_table

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddDescriptionToMissionsTable extends Migration
{
    /**
    * Run the migrations.
    * @return void
    */
    public function up()
    {
        Schema::table('missions', function (Blueprint $table) {
            //
        });
    }

    /**
    * Reverse the migrations.
    * @return void
    */
    public function down()
    {
        Schema::table('missions', function (Blueprint $table) {
            //
        }
    }
}

جان کلام

در این درس، با فلسفه و مفهوم مایگرشن آشنا شدیم و نحوه‌ی تولید فایل‌های آن را در لاراول یاد گرفتیم و آشنایی با دستورهای طراحی دیتابیس، که در متدهای up و down این فایل‌ها جای می‌گیرند را به درس بعد موکول کردیم.