تهجير قواعد البيانات (migrations) على Laravel


يوغرطة بن علي

تخيّل معي الوضع التالي. أنت عضو في فريق تطوير تطبيق باستخدام Laravel 4. يستخدم أعضاء الفريق git لإدارة إصدارات التطبيق وفي كل مرة يقوم عضو من أعضاء الفريق بإضافة خصائص أو إدخال تعديلات جديدة على المشروع يقوم بإيداع التغييرات في مُستودع التطبيق. إلى هنا يبدو الوضع عاديا (بل مثاليا) لكن ماذا لو قام أحد أعضاء الفريق بإدخال تعديل يتطلب إضافة جداول جديدة إلى قاعدة البيانات أو تعديل حقول وحذف أخرى، فما الحل هنا؟ هل يستطيع git مثلا أن يفي بالغرض؟ أم أنه سيتم تصدير قاعدة البيانات في كل مرة ويُطلب من كل عضو في الفريق استيرادها؟ ماذا عن البيانات التي تحتويها قاعدة البيانات؟ وهل يجب فعلا أن نتخلص من قاعدة البيانات القديمة واستبدالها بأخرى في كل مرة؟

إن كنت تستخدم إطار عمل لارافل فالحل يكمن في استخدام التهجير migrations والذي يُعتبر نظاما لإدارة الإصدارات الخاصة بقواعد البيانات، حيث أنه لن تعود هناك حاجة إلى إنشاء أي جداول أو إضافة حقول والتعديل عليها بشكل مُباشر/يدوي، وإنما يتم وصف تلك الجداول وحقولها بصيغة تجعل من التعامل مع قواعد البيانات أسهل.
قد يبدو الأمر مُعقّدا بعض الشيء، لكنه في حقيقة الأمر بسيط، وبمُجرد أن تفهم آلية عمله وتشرع في استخدامه حتى تستغرب كيف ضيعت كل الوقت السابق في إدارة قواعد البيانات يدويا. خاصية migrations مُفيدة لك حتى ولو كنت تعمل على مشروعك بشكل فردي.

بطبيعة الحال ستحتاج إلى إنشاء قاعدة بيانات للمشروع، ومن ثم التعديل على ملف app/config/database.php بما يتوافق مع ذلك.

إنشاء ملفات migrations

لإنشاء ملف migration جديد نحتاج إلى استخدام artisan لتنفيذ الأمر migration:make على النحو التالي مع استبدال اسم عملية التهجير بما يتوافق مع ما تقوم به (بطبيعة الحال ستحتاج إلى تنفيذ هذا الأمر بسطر الأوامر لما تكون داخل مُجلد المشروع):

php artisan migrate:make create_users_table

سيقوم laravel بإنشاء ملف جديد داخل مُجلد app/database/migrations يحمل الاسم الذي حددته في الأمر السابق ( create_users_table) مسبوقا بترقيم يُمثل تاريخ إنشائه حتى يتسنى لـ laravel معرفة الترتيب الذي يجب اتباعه لدى تنفيذ التهجيرات.
يُفضل استخدام أسماء للتهجيرات تدل على ما تقوم به. ففي المثال السابق أردنا إنشاء عملية تهجير جديدة لإنشاء جدول مُستخدمين، وبالتالي كان الاسم create_users_table.
ينتج عن تنفيذ الأمر السابق ملف يحتوي:

<?php

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

class CreateUsersTable extends Migration {

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

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

}

 

كما هو ظاهر هنا فإن الصنف CreateUsersTable يحتوي على دالتين الأولى up والتي تُبين ما الذي يجب القيام به لدى تنفيذ التهجير، والثانية down والتي نُحدد فيها ما الذي يجب القيام به لدى إلغاء التهجير في حال ما إذا أردنا العودة بقاعدة البيانات إلى الحالة التي كانت عليها قبل تنفيذ التهجير.

هذا الملف لا يُحدد أي جدول نعمل عليه أو نرغب في إنشاءه. يُمكن إضافة ذلك يدويا، كما أنه يُمكن القيام بذلك عبر تحديد اسم الجدول لدى تنفيذ أمر إنشاء عملية التهجير وذلك باستخدام --create التي تُحدد اسم الجدول الذي نرغب في إنشاءه أو --table التي تُحدد اسم الجدول الذي نرغب في التعديل عليه. فمثلا لو حذفنا عملية التهجير السابقة ورغبنا في إعادة إنشاء أخرى مع تحديد اسم الجدول فسيكون ذلك على النحو التالي:

php artisan migrate:make create_users_table --create=users

والذي سينتج عنه ملف مثل الملف السابق، لكن هذه المرة نجد أن دالتي up و down تحتويان أوامر أولية:

<?php

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

class CreateUsersTable extends Migration {

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

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

}

 

لاحظ هنا أن users هي اسم الجدول المُراد إنشاؤه والذي يكون عادة جمع اسم الـ model الذي تتعامل معه (بمعنى إن كان  user هو اسم الـ model فسيكون اسم الجدول الخاص به users)

أما لو أردنا التعديل على نفس الجدول السابق وإضافة حقل جديد إليه فيكفي تنفيذ الأمر التالي:

php artisan migrate:make add_votes_to_user_table --table=users

 تنفيذ عمليات التهجير

إلى حد الآن كل ما قمنا به هو إنشاء ملفات التهجير، حيث أنك لو تحققت من قاعدة البيانات لوجدتها فارغة. لتنفيذ عمليات التهجير نستعمل الأمر

php artisan migrate

وبعد ذلك ستلاحظ ظهور جدول جديد على قاعدة البيانات.
أما لو رغبت في التراجع عن آخر عملية تهجير (أو بالأحرى عن آخر جملة تهجيرات تم تنفيذها مع بعض) فإننا نستعمل الأمر:

php artisan migrate:rollback

وفي حال ما إذا رغبت في التراجع عن جميع عمليات التهجير والرجوع إلى الحالة الأولى لقاعدة البيانات فإن الأمر التالي كفيل بالقيام بذلك:

php artisan migrate:reset

ويُمكن أيضا استخدام الأمر التالي للتخلص من جميع عمليات التهجير وإعادة تنفيذها من جديد بشكل مُباشر بعد ذلك:

php artisan migrate:refresh

أنواع الحقول

رأينا في الفقرة السابقة بأن عمليات التهجير تسمح لنا بإنشاء معرف autoincrement إضافة إلى حقلي created_at و updated_at بفضل دالة timestamps. يسمح Laravel بإنشاء شتى أنواع الحقول التي قد تحتاجها في مشروعك إلى جانب إضافة خصائص للحقول وإعطائها قِيمًا أوليّة. المثال التالي يُبين بعض هذه الحقول والخصائص:

$user->string('name', 64);
$user->integer('age')->nullable();
$user->boolean('active')->default(1);
$user->integer('role_id')->unsigned();
$user->text('bio');

والذي يقوم  بإنشاء:

  • حقل name يكون نصيا يكون أقصر من أو يُساوي 64 محرفا.
  • حقل age يكون رقميا، كما أنه يقبل القيمة NULL
  • حقل active يكون منطقيا ويحمل قيمة أولية 1
  • حقل role_id رقميا ويكون موجبا
  • حقل bio يكون نصيا

بإمكان الاطلاع على جميع أنواع الحقول المُمكنة من هنا

حذف الحقول

ستحتاج إلى حذف الحقول في دالة down ويتم ذلك على النحو التالي:

Schema::table('users', function($table)
{
   $table->dropColumn('votes');
});

بذر قواعد البيانات database seeding

المقصود ببذر قواعد البيانات هو إدخال البيانات الأولية التي نحتاجها لتجربة التطبيق. بالرغم من أن تطبيقك يسمح بإنشاء مُستخدمين جدد فإنك سترغب في استخدام مُستخدمين تجريبيين في كل مرة تُحدث تغييرات في التطبيق، وإنشاء عدد من المُستخدمين يدويا في كل مرة مضيعة للوقت. الحل يكمن في إعلام Laravel بالبيانات الأولية التي ترغب في بذر قاعدة البيانات بها بعد إنشائها ويتم ذلك عبر إنشاء ملفات بذر داخل مُجلد app/database/seeds يحتوي الأوامر التي يجب تنفيذها.
مثال على ملف بذر يقوم بإضافة مُستخدم جديد:

class UserTableSeeder extends Seeder {

   public function run()
   {
      DB::table('users')->delete();
      User::create(array('email' => 'foo@bar.com'));
   }

}

لتنفيذ عملية البذر التي قمنا بإنشائها فإننا نستخدم الأمر التالي:

php artisan db:seed --class=UserTableSeeder

وإن كان لديك أكثر من ملف بذر وترغب في تنفيذها كاملة بأمر واحد فإنه يكفي القيام بذلك عبر تحديد أسماء عمليات البذر المُراد تنفيذها في صنف/ملف DatabaseSeeder الذي ستجده داخل مُجلد app/database/seeds على النحو التالي:

class DatabaseSeeder extends Seeder {

   public function run()
   {
      $this->call('UserTableSeeder');
      $this->call('PostTableSeeder');
   }
}

وبعد ستحتاج إلى تنفيذ الأمر

php artisan db:seed

الذي سيقوم بقراءة الملف واستدعاء عمليات البذر بشكل مُتوال
بإمكانك أيضا تنفيذ عمليات البذر مُباشرة بعد تحديث عمليات التهجير على الشكل التالي:

php artisan migrate:refresh --seed

توليد بيانات تجريبية باستخدام Faker

بالرغم من أن هذه الخُطوة ليست ضرورية، إلا أنه في الكثير من الحالات ستحتاج إلى بيانات تجريبية أقرب ما تكون إلى البيانات الحقيقية للتجريب عليها. فمثلا سترغب في استخدام أسماء مُستخدمين "حقيقيين" وعناوين بريد إلكتروني، وعناوين منازل، إضافة إلى أسماء المُدن وأرقام هواتف وما إلى ذلك. بطبيعة الحال فإنه بالإمكان الاكتفاء بملفات البذر وإدخال تلك البيانات بطريقة شبه يدوية، إلا أن هناك حلا آخر يُسهّل عليك ذلك إن استعنت بمكتبة Faker للحصول على هذه البيانات.
بداية سنحتاج إلى "تنصيب" Faker وذلك على النحو التالي:
قم بالتعديل على ملف composer.json وإضافة التالي:

"require-dev":{
"fzaninotto/faker": "1.5.*@dev"
},

أو قم بإضافة "fzaninotto/faker": "1.5.*@dev" إن كان حقل require-dev مُتوفرا في الملف.
بعدها قم بتنفيذ الأمر php artisan update ليقوم artisan بتحميل الملفات المطلوبة.
في غالب الأحوال ستحتاج إلى إنشاء مُستخدم غير عشوائي إلى جانب البيانات التجريبية، وعليه يُفضل إنشاؤه أولا قبل توليد البيانات العشوائية.

$user = User::create(array(
   'username' => 'djug',
   'first_name' => 'Youghourta',
   'last_name' => 'Benali',
   'email' => 'djug@someNewProject.com',
   'password' => Hash::make('MySuperPassword')
));

$faker = Faker\Factory::create();

for ($i = 0; $i < 25; $i++)
{
   $user = User::create(array(
   'username' => $faker->userName,
   'first_name' => $faker->firstName,
   'last_name' => $faker->lastName,
   'email' => $faker->email,
   'password' => Hash::make('Password')
));

في هذا المثال قمنا بإنشاء 25 مُستخدم يحملون أسماء بشر (وليس مُجرد حروف عشوائية) إضافة إلى عناوين بريد إلكتروني.

تسمح مكتبة Faker بتوليد شتى أنواع الحقول التي قد تحتاجها والتي يُمكن الحصول على نُسخ مُوطنة ومُترجمة منها، فمثلا يُمكن توليد أسماء عربية وعناوين فرنسية وما إلى ذلك.
للمزيد حول مكتبة Faker قم بإلقاء نظرة على مُستودع المشروع على github
وللمزيد حول جميع أنواع العمليات التي يُمكن القيام بها على الهجرات: Schema Builder



2 اشخاص أعجبوا بهذا


تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن