سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

CMS نویس مرجعی برای آموزش برنامه نویسی وب و PHP، توسعه افزونه‌های اختصاصی وردپرس، طراحی ورک‌فلو و اتوماسیون با n8n و توسعه CMS های اختصاصی است. هدف ما ارائه آموزش‌های کاربردی و راهکارهای حرفه‌ای برای توسعه‌دهندگان، کسب‌وکارها و علاقه‌مندان به دنیای برنامه‌نویسی است.

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Active Record Pattern در PHP چیست؟ آموزش الگوی Active Record با مثال عملی

Active Record Pattern در PHP چیست؟ آموزش الگوی Active Record با مثال عملی

ممدیر کل سیستم ۲۵ شهریور ۱۴۰۵ ۱۹ دقیقه مطالعه ۲ بازدید
Active Record Pattern در PHP چیست؟ آموزش الگوی Active Record با مثال عملی

در بسیاری از پروژه‌های PHP، اطلاعات برنامه در دیتابیس ذخیره می‌شوند و برنامه باید بتواند رکوردهای دیتابیس را بخواند، ایجاد کند، تغییر دهد و حذف کند.

یک سؤال مهم این است:

چطور می‌توانیم یک رکورد دیتابیس را به یک شیء PHP تبدیل کنیم و عملیات مربوط به همان رکورد را نیز از طریق همان شیء انجام دهیم؟

یکی از پاسخ‌های معروف به این مسئله، Active Record Pattern است.

در این الگو، یک شیء معمولاً نماینده یک رکورد در دیتابیس است و خود شیء می‌تواند عملیات مربوط به ذخیره، به‌روزرسانی یا حذف داده را انجام دهد. پیاده‌سازی‌های مختلف Active Record نیز دقیقاً بر همین ایده بنا شده‌اند؛ یعنی یک کلاس به یک جدول یا رکورد دیتابیس مرتبط می‌شود و عملیات Persistence از طریق مدل انجام می‌گیرد. 

اگر با Laravel کار کرده باشید، احتمالاً این مفهوم برایتان آشناست؛ زیرا Eloquent بسیاری از رفتارهای رایج Active Record را در اختیار مدل‌ها قرار می‌دهد.

در این مقاله ابتدا Active Record را از پایه یاد می‌گیریم، سپس آن را با PHP خام پیاده‌سازی می‌کنیم و در نهایت ارتباط آن با Laravel و Eloquent را بررسی خواهیم کرد.


# Active Record Pattern چیست؟

Active Record یک الگوی طراحی برای کار با داده‌های ذخیره‌شده است که در آن شیء برنامه معمولاً نماینده یک رکورد دیتابیس است.

برای مثال فرض کنید جدول زیر را داریم:


CREATE TABLE products (

    id INT PRIMARY KEY AUTO_INCREMENT,

    name VARCHAR(255) NOT NULL,

    price BIGINT NOT NULL

);

در Active Record می‌توانیم کلاسی مانند Product داشته باشیم:


products table

      ↕

Product object

هر نمونه از Product می‌تواند نماینده یک رکورد از جدول products باشد.

مثلاً:


$product = Product::find(10);

در اینجا محصولی با شناسه ۱۰ از دیتابیس دریافت می‌شود.

سپس می‌توانیم آن را تغییر دهیم:


$product->price = 2500000;

و در نهایت:


$product->save();

در این مدل، خود Object به عملیات Persistence دسترسی دارد.

این ویژگی یکی از مشخصه‌های اصلی Active Record است. 


# ایده اصلی Active Record

اگر بخواهیم مفهوم Active Record را خیلی ساده بیان کنیم:

> هر Object نماینده یک رکورد است و خودش می‌تواند عملیات ذخیره‌سازی آن رکورد را انجام دهد.

برای مثال:


Database Row

     ↕

Product Object

و عملیات:


find()

save()

update()

delete()

از طریق همان Model انجام می‌شوند.


# یک مثال ساده

فرض کنیم در دیتابیس چنین رکوردی داریم:


id = 10

name = Laptop

price = 45000000

در Active Record:


$product = Product::find(10);

حالا:


echo $product->name;

