recent
أخبار ساخنة

إنشاء بيانات تجريبية بسهولة Factories في Laravel

التعامل مع قواعد البيانات في Laravel 11

إنشاء بيانات تجريبية بسهولة 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 والمستخدمون وتسجيل الدخول والتسجيل وإدارة الجلسات، حتى نبدأ في بناء تطبيقات تحتوي على مستخدمين حقيقيين وصلاحيات وسلوكيات مرتبطة بالحسابات.

google-playkhamsatmostaqltradentX