إنشاء بيانات تجريبية بسهولة Factories و Seeders و Faker في Laravel
بعد أن تعلّمنا في الدروس السابقة كيفية إنشاء قواعد البيانات والجداول باستخدام Migrations، وكيفية التعامل مع البيانات باستخدام Models وEloquent، ثم تعلّمنا كيفية إنشاء العلاقات بين الجداول، نصل الآن إلى موضوع مهم جدًا في تطوير تطبيقات Laravel: إنشاء البيانات التجريبية واختبار التطبيق ببيانات واقعية.
تخيل أنك أنشأت تطبيق مدونة يحتوي على عشرات المقالات والمستخدمين والتعليقات والتصنيفات. هل ستقوم بإضافة كل سجل يدويًا من خلال لوحة الإدارة؟ بالتأكيد لا.
هنا تأتي أهمية ثلاثة مفاهيم أساسية في Laravel:
- Factories
- Seeders
- Faker
تسمح لك هذه الأدوات بإنشاء مئات أو آلاف السجلات بسرعة، وربطها ببعضها، وتجهيز قاعدة البيانات أثناء مرحلة التطوير والاختبار.
في هذا الدرس سنبني مثالًا عمليًا على نظام مقالات يحتوي على Users وArticles، وسنتعلم كيف ننشئ بيانات وهمية ومنظمة يمكن استخدامها أثناء تطوير التطبيق.
ما هي Factories في Laravel؟
الـ Factory هي طريقة لتعريف مجموعة من البيانات الافتراضية التي يمكن استخدامها لإنشاء سجلات جديدة من Model معين.
بدلًا من كتابة:
Article::create([
'title' => 'Laravel Tutorial',
'slug' => 'laravel-tutorial',
'content' => 'Learn Laravel step by step...',
]);
ثم تكرار العملية عشرات المرات، يمكننا إنشاء Factory تحدد شكل البيانات، وبعد ذلك نطلب من Laravel إنشاء العدد الذي نريده.
مثلًا:
Article::factory()->count(20)->create();
السطر السابق يمكنه إنشاء 20 مقالًا باستخدام البيانات التي عرّفناها في Factory.
توثيق Laravel الرسمي يوضح أن Factories تعتمد على تعريف definition() لإرجاع القيم الافتراضية، ويمكنها استخدام Faker لإنشاء بيانات عشوائية مناسبة.
ما هو Faker؟
Faker هو مكتبة تستخدم لإنشاء بيانات وهمية تشبه البيانات الحقيقية.
يمكن استخدامها لإنشاء:
- أسماء.
- بريد إلكتروني.
- عناوين.
- جمل.
- نصوص.
- أرقام.
- تواريخ.
- عناوين URL.
- بيانات أخرى كثيرة.
مثلًا:
fake()->name()
يمكن أن يعيد اسمًا عشوائيًا.
وهذا:
fake()->email()
يمكن أن يعيد بريدًا إلكترونيًا وهميًا.
وهذا:
fake()->sentence()
ينشئ جملة عشوائية.
وهذا:
fake()->paragraph()
ينشئ فقرة نصية.
ميزة Faker أنك لا تحتاج إلى كتابة بيانات مختلفة لكل سجل بنفسك.
لماذا نحتاج إلى Factories وFaker؟
هناك عدة أسباب تجعل هذه الأدوات مهمة جدًا أثناء تطوير Laravel.
اختبار تصميم الواجهة
عندما تبني صفحة تعرض المقالات، من المفيد أن ترى كيف ستبدو الصفحة عندما تحتوي على 10 أو 50 أو 100 مقال.
بدلًا من إدخال هذه البيانات يدويًا، يمكنك إنشاءها باستخدام Factory.
اختبار Pagination
إذا كانت الصفحة تعرض 10 مقالات في كل صفحة، فمن الصعب اختبار Pagination بوجود مقالين فقط.
يمكنك إنشاء 100 مقال:
Article::factory()->count(100)->create();
وبذلك يمكنك اختبار الصفحات المختلفة.
اختبار البحث
وجود بيانات كثيرة يسمح لك باختبار البحث والتصفية والترتيب.
اختبار العلاقات
إذا كان لديك User لديه Articles، وArticle لديه Comments، يمكنك إنشاء هذه البيانات والعلاقات تلقائيًا.
تطوير لوحة الإدارة
لوحة الإدارة تحتاج عادةً إلى كمية كبيرة من البيانات حتى تستطيع اختبار:
- الجداول.
- Pagination.
- البحث.
- الفلاتر.
- الترتيب.
- الإحصائيات.
- الصلاحيات.
ما هي Seeders؟
الـ Seeder هو كلاس مسؤول عن إدخال بيانات إلى قاعدة البيانات.
توجد Seeders في:
database/seeders
ويأتي Laravel افتراضيًا مع:
DatabaseSeeder.php
يمكن استخدامه كنقطة البداية لتشغيل Seeders أخرى.
وفقًا للتوثيق الرسمي لـ Laravel 13، يمكن إنشاء Seeder باستخدام make:seeder، ويحتوي Seeder عادةً على method باسم run() يتم تنفيذها عند تشغيل أمر db:seed.
إنشاء أول Factory
لنفرض أن لدينا Model باسم:
Article
يمكننا إنشاء Factory باستخدام Artisan:
php artisan make:factory ArticleFactory
سيتم إنشاء الملف داخل:
database/factories
ليصبح لدينا:
database/
└── factories/
└── ArticleFactory.php
إنشاء Factory مع Model
إذا كنت تنشئ Model جديدًا من البداية، يمكنك استخدام:
php artisan make:model Article --factory
أو يمكنك استخدام الخيار المختصر:
php artisan make:model Article -f
وبذلك يساعدك Artisan في إنشاء Model وFactory.
فهم ArticleFactory
بعد إنشاء Factory، ستجد كلاس مشابهًا لهذا:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
public function definition(): array
{
return [
//
];
}
}
أهم جزء هنا هو:
definition()
هذه الدالة تحدد البيانات الافتراضية التي سيتم استخدامها عند إنشاء Article باستخدام Factory.
>كتابة البيانات داخل Factory
لنفترض أن جدول articles يحتوي على:
- title
- slug
- content
- is_published
يمكن كتابة Factory مثل التالي:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
public function definition(): array
{
return [
'title' => fake()->sentence(),
'slug' => fake()->unique()->slug(),
'content' => fake()->paragraphs(3, true),
'is_published' => fake()->boolean(),
];
}
}
الآن أصبح لدينا قالب لإنشاء المقالات.
ماذا يفعل fake()؟
لننظر إلى كل سطر.
إنشاء عنوان
'title' => fake()->sentence(),
ينشئ عنوانًا عشوائيًا.
إنشاء Slug
'slug' => fake()->unique()->slug(),
ينشئ slug عشوائيًا، مع استخدام unique() لتجنب تكرار القيمة أثناء عملية التوليد.
إنشاء المحتوى
'content' => fake()->paragraphs(3, true),
ينشئ عدة فقرات نصية.
إنشاء قيمة Boolean
'is_published' => fake()->boolean(),
يمكن أن تنتج:
true
أو:
false
استخدام Factory لإنشاء سجل واحد
بعد تجهيز Factory، يمكننا استخدامه من خلال Model.
مثلًا:
use App\Models\Article; $article = Article::factory()->create();
سيتم إنشاء Article جديد وإدخاله في قاعدة البيانات.
توثيق Laravel يوضح استخدام factory() على Models لإنشاء نماذج واختبارها أو استخدامها ضمن عمليات seeding.
إنشاء عدة سجلات
يمكننا إنشاء أكثر من سجل باستخدام:
Article::factory()->count(10)->create();
سيتم إنشاء 10 مقالات.
ويمكنك تغيير الرقم حسب حاجتك:
Article::factory()->count(50)->create();
أو:
Article::factory()->count(100)->create();
وهذه واحدة من أهم فوائد Factories.
الفرق بين create وmake
هناك فرق مهم بين:
Article::factory()->make();
و:
Article::factory()->create();
make()
ينشئ Model في الذاكرة فقط دون حفظه في قاعدة البيانات.
مثلًا:
$article = Article::factory()->make();
يمكنك استخدامه عندما تريد التعامل مع الكائن دون إدخاله إلى قاعدة البيانات.
create()
ينشئ Model ويحفظه في قاعدة البيانات.
$article = Article::factory()->create();
لذلك عند تجهيز بيانات حقيقية داخل قاعدة البيانات، ستستخدم create() غالبًا.
استخدام Factory مع العلاقات
وهنا تبدأ قوة Factories بالظهور بشكل أكبر.
لنفترض أن لدينا:
users articles
والعلاقة هي:
User hasMany Articles Article belongsTo User
أي أن المستخدم يمكن أن يمتلك عدة مقالات.
إذا أردنا إنشاء User ومعه عدة Articles، يمكننا استخدام العلاقة التي عرفناها في الدرس السابق.
مثلًا:
$user = User::factory()
->has(Article::factory()->count(5))
->create();
سيتم إنشاء مستخدم، ومعه 5 مقالات مرتبطة به.
هذه الطريقة مفيدة جدًا عندما يكون التطبيق يحتوي على بيانات مترابطة.
توثيق Laravel 13 يخصص قسمًا كاملًا لعلاقات Factories، ومنها علاقات hasMany وbelongsTo وmany-to-many.
إنشاء عدة Users مع المقالات
يمكننا أيضًا إنشاء 10 مستخدمين، ولكل مستخدم 5 مقالات:
User::factory()
->count(10)
->has(Article::factory()->count(5))
->create();
والنتيجة ستكون تقريبًا:
10 Users │ ├── User 1 │ ├── Article │ ├── Article │ ├── Article │ ├── Article │ └── Article │ ├── User 2 │ ├── Article │ ├── Article │ ├── Article │ ├── Article │ └── Article │ └── ...
أي 10 مستخدمين و50 مقالًا مرتبطًا بهم.
إنشاء Seeder
لننشئ Seeder خاصًا بالمقالات:
php artisan make:seeder ArticleSeeder
سيتم إنشاء:
database/seeders/ArticleSeeder.php
وسيكون هيكله الأساسي قريبًا من:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
public function run(): void
{
//
}
}
إضافة Factory إلى Seeder
يمكننا الآن استخدام Article Factory داخل Seeder:
<?php
namespace Database\Seeders;
use App\Models\Article;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
public function run(): void
{
Article::factory()
->count(50)
->create();
}
}
الآن عند تشغيل هذا Seeder سيتم إنشاء 50 مقالًا.
تشغيل Seeder
يمكن تشغيل الـ Seeder الرئيسي باستخدام:
php artisan db:seed
افتراضيًا يقوم Laravel بتشغيل:
DatabaseSeeder
والذي يمكنه بدوره تشغيل Seeders أخرى.
يمكن أيضًا تشغيل Seeder محدد باستخدام:
php artisan db:seed --class=ArticleSeeder
وهذه الأوامر موثقة رسميًا في Laravel 13.
ما هو DatabaseSeeder؟
داخل:
database/seeders
ستجد:
DatabaseSeeder.php
يمكن اعتباره نقطة التجميع الرئيسية للـ Seeders.
بدلًا من وضع كل البيانات داخل ملف واحد، من الأفضل تقسيمها.
مثلًا:
database/seeders/ ├── DatabaseSeeder.php ├── UserSeeder.php ├── ArticleSeeder.php ├── CategorySeeder.php └── CommentSeeder.php
ثم يمكنك استدعاؤها من DatabaseSeeder.
استخدام call()
يمكن كتابة:
public function run(): void
{
$this->call([
UserSeeder::class,
CategorySeeder::class,
ArticleSeeder::class,
CommentSeeder::class,
]);
}
وبذلك يتم تشغيل Seeders بالترتيب المحدد.
يسمح Laravel باستخدام call() لتقسيم عملية seeding إلى عدة Seeders بدل وضع كل شيء داخل DatabaseSeeder واحد.
لماذا ترتيب Seeders مهم؟
تخيل أن لدينا:
Users Categories Articles Comments
والمقال يحتاج إلى:
user_id category_id
والتعليق يحتاج إلى:
article_id user_id
إذًا من المنطقي أن ننشئ البيانات بهذا الترتيب:
Users ↓ Categories ↓ Articles ↓ Comments
لأن البيانات اللاحقة تعتمد على البيانات السابقة.
مثال عملي كامل
لنقم ببناء سيناريو صغير لموقع مقالات.
لدينا:
User Category Article Comment
والعلاقات:
User └── hasMany Articles Category └── hasMany Articles Article ├── belongsTo User ├── belongsTo Category └── hasMany Comments Comment ├── belongsTo User └── belongsTo Article
هذه العلاقات مبنية على نفس مفهوم Eloquent Relationships الذي تعلمناه في الدرس العاشر.
UserFactory
يمكن أن يكون لدينا:
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('password'),
];
}
وبذلك يمكن إنشاء المستخدمين تلقائيًا.
CategoryFactory
يمكن إنشاء Factory للتصنيفات:
php artisan make:factory CategoryFactory
ثم:
public function definition(): array
{
return [
'name' => fake()->unique()->words(2, true),
'slug' => fake()->unique()->slug(),
];
}
ArticleFactory مع العلاقات
إذا كان جدول articles يحتوي على:
user_id category_id title slug content is_published
يمكن أن نكتب:
public function definition(): array
{
return [
'user_id' => User::factory(),
'category_id' => Category::factory(),
'title' => fake()->sentence(),
'slug' => fake()->unique()->slug(),
'content' => fake()->paragraphs(4, true),
'is_published' => fake()->boolean(),
];
}
بهذه الطريقة يستطيع Factory إنشاء User وCategory عند الحاجة وربطهما بالمقال.
لكن في التطبيقات الكبيرة، قد تفضّل إنشاء المستخدمين والتصنيفات بشكل مستقل ثم إعادة استخدامهم، خصوصًا عندما تريد التحكم في عدد العلاقات بدل إنشاء سجلات جديدة لكل Article.
إعادة استخدام سجلات موجودة
لنفرض أننا أنشأنا 10 Users و5 Categories:
User::factory()->count(10)->create(); Category::factory()->count(5)->create();
بعد ذلك يمكننا استخدام سجلات موجودة عند إنشاء Articles.
على سبيل المثال، يمكنك اختيار مستخدم وتصنيف موجودين ثم استخدام معرفاتهما:
$user = User::inRandomOrder()->first();
$category = Category::inRandomOrder()->first();
Article::factory()->create([
'user_id' => $user->id,
'category_id' => $category->id,
]);
هذه الفكرة مفيدة عندما تريد التحكم بشكل أكبر في البيانات.
استخدام Factory States
أحيانًا نحتاج إلى أنواع مختلفة من السجلات.
مثلًا في المقالات قد نحتاج إلى:
- مقالات منشورة.
- مقالات غير منشورة.
بدل إنشاء Factory منفصل لكل نوع، يمكننا استخدام States.
مثلًا:
public function published(): static
{
return $this->state(fn (array $attributes) => [
'is_published' => true,
]);
}
ثم:
Article::factory()
->published()
->count(10)
->create();
وهكذا أصبح لدينا 10 مقالات منشورة.
يمكن أيضًا إنشاء حالة للمقالات غير المنشورة:
public function draft(): static
{
return $this->state(fn (array $attributes) => [
'is_published' => false,
]);
}
ثم:
Article::factory()
->draft()
->count(5)
->create();
توثيق Laravel 13 يدعم Factory States كطريقة لتغيير الحالة الافتراضية للبيانات عند إنشاء النماذج.
مثال على Seeder احترافي
يمكن أن يصبح ArticleSeeder مثلًا:
<?php
namespace Database\Seeders;
use App\Models\Article;
use App\Models\Category;
use App\Models\User;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
public function run(): void
{
User::factory()->count(10)->create();
Category::factory()->count(5)->create();
Article::factory()->count(50)->create();
}
}
هذا المثال مناسب للتعلم، لكن في مشروع حقيقي قد ترغب في التحكم بشكل أكبر في العلاقات وربط المقالات بمستخدمين وتصنيفات موجودة بالفعل.
migrate --seed
أثناء التطوير ستحتاج أحيانًا إلى إعادة بناء قاعدة البيانات من البداية.
يمكنك استخدام:
php artisan migrate:fresh --seed
هذا الأمر يقوم بإسقاط الجداول ثم تشغيل الـ migrations من جديد، وبعد ذلك تشغيل الـ seeders. لذلك يجب استخدامه بحذر، خصوصًا إذا كانت قاعدة البيانات تحتوي على بيانات مهمة. Laravel يوضح رسميًا أن migrate:fresh يحذف جميع الجداول ثم يعيد تشغيل الـ migrations، ويمكن دمجه مع --seed.
أثناء التطوير يمكن أن يكون هذا الأمر مفيدًا جدًا.
مثلًا:
php artisan migrate:fresh --seed
ثم تصبح لديك قاعدة بيانات جديدة تحتوي على بيانات تجريبية.
الفرق بين migrate وseed
من المهم جدًا فهم الفرق.
migrate
المigrations مسؤولة عن بنية قاعدة البيانات.
مثل:
إنشاء جدول users إنشاء جدول articles إضافة عمود slug إضافة Foreign Key
seed
الـ Seeders مسؤولة عن البيانات الموجودة داخل الجداول.
مثل:
إنشاء 10 Users إنشاء 50 Articles إنشاء Categories إنشاء Comments
بمعنى آخر:
Migration
↓
بناء الجداول
Seeder
↓
إضافة البيانات
الفرق بين Factory وSeeder وFaker
من أكثر الأشياء التي تسبب ارتباكًا للمبتدئين الخلط بين هذه المفاهيم.
يمكن تلخيصها كالتالي:
| الأداة | وظيفتها |
|---|---|
| Migration | إنشاء وتعديل بنية قاعدة البيانات |
| Model | التعامل مع بيانات الجدول |
| Factory | تحديد شكل البيانات التجريبية |
| Faker | توليد قيم وهمية |
| Seeder | تشغيل وإدخال البيانات إلى قاعدة البيانات |
مثلًا:
Faker ↓ ينشئ قيمًا عشوائية Factory ↓ يحدد شكل Article Seeder ↓ يطلب إنشاء 50 Article Database ↓ تخزن البيانات
إنشاء بيانات مرتبطة
لنستخدم العلاقات التي تعلمناها في الدرس السابق.
لنفترض:
User::factory()
->has(Article::factory()->count(5))
->create();
هنا لدينا:
User │ ├── Article ├── Article ├── Article ├── Article └── Article
يمكنك توسيع الفكرة لإنشاء بيانات كبيرة مترابطة.
مثلًا:
User::factory()
->count(20)
->has(Article::factory()->count(5))
->create();
يمكن أن ينتج عن ذلك 20 مستخدمًا مع 5 مقالات لكل مستخدم.
Factories وMany-to-Many
يمكن استخدام Factories أيضًا مع العلاقات Many-to-Many.
مثلًا إذا كان لدينا:
users roles role_user
يمكن إنشاء المستخدم والأدوار وربطها باستخدام إمكانيات Factories الخاصة بالعلاقات.
الفكرة الأساسية هي أن Factory لا يقتصر على إنشاء سجل منفرد، بل يمكنه المساعدة في إنشاء مجموعات من البيانات المرتبطة.
وهذا مهم جدًا في التطبيقات الكبيرة، لأن البيانات الواقعية غالبًا لا تكون عبارة عن جداول منفصلة، وإنما مجموعة من العلاقات.
استخدام بيانات Faker بحذر
Faker ممتاز للبيانات التجريبية، لكن يجب أن تتذكر أن هذه البيانات ليست بيانات حقيقية.
مثلًا:
fake()->email()
ينشئ بريدًا وهميًا.
لا يجب أن تعتمد على هذه البيانات باعتبارها بيانات مستخدمين حقيقيين.
كما يجب ألا تستخدم Seeder يحتوي على بيانات تجريبية بشكل عشوائي على قاعدة بيانات Production.
مشكلة شائعة: تشغيل Seeder على Production
تخيل أنك كتبت:
php artisan migrate:fresh --seed
ثم نفذته على قاعدة بيانات Production.
هذا قد يؤدي إلى حذف الجداول والبيانات الموجودة ثم إعادة بنائها.
لذلك يجب الانتباه جدًا إلى البيئة التي تعمل عليها.
Laravel يطلب تأكيدًا عند تنفيذ بعض عمليات seeding في بيئة production، ويمكن استخدام --force لتجاوز التأكيد، ولذلك يجب عدم استخدامه إلا عندما تكون متأكدًا من النتيجة.
مشكلة شائعة: العلاقات لا تعمل
إذا حاولت إنشاء:
Article::factory()->create();
وكان Factory يحتاج إلى:
user_id
لكن لم يتم توفيره، فقد تواجه مشكلة حسب بنية الجدول والعلاقة.
لذلك تأكد من أن Factory يعرف كيفية إنشاء أو الحصول على السجلات المرتبطة.
مثلًا:
'user_id' => User::factory(),
يمكن أن يوفر مستخدمًا مرتبطًا عند إنشاء Article.
مشكلة شائعة: أسماء الأعمدة
يجب أن تتطابق البيانات التي تضعها داخل Factory مع أسماء الأعمدة في Migration.
إذا كان لديك:
$table->string('title');
يجب أن تستخدم:
'title' => fake()->sentence(),
وليس:
'name' => fake()->sentence(),
إلا إذا كان لديك فعلًا عمود باسم name.
مشكلة شائعة: Unique
إذا كان لديك عمود فريد:
$table->string('slug')->unique();
فلا تريد إنشاء نفس القيمة عشرات المرات.
لذلك يمكنك استخدام:
'slug' => fake()->unique()->slug(),
وبذلك تقل احتمالية إنتاج قيم مكررة أثناء إنشاء البيانات.
مثال عملي نهائي
لنضع كل شيء معًا.
ArticleFactory
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
public function definition(): array
{
return [
'title' => fake()->sentence(),
'slug' => fake()->unique()->slug(),
'content' => fake()->paragraphs(4, true),
'is_published' => fake()->boolean(),
];
}
public function published(): static
{
return $this->state(fn (array $attributes) => [
'is_published' => true,
]);
}
}
ArticleSeeder
<?php
namespace Database\Seeders;
use App\Models\Article;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
public function run(): void
{
Article::factory()
->published()
->count(20)
->create();
Article::factory()
->count(10)
->create();
}
}
النتيجة:
20 Published Articles + 10 Draft/Random Articles = 30 Articles
DatabaseSeeder
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
ArticleSeeder::class,
]);
}
}
ثم نفذ:
php artisan migrate:fresh --seed
إذا كانت الـ migrations والـ Models والـ Factories مكتملة بشكل صحيح، فسيتم بناء قاعدة البيانات من جديد ثم تشغيل Seeder.
كيف تستخدم البيانات في التطبيق؟
بعد إنشاء البيانات، يمكنك استخدامها مع Eloquent كما تعلمنا في الدرس التاسع.
مثلًا:
$articles = Article::latest()->get();
ثم إرسالها إلى View:
return view('articles.index', compact('articles'));
وفي Blade:
@foreach ($articles as $article)
<article>
<h2>{{ $article->title }}</h2>
<p>{{ $article->content }}</p>
</article>
@endforeach
وهكذا أصبح لدينا دورة كاملة:
Migration ↓ Database Tables ↓ Model ↓ Factory ↓ Faker ↓ Seeder ↓ Database Records ↓ Controller ↓ View
وهذه الدورة مهمة جدًا لفهم كيفية بناء تطبيق Laravel متكامل.
Factories والاختبارات
Factories لا تستخدم فقط أثناء التطوير.
يمكن استخدامها أيضًا داخل الاختبارات لإنشاء البيانات المطلوبة قبل اختبار جزء من التطبيق.
مثلًا:
$user = User::factory()->create();
ثم يمكنك تنفيذ طلب:
$response = $this->actingAs($user)
->get('/articles');
وجود Factory يجعل تجهيز بيانات الاختبار أسهل بكثير.
Laravel يوفر أدوات لاستخدام Factories وSeeders ضمن اختبارات قاعدة البيانات أيضًا.
أفضل الممارسات
اجعل Factory بسيطًا
ضع البيانات الافتراضية الأساسية داخل:
definition()
ولا تجعل Factory معقدًا دون حاجة.
استخدم States للحالات المختلفة
بدل إنشاء Factory لكل حالة، استخدم:
published()
أو:
draft()
أو حالات أخرى تناسب التطبيق.
قسم Seeders
إذا كان المشروع كبيرًا، لا تضع كل شيء داخل:
DatabaseSeeder.php
استخدم:
UserSeeder CategorySeeder ArticleSeeder CommentSeeder
ثم استدعها من DatabaseSeeder.
انتبه للعلاقات
عند إنشاء بيانات مترابطة، تأكد من أن السجلات المطلوبة موجودة وأن Foreign Keys صحيحة.
لا تستخدم بيانات الاختبار بشكل عشوائي في Production
بيانات Faker مخصصة أساسًا للبيانات التجريبية والتطوير والاختبار.
تمرين عملي
حان وقت التطبيق.
قم بإنشاء نظام صغير للمقالات يحتوي على:
User Category Article
ثم نفذ الخطوات التالية.
الخطوة الأولى
أنشئ Factory للتصنيف:
php artisan make:factory CategoryFactory
الخطوة الثانية
اجعل Factory ينشئ:
name slug
الخطوة الثالثة
أنشئ Seeder:
php artisan make:seeder CategorySeeder
الخطوة الرابعة
أنشئ 10 تصنيفات:
Category::factory()
->count(10)
->create();
الخطوة الخامسة
أنشئ 20 مستخدمًا:
User::factory()
->count(20)
->create();
الخطوة السادسة
أنشئ 100 مقال.
اجعل كل مقال مرتبطًا بمستخدم وتصنيف.
الخطوة السابعة
شغّل:
php artisan migrate:fresh --seed
الخطوة الثامنة
أنشئ Route يعرض المقالات:
Route::get('/articles', function () {
$articles = Article::latest()->get();
return view('articles.index', compact('articles'));
});
ثم أنشئ View لعرض المقالات.
بهذا التمرين ستكون قد ربطت تقريبًا جميع المفاهيم التي تعلمتها حتى الآن.
ماذا تعلمنا في هذا الدرس؟
في هذا الدرس تعرفنا على طريقة إنشاء البيانات التجريبية في Laravel باستخدام مجموعة من الأدوات المتكاملة.
تعلمنا أن:
Factory تحدد شكل البيانات التي سيتم إنشاؤها.
Faker يوفر بيانات وهمية مثل الأسماء والبريد الإلكتروني والنصوص.
Seeder مسؤول عن تشغيل عملية إدخال البيانات إلى قاعدة البيانات.
وتعلمنا إنشاء Factory باستخدام:
php artisan make:factory ArticleFactory
وإنشاء Seeder باستخدام:
php artisan make:seeder ArticleSeeder
وتعلمنا إنشاء سجل:
Article::factory()->create();
وإنشاء عدة سجلات:
Article::factory()->count(50)->create();
وتعلمنا استخدام العلاقات:
User::factory()
->has(Article::factory()->count(5))
->create();
كما تعرفنا على Factory States مثل:
Article::factory()
->published()
->count(10)
->create();
وتعلمنا تشغيل Seeders:
php artisan db:seed
أو Seeder محدد:
php artisan db:seed --class=ArticleSeeder
وتعلمنا إعادة بناء قاعدة البيانات مع تشغيل البيانات التجريبية:
php artisan migrate:fresh --seed
أصبحت الآن قادرًا على تجهيز قاعدة بيانات Laravel بكمية كبيرة من البيانات دون الحاجة إلى إدخال كل سجل يدويًا.
وهذا مهم جدًا في المشاريع الحقيقية، لأن المطور يحتاج باستمرار إلى بيانات تساعده على اختبار التطبيق وتصميم الواجهات وتجربة البحث وPagination والعلاقات ولوحات الإدارة.
يمكن تصور الأدوات التي تعلمناها حتى الآن بهذه الصورة:
Migrations
↓
إنشاء الجداول
↓
Models + Eloquent
↓
التعامل مع البيانات
↓
Relationships
↓
ربط الجداول
↓
Factories + Faker
↓
توليد بيانات تجريبية
↓
Seeders
↓
تعبئة قاعدة البيانات
في الدرس القادم سنبدأ بالانتقال إلى جزء مهم جدًا في بناء تطبيقات Laravel العملية، وهو Authentication والمستخدمون وتسجيل الدخول والتسجيل وإدارة الجلسات، حتى نبدأ في بناء تطبيقات تحتوي على مستخدمين حقيقيين وصلاحيات وسلوكيات مرتبطة بالحسابات.