خروجی:


Laptop

اگر قیمت را تغییر دهیم:


$product->price = 42000000;

و ذخیره کنیم:


$product->save();

عملاً رکورد مربوط به همان Object در دیتابیس به‌روزرسانی می‌شود.


# ساخت Active Record ساده با PHP

برای اینکه مفهوم را بدون Laravel یاد بگیریم، یک پیاده‌سازی بسیار ساده با PDO ایجاد می‌کنیم.

ابتدا جدول محصولات را ایجاد می‌کنیم:


CREATE TABLE products (

    id INT PRIMARY KEY AUTO_INCREMENT,

    name VARCHAR(255) NOT NULL,

    price BIGINT NOT NULL

);

اکنون کلاس Product را ایجاد می‌کنیم.


<?php



declare(strict_types=1);



final class Product

{

    public ?int $id = null;



    public string $name;



    public int $price;



    private PDO $pdo;



    public function __construct(PDO $pdo)

    {

        $this->pdo = $pdo;

    }

}

در اینجا هر Product یک اتصال PDO دارد.

این موضوع برای مثال آموزشی قابل قبول است، اما در پروژه‌های واقعی بهتر است وابستگی‌ها با دقت بیشتری مدیریت شوند.


# ایجاد رکورد با Active Record

اکنون می‌توانیم متد save() را اضافه کنیم.


public function save(): void

{

    if ($this->id === null) {

        $stmt = $this->pdo->prepare(

            'INSERT INTO products (name, price)

             VALUES (:name, :price)'

        );



        $stmt->execute([

            'name' => $this->name,

            'price' => $this->price,

        ]);



        $this->id = (int) $this->pdo->lastInsertId();



        return;

    }



    $stmt = $this->pdo->prepare(

        'UPDATE products

         SET name = :name,

             price = :price

         WHERE id = :id'

    );



    $stmt->execute([

        'id' => $this->id,

        'name' => $this->name,

        'price' => $this->price,

    ]);

}

حالا می‌توانیم محصول جدید ایجاد کنیم:


$product = new Product($pdo);



$product->name = 'Mechanical Keyboard';

$product->price = 3500000;



$product->save();

در اینجا:


Product Object

      ↓

save()

      ↓

INSERT

      ↓

Database


# دریافت یک رکورد

حالا یک متد find() ایجاد می‌کنیم.


public static function find(

    PDO $pdo,

    int $id

): ?self {

    $stmt = $pdo->prepare(

        'SELECT id, name, price

         FROM products

         WHERE id = :id'

    );



    $stmt->execute([

        'id' => $id,

    ]);



    $row = $stmt->fetch(PDO::FETCH_ASSOC);



    if ($row === false) {

        return null;

    }



    $product = new self($pdo);



    $product->id = (int) $row['id'];

    $product->name = (string) $row['name'];

    $product->price = (int) $row['price'];



    return $product;

}

اکنون:


$product = Product::find($pdo, 10);

اگر رکورد وجود داشته باشد، یک Object از Product دریافت می‌کنیم.


# به‌روزرسانی رکورد

فرض کنیم محصول را پیدا کرده‌ایم:


$product = Product::find($pdo, 10);

قیمت را تغییر می‌دهیم:


$product->price = 4000000;

و ذخیره می‌کنیم:


$product->save();

کلاس خودش تشخیص می‌دهد که Object دارای id است و بنابراین به جای INSERT، UPDATE انجام می‌دهد.


# حذف رکورد

می‌توانیم متد delete() نیز اضافه کنیم:


public function delete(): void

{

    if ($this->id === null) {

        return;

    }



    $stmt = $this->pdo->prepare(

        'DELETE FROM products

         WHERE id = :id'

    );



    $stmt->execute([

        'id' => $this->id,

    ]);



    $this->id = null;

}

اکنون:


$product = Product::find($pdo, 10);



$product?->delete();

رکورد از دیتابیس حذف می‌شود.


# ساختار کامل یک Active Record ساده

کلاس ما در نهایت می‌تواند به شکل زیر باشد:


<?php



declare(strict_types=1);



final class Product

{

    public ?int $id = null;



    public string $name = '';



