يتيح إطار العمل لارافيل Laravel المعتمد على لغة PHP عدة أدوات مُستخدمة مع قواعد البيانات ومن أهمها أداتي التهجير وتوليد البيانات أو البذر seeder اللتان تساعدان المطور على تهيئة قاعدة البيانات أو التخلص منها أو إعادة إنشائها بسرعة عالية، إذ تقلل هذه الأدوات من مشاكل عدم الاتساق الخاصة بقاعدة البيانات، والتي تظهر عند تشارك عدة مطورين باستخدام نفس قاعدة البيانات أو نفس التطبيق في الوقت ذاته. ينفذ المطوّر الذي يحتاج للعمل مع قواعد البيانات المشتركة مجموعةً بسيطةً من أوامر "artisan" لإعداد قاعدة البيانات لتصبح جاهزة للاستخدام.
نستخدم في عملنا هذا عدة عمليات تهجير لقواعد البيانات وتوليد بيانات نموذجية لملء قاعدة بيانات خاصة بتطبيق لارافيل توضيحي، وسنحذف الجداول ونعيد إنشائها عدة مرات باستخدام أوامر "artisan" فقط.
المتطلبات الأساسية
لاتباع خطوات هذا المقال ستحتاج ما يلي:
- الوصول إلى حاسب يعمل بنظام التشغيل أوبنتو Ubuntu ذي رقم إصدار 18.04 أو إلى خادم تطوير يعمل بنفس نظام التشغيل المذكور بواسطة مستخدم ذي صلاحيات إدارة sudo ولا يفضل استخدام حساب الجذر Root لأسباب تتعلق بأمان الخادم كما يفضّل وجود جدار حماية نشط في حال العمل على خادم بعيد.
- تثبيت الأداة دوكر Docker على الخادم.
- تثبيت الأداة دوكر كومبوز Docker Compose على الخادم.
ملاحظة: نستخدم بيئة تطوير حاويات تديرها الأداة دوكر كومبوز لتشغيل التطبيق كما يمكن اختيار حزمة التخديم LEMP لتشغيله.
الخطوة 1- الحصول على التطبيق التوضيحي
نبدأ بتحميل تطبيق لارافيل التوضيحي من مخزن Github وننتقل إلى الفرع tutorial-02، الذي يحتوي إعداد الأداة دوكر كومبوز لتشغيل التطبيق على الحاويات، نحمّل التطبيق التوضيحي في المجلد الافتراضي ولكن يمكن اختيار أي مجلد آخر إذا دعت الحاجة لذلك، ومن ثم ننفذ الأوامر التالية:
cd ~ curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-2.0.1.zip -o travellist.zip
يبدأ تحميل الملف المضغوط بصيغة "zip." لذلك يجب عند انتهاء التحميل فك الضغط بعد التأكد من تحديث الحزم الخاصة بنظام التشغيل ما لم تكن محدّثة مؤخرًا، وذلك بتنفيذ الأوامر التالية:
sudo apt update
نثبت الحزمة "unzip" بتنفيذ الأمر:
sudo apt install unzip
مع إتمام عملية التثبيت نفك ضغط الملف بتنفيذ الأمر:
unzip travellist.zip
نعيد تسمية المجلد ليصبح باسم "travellist-demo" لسهولة الوصول إليه بتنفيذ الأمر:
mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo
الخطوة 2- إعداد ملف "env." الخاص بالتطبيق
يتضمن الملف "env." عمليات الضبط الخاصة بالبيئة، مثل بيانات الاعتماد Credentials وأية معلومات تختلف بين عمليات نشر التطبيقات، لذلك لا يُضمّن هذا الملف ضمن ملفات التحكم بالإصدارات لكي لا تنتشر هذه المعلومات لجميع المستخدمين الذين يستخدمون صورة التطبيق لاحقًا.
تحذير: يحتوي ملف ضبط البيئة على معلومات حساسة حول الخادم، بما في ذلك بيانات اعتماد قاعدة البيانات ومفاتيح الأمان، لهذا السبب لا يجب مشاركة هذا الملف علنًا.
توجد أولوية للقيم الموجودة في الملف "env." على القيم الموجودة في ملفات التهيئة الأخرى الموجودة في المجلد "config"، وتتطلب كل عملية تثبيت في بيئة جديدة ملف بيئة مخصص لتعريف معلومات خاصة، مثل إعدادات الاتصال بقاعدة البيانات، خيارات التصحيح debug والرابط الخاص بالتطبيق URL، إضافةً لبقية العناصر التي تختلف تبعاً للبيئة التي يعمل بها التطبيق.
ننتقل إلى المجلّد "travellist-demo" بتنفيذ الأمر:
cd travellist-demo
ننشئ ملف "env." جديد لتخصيص خيارات الإعداد لبيئة التطوير التي نعدها. ويمكننا نسخ الملف "example.env" الذي الموجود افتراضيًا ضمن أي تطبيق لارافيل بتنفيذ الأمر:
cp .env.example .env
نستخدم محرر نانو nano لتعديل محتوى الملف بتنفيذ الأمر:
nano .env
يبدو هذا الملف بالشكل التالي:
APP_NAME=Travellist APP_ENV=dev APP_KEY= APP_DEBUG=true APP_URL=http://localhost:8000 LOG_CHANNEL=stack DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=travellist DB_USERNAME=travellist_user DB_PASSWORD=password …
يحتوي ملف "env." الحالي الخاص بتطبيق "travellist" التوضيحي إعدادات لاستخدام بيئة الحاويات التي أنشأناها باستخدام أداة دوكر كومبوز. لا نحتاج إلى تغيير أي من هذه القيم، ولكن يمكن تعديل DB_DATABASE
و DB_USERNAME
و DB_PASSWORD
عند الحاجة، حيث أنّ هذه القيم تُسحب بالاعتماد على الملف docker-compose.yml
تلقائيًا لإعداد قاعدة البيانات.
نتأكد من بقاء المتغير DB_HOST
دون تغيير، لأنه يشير إلى اسم خادم قاعدة البيانات داخل بيئة دوكر كومبوز. نضغط على الاختصار "CTRL + X" ثم زر "Y" وأخيرًا زر الإدخال "Enter" عند الانتهاء من تعديل الملف.
ملاحظة: نحتاج عند تشغيل التطبيق على خادم LEMP إلى تغيير القيم المشار إليها لتتوافق مع إعدادات قاعدة البيانات بما في ذلك المتغير "DB_HOST".
الخطوة 3- تثبيت اعتماديات التطبيق مع كومبوزر
نستخدم الأداة كومبوزر لإدارة الاعتمادية الخاصة ببرامج PHP، إذ تُستخدم لتثبيت جميع اعتماديات التطبيق والتأكد من إمكانية استخدام أوامر "artisan".
نُظهر بيئة دوكر كومبوز حيث نبني صورة "travellist" لتشغيل التطبيق مثل خدمة "app" كما تُحمَّل جميع صور دوكر المتعلقة بالتطبيق مثل "nginx" و "db" لتشكيل بيئة التطبيق الكاملة. ننفذ الأمر التالي لتحقيق ذلك:
docker-compose up -d
وسيكون الخرج على النحو التالي:
Creating network "travellist-demo_travellist" with driver "bridge" Building app Step 1/11 : FROM php:7.4-fpm ---> fa37bd6db22a Step 2/11 : ARG user ---> Running in 9259bb2ac034 … Creating travellist-app ... done Creating travellist-nginx ... done Creating travellist-db ... done
تستغرق هذه العملية بضع دقائق حتى تكتمل ومن ثم نشغّل كومبوزر لتثبيت اعتماديات التطبيق. نستخدم الأمر docker-compose exec
لتنفيذ أوامر كومبوزر وجميع الأوامر الأخرى ضمن حاوية خدمة التطبيق، إذ يسمح الأمرexec
بتنفيذ أي أمر على الحاويات التي يديرها دوكر كومبوز، ويُكتب هذا الأمر وفقًا للصيغة التالية:
docker-compose exec service_name command
إذ يُستبدل المتغير service_name
باسم الخدمة التي نرغب بتنفيذ الأمر عليها ويُستبدل المتغيرcommand
بالأمر الذي نريد تطبيقه.
ملاحظة: نتجاهل عمليات الأمر docker-compose exec
في حال استخدام خادم LEMP لتشغيل التطبيق التجريبي ونستخدم الأمر composer install
عوضًا عنه.
ننفذ الأمر composer install
ضمن الحاوية app
بتطبيق الأمر:
docker-compose exec app composer install
يظهر الخرج التالي بعد انتهاء التنفيذ:
Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 85 installs, 0 updates, 0 removals - Installing doctrine/inflector (1.3.1): Downloading (100%) - Installing doctrine/lexer (1.2.0): Downloading (100%) - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%) …
ننتظر إلى أن ينتهي كومبوزر من تثبيت اعتماديات التطبيق ومن ثم نستطيع تنفيذ أوامر "artisan". نختبر قدرة التطبيق على الاتصال بقاعدة البيانات بتنفيذ الأمر التالي الذي يفرّغ محتوى الجداول الموجودة مسبقًا:
docker-compose exec app php artisan db:wipe
يظهر الخرج التالي ما لم توجد مشكلة ما وعندها يكون التطبيق قادرًا على الاتصال بقاعدة البيانات:
Dropped all tables successfully.
نستخدم أداة "artisan" في تهجير وتوليد المعطيات بعد التأكد من قدرة التطبيق على الاتصال بقاعدة البيانات.
الخطوة 4- تهجير قاعدة البيانات
يتضمن الأمر "artisan" المُتاح افتراضيًا ضمن لارافيل عدة أوامر مساعدة تُستخدم في إدارة التطبيقات وتهيئة الأصناف الجديدة، نستخدم الأمر make:migration
لتوليد صنف تهجير بيانات جديد بالشكل التالي:
docker-compose exec app php artisan make:migration create_places_table
تستنتج لارافيل من الأمر السابق أن العملية المطلوبة هي عملية إنشاء create
وأنّ اسم الجدول المطلوب places
. تحدد لارافيل إذا ما كانت عملية التهجير تنشئ جدولًا جديدًا أم لا بناءً على الاسم الوصفي الموجود في الأمر make:migration
.
يظهر الخرج التالي بعد تنفيذ الأمر:
Created Migration: 2020_02_03_143622_create_places_table
يولَّد ملف جديد في المجلد "database/migrations" ضمن التطبيق ويُستخدم الطابع الزمني المضمّن في الملف المُنشأ تلقائيًا بوساطة لارافيل لتحديد الترتيب الذي تُنفّذ عمليات التهجير وفقًا له. نحرر الملف الذي ولّدناه باستخدام محرر النصوص المفضّل مع التركيز على استبدال اسم الملف أدناه باسم الملف الفعلي في حال وجود اختلاف بينهما.
nano database/migrations/2020_02_03_143622_create_places_table.php
يحتوي هذا الملف على صنفٍ يدعى CreatePlacesTable
كما هو مبين فيما يلي:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePlacesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('places', function (Blueprint $table) { $table->bigIncrements('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('places'); } }
يتضمن هذا الصنف تابعين هما up
و down
، اللتان تحتويان على شيفرة تهيئة التشغيل التي تحدد ما يحدث عند تنفيذ عملية التهجير وعند التراجع عنها.
نعدّل التابع up
بحيث يعكس الجدول places
البنية التي نستخدمها في تطبيقنا الحالي:
-
id
: حقل المفتاح الأساسي. -
name
: حقل اسم المكان. -
visited
: حقل يشير إذا ما حدثت زيارة لهذا المكان مسبقًا أم لا.
يقدِّم مُنشِئ المخططات schema في لارافيل طرقًا لإنشاء وتعديل وحذف الجداول في قاعدة البيانات، إذ يعرّف الصنف Blueprint
بنية الجدول ويقدم مجموعة توابع تحدّد حقول الجدول على نحوٍ مجرّد.
تُعد الشيفرة البرمجية المولّدة تلقائيًا حقلًا للمعرف الأساسي id
كما ينشئ التابع timestamps
حقلين من نوع معطيات timestamps
يُعدَلان آليًا عند إضافة قيم إلى الجدول أو عند تعديل القيم الموجودة مسبقًا ضمن الجدول، ويُضاف إلى هذه الحقول حقلين إضافيين هما name
و visited
.
يُضبط نوع الحقل name
ليكون سلسلة نصية "string" والحقل visited
من النوع "boolean" وتوضع القيمة "0" في الحقل visited
على أنها قيمة افتراضية لتمثّل عدم زيارة المكان مسبقًا ليصبح التابع الذي نعدّله على الشكل التالي:
… public function up() { Schema::create('places', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name', 100); $table->boolean('visited')->default(0); $table->timestamps(); }); } …
ملاحظة: توجد قائمة بجميع أنواع الأعمدة المتاحة ضمن التوثيق الخاص بلارافيل.
نحفظ الملف بعد التأكد من إضافة كامل المحتوى السابق، ثم نغلقه فتصبح قاعدة البيانات جاهزة للتهجير بتنفيذ الأمر:
artisan migrate
تُنشأ حاليًا جداول فارغة بالبنية التي اعتمدناها ولملء هذه الجداول ببيانات من اختيارنا لا بُد من استخدام مولّدات قواعد البيانات.
الخطوة 5- إنشاء مولدات قواعد البيانات
يستخدم الصنف الخاص Seeder لتوليد وإدخال البيانات إلى قاعدة البيانات، وتساعد هذه الميزة المطورين على إعادة إنشاء قاعدة البيانات وإدخال البيانات إليها بسرعة عالية دون الحاجة إلى عمليات يدوية لتحقيق ذلك. يولَّد صنف توليد بيانات آليًا باستخدام الأمر artisan
ويحمل هذا الصنف الاسم PlacesTableSeeder
بتنفيذ الأمر التالي:
docker-compose exec app php artisan make:seeder PlacesTableSeeder
يظهر ملف جديد اسمه "PlacesTableSeeder.php" ضمن المجلد "database/seeds". نحرّر محتوى الملف باستخدام محرر النصوص المفضّل:
nano database/seeds/PlacesTableSeeder.php
يتضمن الملف "PlacesTableSeeder.php" المُولّد تلقائيًا المحتوى التالي:
<?php use Illuminate\Database\Seeder; class PlacesTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // } }
يحتوي الصنف على تابع فارغ run
والذي يبدأ عمله عند تنفيذ الأمر db:seed
. نعدّل محتوى هذا التابع ليتضمن التعليمات التي تُدخِل عينةً من البيانات إلى قاعدة البيانات، ونستخدم مُنشئ استعلامات لارافيل لتنفيذ ذلك.
يتيح منشئ استعلام لارافيل واجهة سلسة لعمليات قاعدة البيانات، مثل إدراج البيانات وتحديثها وحذفها واسترجاعها، كما أنّه يحمي قاعدة البيانات من هجمات حقن SQL. يمكن الوصول إلى باني الاستعلامات بالاعتماد على واجهة خاصة تدعى facade وهي وكيل Proxy ساكن إلى الأصناف الخاصة بقاعدة البيانات ضمن حاوية التطبيق.
ننشئ متغير ساكن من نوع مصفوفة ضمن الصنف والذي يحتوي على جميع الأماكن التي نرغب بإدخالها إلى قاعدة البيانات مثل مصفوفة. نستخدم حلقة foreach
للتجوال على جميع القيم وإدخال كل منها بالاعتماد على باني الاستعلامات وسندعو هذا المتغير بالاسم places$
كما في الشكل التالي:
<?php use Illuminate\Database\Seeder; class PlacesTableSeeder extends Seeder { static $places = [ 'Berlin', 'Budapest', 'Cincinnati', 'Denver', 'Helsinki', 'Lisbon', 'Moscow', 'Nairobi', 'Oslo', 'Rio', 'Tokyo' ]; …
نستخدم عبارة use
ضمن الصنف PlacesTableSeeder
للمساعدة في الإشارة إلى واجهات قاعدة البيانات ضمن الشيفرة البرمجية كما يلي:
<?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class PlacesTableSeeder extends Seeder …
نستخدم حلقة foreach
للتجوال ضمن قيم المصفوفة places$
وإدخال كل من هذه القيم ضمن الجدول places
باستخدام باني الاستعلامات كما يلي:
… public function run() { foreach (self::$places as $place) { DB::table('places')->insert([ 'name' => $place, 'visited' => rand(0,1) == 1 ]); } }
تتكرر تعليمات حلقة foreach
على قيم المصفوفة الساكنة places$
واحدةً تلو الأخرى، ومع كل تكرار تُدخِل واجهة قاعدة البيانات سطرًا جديدًا ضمن الجدول places
، بحيث يُضاف قيمة اسم المدينة الموجود في الجدول ضمن قاعدة البيانات من القيمة الموافقة في المصفوفة places$
، كما توضع قيمة عشوائية إما أن تكون 0 أو 1 ضمن الحقل visited
.
يصبح محتوى الشيفرة البرمجية الكاملة للصف PlacesTableSeeder
بعد تجميع الأجزاء البرمجية السابقة على النحو التالي:
<?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class PlacesTableSeeder extends Seeder { static $places = [ 'Berlin', 'Budapest', 'Cincinnati', 'Denver', 'Helsinki', 'Lisbon', 'Moscow', 'Nairobi', 'Oslo', 'Rio', 'Tokyo' ]; /** * Run the database seeds. * * @return void */ public function run() { foreach (self::$places as $place) { DB::table('places')->insert([ 'name' => $place, 'visited' => rand(0,1) == 1 ]); } } }
لا تُحمّل أصناف توليد البيانات آليًا ضمن التطبيق، أي أنّه يجب تعديل الصنف DatabaseSeeder
الرئيسي لتضمينها استدعاءً للصنف الذي أنشأناه. نحرر الملف "database/seeds/DatabaseSeeder.php" باستخدام محرر نانو أو أي محرر مفضل لديك بتنفيذ الأمر التالي:
nano database/seeds/DatabaseSeeder.php
لا يختلف الصنف "DatabaseSeeder" عن أية صنف آخر لتوليد البيانات، إذ أنّه يرث الصنف "Seeder" ويمتلك التابع "run" الذي نُحدّث محتواه ليتضمن استدعاءً للصنف "PlacesTableSeeder".
نحدّث محتوى التابع run
ضمن الصنف DatabaseSeeder
بإزالة التعليق الموجود ضمنه وإضافة ما يلي:
… public function run() { $this->call(PlacesTableSeeder::class); } …
يصبح محتوى الشيفرة البرمجية للصنف DatabaseSeeder
بعد التحديث كما يلي:
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(PlacesTableSeeder::class); } }
نحفظ الملف السابق وبهذا يكون قد انتهى إعداد كل من وظيفتي التهجير وتوليد البيانات الخاصتين بالجدول places
ويبقى تنفيذ هذه الإجراءات.
الخطوة 6- ترحيل قواعد البيانات وتوليد البيانات
نتأكد من أنّ التطبيق الذي أعددناه جاهز للعمل، ومن ثم نُعدّ مفاتيح التشفير الخاصة بالتطبيق وعندها نستطيع اختبار التطبيق بطلبه ضمن المتصفح ومراقبة استجابة الخادم للطلب. نولّد مفاتيح التشفير الضرورية لعمل لارافيل وذلك باستخدام الأمر التالي:
docker-compose exec app php artisan key:generate
نطلب من المتصفح رابط التطبيق على المنفذ 8000 كما يلي:
http://server_host_or_ip:8000
نرى الاستجابة التالية على المتصفح:
نستنتج أن التطبيق يستطيع الاتصال بقاعدة البيانات لكنه لم يعثر على جدول باسم places
ولذا ننشئ هذا الجدول بأمر التهجير التالي:
docker-compose exec app php artisan migrate
يظهر الخرج التالي:
Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)
نلاحظ تنفيذ عمليات تهجير إضافية إلى جانب التهجير create_places_table
الذي أعددناه، إذ يجري إعداد هذه العمليات الإضافية عند تثبيت لارافيل. لا تفيد هذه الجداول ضمن نطاق العمل الحالي إلا أنها أساسيةٌ عند توسيع عمل التطبيق لتشمل المهام المجدولة والتعامل مع المستخدمين المسجّلين ولهذا لا نعدل في محتواها الآن.
تخلو الجداول السابقة من البيانات ومن أجل توليد بيانات في الجدول places نستخدم الأمر db:seed
بالمحتوى الذي أنشأناه مسبقًا:
docker-compose exec app php artisan db:seed
يشغّل الأمر السابق المُولد الذي أنشأناه ضمن الصنف PlacesTableSeeder
، ويظهر خرجٌ مشابهٌ لما يلي:
Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.
نعيد تحميل صفحة المتصفح لتظهر بالشكل التالي:
يمكن إفراغ الجداول من بياناتها بتنفيذ الأمر:
docker-compose exec app php artisan db:wipe
ويكون الخرج على النحو التالي:
Dropped all tables successfully.
ويمكن تنفيذ عمليتي التهجير والتوليد بأمر برمجي واحد بتنفيذ الأمر:
docker-compose exec app php artisan migrate --seed
ويكون الخرج على النحو التالي:
Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.07 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds) Migrating: 2020_02_10_144134_create_places_table Migrated: 2020_02_10_144134_create_places_table (0.03 seconds) Seeding: PlacesTableSeeder Seeded: PlacesTableSeeder (0.06 seconds) Database seeding completed successfully.
يمكن التراجع عن عملية التهجير بتنفيذ الأمر:
docker-compose exec app php artisan migrate:rollback
حيث يُستدعى التابع down
من أجل كل عملية تهجير معرّفة ضمن الصنف وتكون هذه الأصناف مجمّعةً في مجلد "migrations" حيث تجري إزالة جميع الجداول التي أنشأتها أصناف التهجير باستثناء تلك التي أنشأها المستخدم يدويًا. يظهر لدينا خرج مشابهٌ لما يلي:
Rolling back: 2020_02_10_144134_create_places_table Rolled back: 2020_02_10_144134_create_places_table (0.02 seconds) Rolling back: 2019_08_19_000000_create_failed_jobs_table Rolled back: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds) Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.02 seconds)
يفيد أمر التراجع بصورةٍ خاصة عندما نعدّل النماذج الخاصة بالتطبيق علمًا أنّ الأمر "db:wipe" لا يكون متاحًا للاستخدام كما في حالة اعتماد أكثر من نظام على قاعدة بيانات مشتركة.
الخاتمة
تضمنّت هذه المقالة توضيحًا بمدى أهمية عمليات تهجير وتوليد البيانات ضمن قاعدة البيانات من أجل إعداد واختبار قواعد البيانات الخاصة بتطبيقات لارافيل من الإصدار 6.
ترجمة –وبتصرف- للمقال How To Use Database Migrations and Seeders to Abstract Database Setup in Laravel لصاحبه Erika Heidi.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.