تهجير قاعدة البيانات في Laravel

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

مقدمة

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

توفّر الواجهة الساكنة Schema دعمًا لإنشاء وتعديل الجداول عبر جميع أنظمة قواعد البيانات المدعومة من قبل Laravel.

توليد التهجيرات

لإنشاء تهجير، استخدم أمر make:migration Artisan:

php artisan make:migration create_users_table

سيوضع التهجير الجديد في مجلد database/migrations. يحتوي كل اسم ملف تهجير على بصمة وقت مما يسمح لإطار Laravel بترتيب عمليات التهجير. يمكنك استخدام خيارات ‎--table و‎--create لتحديد اسم الجدول وما إذا كان التهجير سينشئ جدولًا جديدًا، وستملأ هذه الخيارات ملف التهجير المُنشئ باستخدام جدول محدد:

php artisan make:migration create_users_table --create=users

php artisan make:migration add_votes_to_users_table --table=users

إذا كنت ترغب في تحديد مسار مخرجات مخصّص للتهجير المنشئ، فيمكنك استخدام خيار ‎--path عند تنفيذ أمر make:migration، ويجب أن يكون المسار المحدد متعلقًا بالمسار الأساسي للتطبيق.

هيكلة التهجير

يحتوي صنف التهجير على تابعين: up و down، ويُستخدم التابع up لإضافة جداول جديدة أو أعمدة أو فهارس إلى قاعدة بياناتك، وأما التابع down فهو يعكس العملية التي أُجريت باستخدام التابع up.

يمكنك استخدام منشئ المخطّطات الخاص لإطار Laravel في أي من التابعين لإنشاء الجداول وتعديلها بشكل صريح، و للتعرّف على جميع الأساليب الموجودة في منشئ المخطّطات، راجع توثيقه على سبيل المثال، ينشئ هذا المثال للتهجير جدول flights:

<?php

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

class CreateFlightsTable extends Migration
{

   /**
    * تنفيذ التهجيرات     *
    * @return void
    */

   public function up()
   {
       Schema::create('flights', function (Blueprint $table) {

           $table->increments('id');
           $table->string('name');
           $table->string('airline');
           $table->timestamps();
       });
   }

   /**
    * عكس التهجيرات
    *
    * @return void
    */

   public function down()
   {
       Schema::drop('flights');
  }
}

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

لتشغيل جميع التهجيرات المعلّقة، نفّذ أمر migrate Artisan:

php artisan migrate

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

إجبار تشغيل التهجيرات في بيئة الإنتاج

بعض عمليات التهجير مدمّرة، مما يعني أنها قد تتسبّب بفقدان البيانات. لحمايتك من تشغيل هذه الأوامر على قاعدة البيانات في بيئة الإنتاج الخاصة بك، ستُطالب بالتأكيد قبل تنفيذ الأوامر، ولفرض تشغيل أمر دون المرور بمرحلة التأكيد، استخدم الخيار ‎--force:

php artisan migrate --force

التراجع عن التهجيرات

للتراجع عن عمليّة التهجير الأخيرة، يمكنك استخدام الأمر rollback، وسيتراجع هذا الأمر عن آخر دفعة من عمليات التهجير، والذي قد يتضمن العديد من ملفات تهجير:

php artisan migrate:rollback

يمكنك التراجع عن عدد محدود من التهجيرات من خلال توفير خيار step لأمر rollback. على سبيل المثال، سيستعيد هذا الأمر آخر خمس عمليات تهجير:

php artisan migrate:rollback --step=5

سيعمل الأمر migrate:reset على استعادة جميع عمليات التهجير في تطبيقك:

php artisan migrate:reset

التراجع والتهجير في أمر واحد

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

php artisan migrate:refresh

//  إنشاء قاعدة البيانات وتنفيذ البذر

php artisan migrate:refresh --seed

يمكنك التراجع وتهجير عدد محدود من عمليات التهجير عن طريق توفير خيار step، لأمر refresh، فعلى سبيل المثال، الأمر التالي سيتراجع عن آخر خمس عمليات تهجير:

php artisan migrate:refresh --step=5

حذف جميع الجداول والتهجير

سيحذف الأمر migrate:fresh جميع الجداول من قاعدة البيانات وسيُنفّذ أمر migrate:

php artisan migrate:fresh

php artisan migrate:fresh --seed

الجداول

إنشاء الجداول

لإنشاء جدول قاعدة بيانات جديد، استخدم التابع create على الواجهة الساكنة Schema. يقبل هذا التابع معاملين: الأوّل اسم الجدول والثاني نطاق مغلق Closure الذي يقبل كائن Blueprint يمكن استخدامه لتعريف جدول جديد:

Schema::create('users', function (Blueprint $table) {

   $table->increments('id');

});

بالطبع، عند إنشاء الجدول، يمكنك استخدام أي من توابع عمود منشئ المخطّطات لتعريف أعمدة الجدول.

التحقق من وجود جدول أو عمود

يمكنك التحقق بسهولة من وجود جدول أو عمود باستخدام التابعين hasTable و hasColumn:

if (Schema::hasTable('users')) {

  //
}
if (Schema::hasColumn('users', 'email')) {

  //
}

الاتصال بقاعدة البيانات وخيارات الجداول

إذا رغبت بإجراء عملية تخطيط على اتصال قاعدة البيانات الذي هو ليس باتصالك الافتراضي يمكنك استخدام التابع Connection:

Schema::connection('foo')->create('users', function (Blueprint $table) {

   $table->increments('id');

});

يمكنك استخدام الأوامر التالية على منشئ المخطّطات لتحديد خيارات الجداول:

الأمر الوصف
;'‎$table->engine = 'InnoDB تحديد محرّك تخزين الجداول (MySQl).
;'‎$table->charset = 'utf8 تحديد مجموعة حروف افتراضيّة للجدول (MySQL).
;'‎$table->collation = 'utf8_unicode_ci تحديد الترتيب الافتراضي للجدول (MySQL).
;()‎$table->temporary إنشاء جدول مؤقت (باستثناء SQL Server).

إعادة تسمية أو حذف الجداول

لإعادة تسمية جدول قاعدة بيانات موجود، استخدم التابع rename:

Schema::rename($from, $to);

لحذف جدول موجود، يمكنك استخدام التوابع drop أو dropIfExists:

Schema::drop('users');

Schema::dropIfExists('users');

إعادة تسمية الجداول باستخدام مفاتيح ثانويّة

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

الأعمدة

إنشاء الأعمدة

يمكن استخدام التابع table على الواجهة الساكنة Schema لتحديث الجداول الموجودة، ومثل التابع create، سيقبل التابع table معاملين: الأول هو اسم الدّول والثاني هو  Closure يقبل نسخة Blueprint يمكنك استخدامها لإضافة أعمدة إلى الجدول:

أنواع الأعمدة المتاحة

يحتوي منشئ المخططات على مجموعة متنوّعة من أنواع الأعمدة التي يمكنك تحديدها عند إنشاء الجداول:

الأمر الوصف
$table->bigIncrements('id');‎ زيادة UNSIGNED BIGINT تلقائيًا (المفتاح الرئيسي) للعمود المعني.
$table->bigInteger('votes');‎ عمود BIGINT المكافئ.
$table->binary('data');‎ عمود BLOB المكافئ.
$table->boolean('confirmed');‎ عمود BOOLEAN المكافئ.
$table->char('name', 100);‎ عمود CHAR المكافئ مع طول اختياري.
$table->date('created_at');‎ عمود DATE المكافئ.
$table->dateTime('created_at');‎ عمود DATETIME المكافئ.
$table->dateTimeTz('created_at');‎ عمود DATETIME المكافئ (مع الوحدة الزمنيّة).
$table->decimal('amount', 8, 2);‎ عمود DECIMAL المكافئ مع الدقّة (مجموع الأرقام) ومقياس (الأرقام العشريّة).
$table->double('amount', 8, 2);‎ عمود DOUBLE المكافئ مع الدقّة (مجموع الأرقام) والمقياس (أرقام عشريّة).
$table->enum('level', ['easy', 'hard']);‎ عمود ENUM المكافئ.
$table->float('amount', 8, 2);‎ عمود FLOAT المكافئ مع الدقّة (مجموع الأرقام) والمقياس (أرقام عشريّة).
$table->geometry('positions');‎ عمود GEOMETRY المكافئ.
$table->geometryCollection('positions');‎ عمود GEOMETRYCOLLECTION المكافئ.
$table->increments('id');‎ زيادة UNSIGNED INTEGER تلقائيًا (المفتاح الرئيسي) للعمود المعني.
$table->integer('votes');‎ عمود INTEGER المكافئ.
$table->ipAddress('visitor');‎ عمود عنوان IP المكافئ.
$table->json('options');‎ عمود JSON المكافئ.
$table->jsonb('options');‎ عمود JSONB المكافئ.
الأمر الوصف
$table->lineString('positions');‎ عمود LINESTRING المكافئ.
$table->longText('description');‎ عمود LONGTEXT المكافئ.
$table->macAddress('device');‎ عمود عنوان MAC المكافئ.
$table->mediumIncrements('id');‎ زيادة UNSIGNED MEDIUMINT تلقائيًا (المفتاح الرئيسي) للعمود المعني.
$table->mediumInteger('votes');‎ عمود MEDIUMINT المكافئ.
$table->mediumText('description');‎ عمود MEDIUMTEXT المكافئ.
$table->morphs('taggable');‎ يضيف أعمدة taggable_id UNSIGNED BIGINT و taggable_type VARCHAR المكافئة.
$table->multiLineString('positions');‎ عمود MULTILINESTRING المكافئ.
$table->multiPoint('positions');‎ عمود MULTIPOINT المكافئ.
$table->multiPolygon('positions');‎ عمود MULTIPOLYGON المكافئ.
$table->nullableMorphs('taggable');‎ أضف اصدارات معدومة من أعمدة morphs()‎.
$table->nullableTimestamps();‎ اسم بديل لتابع timestamps()‎.
$table->point('position');‎ عمود POINT المكافئ.
$table->polygon('positions');‎ عمود POLYGON المكافئ.
$table->rememberToken();‎ إضافة remember_token VARCHAR(100)‎ معدوم مكافئ للعمود.
$table->smallIncrements('id');‎ زيادة UNSIGNED SMALLINT تلقائيًا (المفتاح الرئيسي) للعمود المعني.
$table->smallInteger('votes');‎ عمود SMALLINT المكافئ.
$table->softDeletes();‎ إضافة عمود deleted_at TIMESTAMP معدوم مكافئ للحذف الناعم.
$table->softDeletesTz();‎ إضافة عمود deleted_at TIMESTAMP معدوم  (مع المنطقة الزمنيّة) مكافئ للحذف الناعم.
$table->string('name', 100);‎ عمود VARCHAR المكافئ مع طول اختياري.
الأمر الوصف
$table->text('description');‎ عمود TEXT المكافئ.
$table->time('sunrise');‎ عمود TIME المكافئ.
$table->timeTz('sunrise');‎ عمود TIME (مع المنطقة الزمنيّة) المكافئ.
$table->timestamp('added_on');‎ عمود TIMESTAMP المكافئ.
$table->timestampTz('added_on');‎ عمود TIMESTAMP (مع المنطقة الزمنيّة) المكافئ.
$table->timestamps();‎ إضافة أعمدة TIMESTAMP created_atو updated_at العدميّة المكافئة.
$table->timestampsTz();‎ إضافة أعمدة TIMESTAMP created_atو updated_at العدميّة (مع المنطقة الزمنيّة)  المكافئة.
$table->tinyIncrements('id');‎ زيادة UNSIGNED TINYINT تلقائيًا (المفتاح الرئيسي) للعمود المعني.
$table->tinyInteger('votes');‎ عمود TINYINT المكافئ.
$table->unsignedBigInteger('votes');‎ عمود UNSIGNED BIGINT المكافئ.
$table->unsignedDecimal('amount', 8, 2);‎ عمود UNSIGNED DECIMAL المكافئ مع الدقّة (مجموع الأرقام) والمقياس (أرقام عشريّة).
$table->unsignedInteger('votes');‎ عمود UNSIGNED INTEGER المكافئ.
$table->unsignedMediumInteger('votes');‎ عمود UNSIGNED MEDIUMINT المكافئ.
$table->unsignedSmallInteger('votes');‎ عمود UNSIGNED SMALLINT المكافئ.
$table->unsignedTinyInteger('votes');‎ عمود UNSIGNED TINYINT المكافئ.
$table->uuid('id');‎ عمود UUID المكافئ.
$table->year('birth_year');‎ عمود YEAR المكافئ.

محدّدات العمود

بالإضافة إلى أنواع العمود الموجودة أعلاه، هنالك العديد من "محدّدات" العمود التي يمكنك استخدامها أثناء إضافة عمود إلى جدول قاعدة البيانات. على سبيل المثال، لجعل العمود معدوم ‎،(nullable)‎ يمكنك استخدام التابع nullable:

Schema::table('users', function (Blueprint $table) {
   $table->string('email')->nullable();
});

فيما يلي قائمة بكافة محدّدات الأعمدة المتاحة، وهي لا تتضمّن محدّدات الفهرس:

المحدّد الوصف
('‎->after('column وضع العمود بعد عمود آخر (MySQL)
()‎->autoIncrement تفعيل عملية الزيادة التلقائيّة لأعمدة INTEGER (مفتاح رئيسي)
('‎->charset('utf8 تحديد مجموعة حروف افتراضيّة للعمود (MySQL).
('‎->collation('utf8_unicode_ci تحديد الترتيب الافتراضي للعمود (MySQL/SQL Server).
('‎->comment('my comment إضافة تعليق إلى عمود (MySQL).
(‎->default($value تحديد قيمة افتراضيّة للعمود.
()‎->first وضع العمود في بداية الجدول (MySQL).
(‎->nullable($value = true السماح (بشكل افتراضي) بإضافة قيم NULL إلى العمود.
(‎->storedAs($expression إنشاء عمود مولّد ومخزّن (MySQL).
()‎->unsigned تحديد أعمدة INTEGER على أنها UNSIGNEDL(MySQL)‎.
‎->useCurrent تحديد أعمدة TIMESTAMP لاستخدام CURRENT_TIMESTAMP كقيمة افتراضيّة.
(‎->virtualAs($expression إنشاء عمود مولّد افتراضي (MySQL).

تعديل الأعمدة

المتطلبات الأساسيّة

قبل تعديل عمود، تأكد من إضافة الاعتماديّة doctrine/dbal إلى ملف composer.json. تُستخدم مكتبة Doctrine DBAL لتحديد الحالة الحاليّة للعمود وإنشاء استعلامات SQL اللازمة لإجراء التعديلات المحدّدة على العمود:

composer require doctrine/dbal

تحديث خصائص العمود

يسمح لك التابع change بتعديل بعض أنواع الأعمدة الموجودة إلى نوع جديد أو تعديل خصائص العمود. فعلى سبيل المثال، لزيادة حجم عمود السلسلة النصيّة، ولتجربة هذا على التابع change، لنرفع حجم عمود name من 25 إلى 50:

Schema::table('users', function (Blueprint $table) {
   $table->string('name', 50)->change();
});

يمكننا تعديل عمود أيضًا ليكون معدومًا:

Schema::table('users', function (Blueprint $table) {
   $table->string('name', 50)->nullable()->change();
});

تنبيه: يمكنك تعديل هذه الأنواع من الأعمدة فقط: bigInteger و binary و boolean و date و dateTime و dateTimeTz و decimal و integer و json و longText و mediumText و smallInteger و string و text و time و unsignedBigInteger و unsignedInteger و unsignedSmallInteger.

إعادة تسمية الأعمدة

لإعادة تسمية عمود، يمكنك استخدام التابع renameColumn على منشئ المخططات.، وقبل إعادة تسمية عمود، تأكد من إضافة الاعتماديّة doctrine/dbal إلى ملف composer.json:

Schema::table('users', function (Blueprint $table) {
   $table->renameColumn('from', 'to');
});

تنبيه: إن تعديل أي عمود في الجدول الذي يملك عمود من نوع enum غير مدعوم حاليًا.

حذف الأعمدة

يمكنك استخدام التابع dropColumn على مُنشئ المخططات لحذف عمود. وقبل حذف عمود من قاعدة بيانات SQLite، ستحتاج إلى إضافة الاعتماديّة doctrine/dbal إلى ملف composer.json وتشغيل أمر composer update في الطرفيّة لتثبيت المكتبة:

Schema::table('users', function (Blueprint $table) {

   $table->dropColumn('votes');

});

يمكنك حذف أعمدة متعدّدة من جدول عن طريق تمرير مصفوفة من أسماء الأعمدة إلى التابع dropColumn:

Schema::table('users', function (Blueprint $table) {

   $table->dropColumn(['votes', 'avatar', 'location']);

});

تنبيه: إن حذف أو تعديل أعمدة متعدّدة بعمليّة تهجير واحدة وباستخدام قاعدة بيانات SQLite غير مدعوم في الوقت الحالي.

الأسماء البديلة للأوامر المتوفّرة

الأمر الوصف
;()‎$table->dropRememberToken حذف عمود remember_token.
;()‎$table->dropSoftDeletes حذف عمود deleted_at.
;()‎$table->dropSoftDeletes اسم بديل للتابع dropSoftDeletes()‎.
;()‎$table->dropTimestamps حذف أعمدة created_at وupdated_at.
;()‎$table->dropTimestampsTz اسم بديل للتابع dropTimestamps()‎.

الفهارس

إنشاء الفهارس

يدعم مُنشئ المخططات العديد من أنواع الفهارس. أولًا، دعنا نلقي نظرة على المثال الذي يحدد قيم العمود الذي يجب أن يكون فريد، ولإنشاء الفهرس، يمكننا ربط التابع unique بتعريف العمود:

$table->string('email')->unique();

وبدلًا من ذلك، يمكنك إنشاء الفهرس بعد تعريف العمود. فعلى سبيل المثال:

$table->unique('email');

يمكنك حتى تمرير مصفوفة من الأعمدة لتابع الفهرس لإنشاء فهرس مركّب:

$table->index(['account_id', 'created_at']);

سيُنشئ Laravel بشكل تلقائي اسم فهرس معقول، لكن يمكنك تمرير معامل ثاني للتابع لتحديد الاسم بنفسك:

$table->unique('email', 'unique_email');

أنواع الفهارس المتاحة

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

الأمر الوصف
;('‎$table->primary('id إضافة مفتاح رئيسي.
;(['‎$table->primary(['id', 'parent_id إضافة مفاتيح مركّبة.
;('‎$table->unique('email إضافة فهرس فريد.
;('‎$table->index('state إضافة فهرس عادي.
;('‎$table->spatialIndex('location إضافة فهرس مكاني (باستثناء SQLite).

طول الفهرس و MySQL/MariaDB

يستخدم Laravel مجموعة حروف utf8mb4 بشكل افتراضي، والتي تتضمّن دعمًا لتخزين "الوجوه التعبيريّة - الإيموجي" في قاعدة البيانات. إذا كنت تستخدم نسخة من MySQL أقدم من الإصدار  5.7.7 أو MariaDB أقدم من الإصدار 10.2.2، فستحتاج إلى ضبط طول السلسلة النصيّة الافتراضي المولّد من التهجيرات بشكل يدوي لكي يتمكن MySQL من إنشاء الفهارس لهم، ويمكنك ضبط طولها عن طريق استدعاء التابع Schema::defaultStringLength داخل AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
* مَهِّد أية خدمات تطبيقية
*
* @return void
*/

public function boot()

{
   Schema::defaultStringLength(191);
}

بدلًا من ذلك، يمكنك تفعيل خيار innodb_large_prefix لقاعدة بياناتك. راجع توثيق قاعدة البيانات للحصول على الإرشادات على كيفيّة تفعيل هذا الخيار بشكل صحيح.

إعادة تسمية الفهارس

لإعادة تسمية الفهرس، يمكنك استخدام التابع renameIndex الذي يقبل اسم الفهرس الحالي كمعامل أوّل والاسم المطلوب كمعامل ثاني:

$table->renameIndex('from', 'to');

حذف الفهارس

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

الأمر الوصف
$table->dropPrimary('users_id_primary');‎ احذف مفتاح رئيسي من جدول المستخدمين.
$table->dropUnique('users_email_unique');‎ احذف فهرس فريد من جدول المستخدمين.
$table->dropIndex('geo_state_index');‎ احذف فهرس بسيط من جدول geo.
$table->dropSpatialIndex('geo_location_spatialindex');‎ احذف فهرس مكاني من جدول geo (باستثناء SQLite).

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

Schema::table('geo', function (Blueprint $table) {
   $table->dropIndex(['state']); // Drops index 'geo_state_index'
});

قيود المفتاح الثانوي

يوفّر Laravel دعم لإنشاء قيود المفاتيح الالثانوية، والتي تُستخدم لفرض التكامل المرجعي على مستوى قاعدة البيانات. فعلى سبيل المثال، لنعرّف عمود user_id على جدول posts الذي يشير إلى عمود id في جدول users:

Schema::table('posts', function (Blueprint $table) {
   $table->unsignedInteger('user_id');
   $table->foreign('user_id')->references('id')->on('users');
});

يمكنك تحديد الإجراء المطلوب أيضًا لخصائص "on delete" و"on update" من القيد:

$table->foreign('user_id')
     ->references('id')->on('users')
     ->onDelete('cascade');

لحذف مفتاح ثانوي، يمكنك استخدام التابع dropForeign، وتستخدم قيود المفتاح الثانوي نفس اتفاقيّة تسمية الفهارس، ولذلك، سنسلسل اسم الجدول والأعمدة في القيد ومن ثم نضيف الاسم مع "_foreign":

$table->dropForeign('posts_user_id_foreign');

أو يمكنك تمرير قيمة مصفوفة التي ستُستخدم تلقائيًا اسم القيد التقليدي عند الحذف:

$table->dropForeign(['user_id']);

يمكنك تفعيل أو تعطيل قيود المفتاح الثانوي داخل التهجيرات عن طريق استخدام التوابع:

Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

مصادر