    public int $price = 0;



    public function __construct(

        private PDO $pdo

    ) {

    }



    public static function find(

        PDO $pdo,

        int $id

    ): ?self {

        $stmt = $pdo->prepare(

            'SELECT id, name, price

             FROM products

             WHERE id = :id'

        );



        $stmt->execute([

            'id' => $id,

        ]);



        $row = $stmt->fetch(PDO::FETCH_ASSOC);



        if ($row === false) {

            return null;

        }



        $product = new self($pdo);



        $product->id = (int) $row['id'];

        $product->name = (string) $row['name'];

        $product->price = (int) $row['price'];



        return $product;

    }



    public function save(): void

    {

        if ($this->id === null) {

            $stmt = $this->pdo->prepare(

                'INSERT INTO products (name, price)

                 VALUES (:name, :price)'

            );



            $stmt->execute([

                'name' => $this->name,

                'price' => $this->price,

            ]);



            $this->id = (int) $this->pdo->lastInsertId();



            return;

        }



        $stmt = $this->pdo->prepare(

            'UPDATE products

             SET name = :name,

                 price = :price

             WHERE id = :id'

        );



        $stmt->execute([

            'id' => $this->id,

            'name' => $this->name,

            'price' => $this->price,

        ]);

    }



    public function delete(): void

    {

        if ($this->id === null) {

            return;

        }



        $stmt = $this->pdo->prepare(

            'DELETE FROM products

             WHERE id = :id'

        );



        $stmt->execute([

            'id' => $this->id,

        ]);



        $this->id = null;

    }

}

این نمونه یک Active Record ساده است.

البته یک ORM حرفه‌ای امکانات بسیار بیشتری مانند Relations، Validation، Events، Query Builder و Transaction در اختیار برنامه‌نویس قرار می‌دهد.


# Active Record چه مشکلی را حل می‌کند؟

بدون Active Record ممکن است برای هر جدول چندین کلاس داشته باشیم:


Product

ProductRepository

ProductMapper

ProductData

ProductGateway

اما Active Record سعی می‌کند بخش زیادی از این عملیات را در همان Model متمرکز کند.

مثلاً:


$product = Product::find(10);



$product->name = 'New Product';



$product->save();

این مدل برای CRUD بسیار ساده و قابل فهم است.


# Active Record و ORM چه ارتباطی دارند؟

Active Record و ORM دقیقاً یک مفهوم نیستند.

ORM یا Object-Relational Mapping یک روش برای نگاشت Objectهای برنامه به داده‌های رابطه‌ای دیتابیس است.

Active Record یکی از الگوهایی است که می‌تواند برای پیاده‌سازی چنین نگاشتی استفاده شود.

به همین دلیل می‌توان گفت:


ORM

│

├── Active Record

│

└── Data Mapper

این دو رویکرد تفاوت‌های معماری مهمی دارند.


# Active Record در Laravel و Eloquent

اگر با Laravel کار کرده باشید، احتمالاً بیشتر از هر جای دیگری Active Record را در Eloquent دیده‌اید.

برای مثال:


$product = Product::find(10);

سپس:


$product->name = 'Gaming Laptop';



$product->save();

یا:


$product->delete();

این سبک استفاده، شباهت بسیار زیادی به Active Record دارد.

Eloquent به مدل‌های Laravel اجازه می‌دهد مستقیماً با رکوردهای دیتابیس کار کنند و متدهایی مانند save()، delete() و Queryهای مختلف را در اختیار Model قرار می‌دهد.

در پیاده‌سازی‌های Active Record نیز همین ایده رایج است: مدل با یک جدول یا رکورد مرتبط است و خودش عملیات Persistence را انجام می‌دهد. 


# مثال Active Record در Laravel

فرض کنیم مدل Product داریم:


php artisan make:model Product -m

Migration:


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

    $table->id();

    $table->string('name');

    $table->unsignedBigInteger('price');

    $table->timestamps();

});

مدل:


<?php



namespace App\Models;



use Illuminate\Database\Eloquent\Model;



class Product extends Model

{

    protected $fillable = [

        'name',

        'price',

    ];

}

حالا ایجاد محصول:


$product = new Product();



$product->name = 'Laptop';

$product->price = 45000000;



$product->save();

یا:


$product = Product::create([

    'name' => 'Laptop',

    'price' => 45000000,

]);

دریافت:


$product = Product::find(10);

به‌روزرسانی:


$product->price = 40000000;



$product->save();

حذف:


$product->delete();

این API ساده یکی از دلایلی است که Eloquent برای توسعه سریع برنامه‌های Laravel بسیار مناسب است.


# Active Record و Model چه تفاوتی دارند؟

گاهی این دو اصطلاح با هم اشتباه گرفته می‌شوند.

در یک معماری ساده MVC ممکن است بگوییم:


Model

View

Controller

اما Active Record درباره نحوه طراحی و مسئولیت Model در ارتباط با Persistence صحبت می‌کند.

یعنی یک Model می‌تواند صرفاً یک Data Object باشد، یا می‌تواند رفتار Active Record داشته باشد.

در Active Record، Model علاوه بر نگهداری داده، مسئولیت‌هایی برای خواندن و ذخیره‌سازی آن داده نیز دارد.


# مزایای Active Record Pattern

۱. سادگی

برای CRUD ساده، Active Record بسیار قابل فهم است:


$product->save();

۲. توسعه سریع

در پروژه‌های CRUD محور، می‌توان با کد نسبتاً کمی امکانات مختلف را پیاده‌سازی کرد.

۳. نزدیک بودن Model به داده

مدل هم اطلاعات رکورد را دارد و هم عملیات مربوط به Persistence را در اختیار دارد.

۴. مناسب برای پروژه‌های ساده و متوسط

اگر ساختار Domain بسیار پیچیده نباشد، Active Record می‌تواند انتخاب مناسبی باشد.

۵. کاهش کدهای تکراری

به جای نوشتن Repository و Mapper برای هر عملیات ساده، بسیاری از عملیات در Model قرار می‌گیرند.


# معایب Active Record Pattern

Active Record نیز محدودیت‌هایی دارد.

۱. وابستگی Model به Persistence

Model معمولاً به دیتابیس یا ORM وابسته می‌شود.

در نتیجه جدا کردن Domain از Infrastructure دشوارتر می‌شود.

۲. سخت‌تر شدن Domain Model پیچیده

اگر Business Logic بسیار پیچیده باشد، ممکن است Model به یک کلاس بسیار بزرگ تبدیل شود.

۳. تست‌نویسی پیچیده‌تر

اگر منطق کسب‌وکار مستقیماً با ORM و دیتابیس ترکیب شود، تست واحد آن می‌تواند دشوارتر شود.

۴. ترکیب چند مسئولیت

یک Model ممکن است هم:

  • داده را نگهداری کند،
  • Validation داشته باشد،
  • Relation تعریف کند،
  • Query اجرا کند،
  • Event ایجاد کند،
  • عملیات ذخیره‌سازی انجام دهد.

در پروژه‌های بزرگ این موضوع می‌تواند نیاز به معماری دقیق‌تری ایجاد کند.


# Active Record در برابر Data Mapper

یکی از مهم‌ترین مقایسه‌ها در طراحی نرم‌افزار، تفاوت Active Record و Data Mapper است.

Active Record

در Active Record:


Entity

  +

Persistence

به هم نزدیک هستند.

برای مثال:


$product->save();

خود Product عملیات Persistence را انجام می‌دهد.

Data Mapper

در Data Mapper، Entity تلاش می‌کند از Persistence مستقل باشد:


Product Entity

      ↓

Data Mapper

      ↓

Database

برای مثال:


$mapper->save($product);

در اینجا Product لزوماً نمی‌داند اطلاعات چگونه ذخیره می‌شوند.


# مقایسه ساده Active Record و Data Mapper

ویژگیActive RecordData Mapper
ارتباط Model با دیتابیسنزدیکجدا
سادگی CRUDبالامتوسط
جداسازی Domainکمتربیشتر
مناسب CRUDبسیار مناسبمناسب
مناسب Domain پیچیدهمحدودترمناسب‌تر
تعداد کلاس‌هاکمتربیشتر
یادگیریساده‌ترپیچیده‌تر

هیچ‌کدام به صورت مطلق برای تمام پروژه‌ها مناسب نیستند.

انتخاب باید بر اساس پیچیدگی دامنه، نیازهای معماری و نوع پروژه انجام شود.


# Active Record در برابر Repository

Repository و Active Record نیز دو رویکرد متفاوت هستند.

در Active Record:


$product = Product::find(10);



$product->save();

اما در معماری Repository:


$product = $productRepository->findById(10);



$productRepository->save($product);

در حالت دوم Repository مسئول Persistence است.

Repository به عنوان یک abstraction برای دسترسی به مجموعه Entityها استفاده می‌شود و هدف آن جدا کردن لایه Domain از جزئیات Persistence است. 


# آیا Repository و Active Record را می‌توان با هم استفاده کرد؟

بله، اما باید دلیل مشخصی برای این ترکیب داشته باشیم.

برای مثال:


Application Service

       ↓

Repository

       ↓

Eloquent Model

       ↓

Database

در این معماری Repository می‌تواند جزئیات Eloquent را از Application پنهان کند.

اما اگر Repository فقط تمام متدهای Eloquent را یک‌به‌یک Wrap کند، ممکن است لایه اضافی بدون ارزش معماری ایجاد شود.

بنابراین باید Repository را برای یک نیاز واقعی طراحی کرد.


# Active Record و Unit of Work

Unit of Work و Active Record نیز می‌توانند در یک پروژه وجود داشته باشند، اما مسئولیت متفاوتی دارند.

Active Record بیشتر روی خود Model و Persistence آن تمرکز دارد:


$product->save();

Unit of Work روی مجموعه‌ای از تغییرات تمرکز می‌کند:


Product

Order

Payment

Wallet

     ↓

Unit of Work

     ↓

Commit

بنابراین:


Active Record

     ↓

مدیریت یک Entity / Record



Unit of Work

     ↓

هماهنگ کردن مجموعه تغییرات

در پروژه‌های ساده ممکن است Active Record به تنهایی کافی باشد.


# چه زمانی Active Record انتخاب مناسبی است؟

Active Record می‌تواند انتخاب مناسبی باشد اگر:

  • پروژه CRUD محور است.
  • مدل‌های دیتابیس نسبتاً ساده هستند.
  • سرعت توسعه اهمیت زیادی دارد.
  • Business Logic پیچیدگی بسیار زیادی ندارد.
  • تیم با ORM مورد استفاده به خوبی آشناست.
  • وابستگی Model به Persistence برای پروژه مسئله مهمی نیست.

برای مثال:

  • پنل مدیریت
  • فروشگاه ساده
  • وبلاگ
  • CMS
  • سیستم مدیریت محتوا
  • داشبورد مدیریتی
  • APIهای CRUD محور

# چه زمانی Active Record مناسب نیست؟

اگر پروژه دارای Domain بسیار پیچیده باشد، ممکن است جداسازی Domain و Persistence ارزش بیشتری پیدا کند.

برای مثال:


سیستم حسابداری پیچیده

سیستم مالی

سیستم سفارش‌گذاری پیچیده

سیستم پردازش تراکنش

سیستم‌های Enterprise

در چنین پروژه‌هایی ممکن است معماری‌هایی مبتنی بر:


Domain Model

Repository

Data Mapper

Unit of Work

Application Service

مناسب‌تر باشند.

البته این به معنی نامناسب بودن مطلق Active Record نیست؛ انتخاب معماری به نیاز واقعی پروژه بستگی دارد.


# اشتباهات رایج در استفاده از Active Record

اشتباه اول: قرار دادن تمام Business Logic در Model

اینکه Model مسئول Persistence است به این معنی نیست که باید تمام منطق سیستم را نیز در خود داشته باشد.

کدی مانند:


$product->save();

طبیعی است.

اما قرار دادن تمام فرآیند سفارش، پرداخت، تخفیف، حسابداری و ارسال در Product می‌تواند باعث ایجاد یک Model بیش از حد بزرگ شود.


اشتباه دوم: استفاده از Model به عنوان همه‌کاره

گاهی Model به چنین چیزی تبدیل می‌شود:


Product

├── Database

├── Validation

├── Payment

├── Discount

├── Notification

├── Reporting

└── Business Rules

این ساختار نگهداری کد را سخت می‌کند.


اشتباه سوم: ایجاد Repository بدون دلیل

گاهی برنامه‌نویس از Eloquent استفاده می‌کند و برای هر Model یک Repository می‌سازد، اما Repository فقط چنین کاری انجام می‌دهد:


public function find(int $id)

{

    return Product::find($id);

}

اگر این abstraction ارزش مشخصی ایجاد نکند، ممکن است صرفاً پیچیدگی پروژه را افزایش دهد.


# Active Record و اصول SOLID

Active Record لزوماً با SOLID ناسازگار نیست، اما طراحی مدل باید با دقت انجام شود.

مشکل زمانی ایجاد می‌شود که یک کلاس بیش از حد مسئولیت پیدا کند.

مثلاً:


Product

├── Data

├── Database

├── Payment

├── Notification

├── Reporting

└── Business Logic

در این حالت بهتر است مسئولیت‌های مختلف به Serviceها یا Domain Objectهای مناسب منتقل شوند.

هدف این نیست که Active Record را حذف کنیم؛ هدف این است که Model را بیش از حد بزرگ نکنیم.


# تست Active Record

یکی از نکات مهم در تست Active Record این است که باید مشخص کنیم چه چیزی را می‌خواهیم تست کنیم.

مثلاً اگر می‌خواهیم رفتار دیتابیس و Model را بررسی کنیم، یک تست Integration مناسب‌تر است:


public function test_product_can_be_saved(): void

{

    $product = Product::create([

        'name' => 'Keyboard',

        'price' => 2500000,

    ]);



    $this->assertDatabaseHas('products', [

        'id' => $product->id,

        'name' => 'Keyboard',

    ]);

}

در Laravel این نوع تست می‌تواند رفتار واقعی Model و دیتابیس را بررسی کند.

اما اگر بخواهیم Business Logic پیچیده را کاملاً مستقل از Persistence تست کنیم، ممکن است معماری مبتنی بر Domain Object، Repository و Dependency Injection مناسب‌تر باشد.


# Active Record و Eloquent؛ چرا این ترکیب مهم است؟

برای یک توسعه‌دهنده Laravel، شناخت Active Record فقط یک موضوع تئوری نیست.

وقتی می‌نویسیم:


$user = User::find(1);

و سپس:


$user->email = 'new@example.com';



$user->save();

در واقع داریم با مدلی کار می‌کنیم که هم داده را نمایندگی می‌کند و هم رفتار Persistence دارد.

این مدل برنامه‌نویسی باعث می‌شود توسعه CRUD بسیار سریع باشد.

به همین دلیل در پروژه‌هایی مانند:


CMS

Blog

Admin Panel

Marketplace

Simple E-commerce

CRUD API

این رویکرد می‌تواند بسیار کاربردی باشد.


# یک مثال واقعی‌تر در Laravel

فرض کنید در یک فروشگاه، Product داریم:


$product = Product::findOrFail($id);

حالا موجودی را کاهش می‌دهیم:


$product->stock -= $quantity;



$product->save();

برای افزایش قیمت:


$product->price = $newPrice;



$product->save();

برای حذف:


$product->delete();

این سادگی یکی از نقاط قوت مدل Active Record است.

اما اگر فرآیند تغییر موجودی شامل چندین مرحله باشد:


Product Stock

Order

Inventory Log

Wallet

Payment

Notification

بهتر است عملیات در یک Service یا Application Layer مدیریت شود و Model صرفاً یکی از اجزای آن فرآیند باشد.


# Active Record برای پروژه‌های Laravel چقدر مناسب است؟

اگر پروژه Laravel شما عمدتاً CRUD محور است، Eloquent می‌تواند بسیاری از نیازهای Persistence را با ساختار ساده پوشش دهد.

در چنین پروژه‌ای ممکن است این ساختار کافی باشد:


Controller

    ↓

Service

    ↓

Eloquent Model

    ↓

Database

اما برای پروژه پیچیده‌تر می‌توان به سمت:


Controller

    ↓

Application Service

    ↓

Repository

    ↓

Eloquent / Data Mapper

    ↓

Database

رفت.

در نتیجه استفاده از Active Record نباید یک تصمیم ایدئولوژیک باشد؛ باید بر اساس نیاز پروژه انتخاب شود.


# جمع‌بندی

Active Record Pattern در PHP روشی برای طراحی Modelهایی است که علاوه بر نمایش داده، مسئولیت‌هایی برای خواندن و ذخیره‌سازی آن داده نیز دارند.

ایده اصلی بسیار ساده است:


Database Row

      ↕

Active Record Object

برای مثال:


$product = Product::find(10);



$product->price = 5000000;



$product->save();

این مدل برنامه‌نویسی برای پروژه‌های CRUD محور بسیار ساده و کاربردی است.

در Laravel، Eloquent تجربه‌ای بسیار نزدیک به این سبک ارائه می‌کند و به همین دلیل یادگیری Active Record به درک بهتر Eloquent نیز کمک می‌کند. نمونه‌های مختلف Active Record در PHP نیز همین ارتباط مستقیم Model با رکورد و عملیات save() را نشان می‌دهند. 

در مقابل، اگر پروژه دارای Domain پیچیده و نیاز جدی به جداسازی Persistence از منطق دامنه باشد، معماری‌هایی مانند Data Mapper و Repository می‌توانند گزینه‌های دیگری باشند.

بنابراین مهم‌ترین نکته این است:

Active Record را زمانی انتخاب کنید که سادگی Model و Persistence برای پروژه ارزشمند باشد؛ نه صرفاً به این دلیل که یک Design Pattern شناخته‌شده است.


# سوالات متداول

Active Record Pattern در PHP چیست؟

Active Record الگویی است که در آن یک Object معمولاً نماینده یک رکورد دیتابیس است و خود Object می‌تواند عملیات خواندن، ذخیره، به‌روزرسانی و حذف داده را انجام دهد.

آیا Eloquent در Laravel از Active Record استفاده می‌کند؟

Eloquent سبک طراحی بسیار نزدیک به Active Record دارد؛ Modelها می‌توانند رکوردهای دیتابیس را نمایش دهند و عملیاتی مانند save() و delete() را روی آن‌ها انجام دهند.

تفاوت Active Record و Data Mapper چیست؟

در Active Record، Model و Persistence به یکدیگر نزدیک هستند؛ در Data Mapper، Entity تلاش می‌کند مستقل از جزئیات Persistence باقی بماند و Mapper مسئول انتقال داده بین Entity و دیتابیس است.

تفاوت Active Record و Repository چیست؟

Active Record عملیات Persistence را در خود Model قرار می‌دهد، اما Repository یک abstraction برای دسترسی به Entityها ایجاد می‌کند و جزئیات ذخیره‌سازی را پشت Repository قرار می‌دهد.

آیا Active Record برای Laravel مناسب است؟

برای بسیاری از پروژه‌های CRUD محور Laravel، Eloquent و سبک Active Record بسیار کاربردی هستند. برای Domainهای پیچیده‌تر ممکن است معماری‌های جداشده‌تری مناسب باشند.

آیا Active Record با SOLID مشکل دارد؟

خود الگو لزوماً با SOLID ناسازگار نیست. مشکل زمانی ایجاد می‌شود که Model علاوه بر Persistence، مسئولیت‌های بسیار زیادی مانند پرداخت، گزارش‌گیری، Notification و تمام Business Logic سیستم را بر عهده بگیرد.

آیا Active Record همان ORM است؟

خیر. ORM یک مفهوم کلی برای نگاشت Objectها به داده‌های رابطه‌ای است و Active Record یکی از الگوهایی است که می‌تواند برای این منظور استفاده شود.

چه زمانی نباید از Active Record استفاده کنیم؟

اگر Domain بسیار پیچیده باشد و استقلال منطق کسب‌وکار از Persistence اهمیت زیادی داشته باشد، بهتر است معماری‌هایی مانند Data Mapper، Repository و Domain Model را نیز بررسی کنیم.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه