در بسیاری از پروژههای PHP، اطلاعات برنامه مستقیماً داخل مدلهایی قرار میگیرند که با دیتابیس ارتباط دارند. این روش برای پروژههای ساده مناسب است، اما در پروژههای بزرگتر ممکن است باعث وابستگی شدید منطق برنامه به ساختار دیتابیس شود.
برای مثال، در یک سیستم فروشگاهی ممکن است کلاس Product همزمان مسئولیتهای زیر را بر عهده داشته باشد:
- نگهداری اطلاعات محصول
- اعتبارسنجی قوانین تجاری
- اجرای Queryهای SQL
- ذخیره محصول در دیتابیس
- حذف محصول
- تبدیل دادههای دیتابیس به Object
- مدیریت ارتباط با جدولها
این ترکیب مسئولیتها باعث میشود تغییر ساختار دیتابیس روی منطق اصلی برنامه اثر بگذارد.
Data Mapper Pattern برای حل همین مشکل استفاده میشود. در این الگو، Entity یا Domain Object از دیتابیس مستقل میماند و یک لایه جداگانه وظیفه انتقال داده بین Objectهای برنامه و محل ذخیرهسازی را بر عهده میگیرد. <Cite refs={["turn0search0","turn0search12"]} />
Data Mapper Pattern چیست؟
Data Mapper یک الگوی طراحی برای جداسازی مدل Domain از لایه ذخیرهسازی اطلاعات است.
در این روش، Entity فقط اطلاعات و رفتارهای مربوط به Domain را نگهداری میکند و از جزئیات زیر اطلاعی ندارد:
- نام جدول دیتابیس
- Queryهای SQL
- نوع Database
- PDO
- ساختار ستونها
- روش ذخیرهسازی
- نحوه بازیابی اطلاعات
یک کلاس جداگانه به نام Mapper، دادهها را بین دیتابیس و Entity منتقل میکند.
ساختار ساده:
Database
▲
│
Data Mapper
▲
│
Domain Entity
▲
│
Application
در مستندات DesignPatternsPHP نیز Data Mapper به عنوان بخشی از Data Access Layer معرفی شده است که دادهها را بهصورت دوطرفه بین Persistent Storage و مدل درون حافظه منتقل میکند. هدف آن مستقل نگهداشتن Domain از دیتابیس است. <Cite refs={["turn0search0","turn0search2"]} />
اجزای اصلی Data Mapper Pattern
۱. Entity
Entity نماینده یک مفهوم واقعی در Domain است؛ مانند:
- User
- Product
- Order
- Invoice
- Service
- Subscription
Entity نباید مسئول اجرای Query یا اتصال به دیتابیس باشد.
۲. Data Mapper
Mapper مسئول تبدیل دادههای دیتابیس به Entity و تبدیل Entity به داده قابل ذخیره در دیتابیس است.
۳. Data Source
Data Source محل ذخیره اطلاعات است؛ برای مثال:
- MySQL
- PostgreSQL
- SQLite
- فایل
- API خارجی
- Redis
۴. Repository
Repository در بعضی پیادهسازیها برای ارائه یک Interface مناسب جهت جستوجو و دریافت Entityها استفاده میشود. Repository و Data Mapper دقیقاً یک مفهوم نیستند، اما میتوانند در کنار هم استفاده شوند.
۵. Service یا Application Layer
این لایه از Entity و Repository استفاده میکند و نباید درگیر جزئیات SQL شود.
مشکل روش مستقیم
فرض کنید کلاس زیر را داریم:
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public int $id,
public string $name,
public string $email
) {
}
public static function find(int $id): ?self
{
// اجرای Query در داخل Entity
return null;
}
public function save(): void
{
// ذخیره مستقیم در دیتابیس
}
}
در این مثال، کلاس User هم Entity است و هم مسئول ارتباط با دیتابیس.
مشکلات این روش:
- تست Entity بدون دیتابیس دشوار میشود.
- تغییر دیتابیس به تغییر Entity نیاز دارد.
- منطق Domain با SQL ترکیب میشود.
- مسئولیت کلاس بیش از حد زیاد میشود.
- استفاده از Entity در محیطهای مختلف سختتر میشود.
Data Mapper تلاش میکند این وابستگی را حذف کند.
ساخت Entity مستقل از دیتابیس
ابتدا یک Entity ساده برای User ایجاد میکنیم:
<?php
declare(strict_types=1);
final class User
{
public function __construct(
private readonly int $id,
private string $name,
private string $email
) {
}
public function id(): int
{
return $this->id;
}
public function name(): string
{
return $this->name;
}
public function email(): string
{
return $this->email;
}
public function changeName(string $name): void
{
if (trim($name) === '') {
throw new InvalidArgumentException(
'User name cannot be empty.'
);
}
$this->name = $name;
}
public function changeEmail(string $email): void
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException(
'Invalid email address.'
);
}
$this->email = $email;
}
}
این کلاس فقط مسئول نگهداری و مدیریت وضعیت User است. هیچ Query، PDO یا نام جدولی در آن وجود ندارد.
ساخت Data Mapper Interface
حالا Interface مربوط به Mapper را تعریف میکنیم:
<?php
declare(strict_types=1);
interface UserMapperInterface
{
public function findById(int $id): ?User;
public function insert(User $user): void;
public function update(User $user): void;
}
این Interface مشخص میکند که Mapper چه عملیاتی را پشتیبانی میکند.
پیادهسازی Mapper با PDO
در این مثال از PDO استفاده میکنیم:
<?php
declare(strict_types=1);
final class PdoUserMapper implements UserMapperInterface
{
public function __construct(
private readonly PDO $pdo
) {
}
public function findById(int $id): ?User
{
$statement = $this->pdo->prepare(
'SELECT id, name, email
FROM users
WHERE id = :id'
);
$statement->execute([
'id' => $id,
]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
if ($row === false) {
return null;
}
return new User(
id: (int) $row['id'],
name: (string) $row['name'],
email: (string) $row['email']
);
}
public function insert(User $user): void
{
$statement = $this->pdo->prepare(
'INSERT INTO users (id, name, email)
VALUES (:id, :name, :email)'
);
$statement->execute([
'id' => $user->id(),
'name' => $user->name(),
'email' => $user->email(),
]);
}
public function update(User $user): void
{
$statement = $this->pdo->prepare(
'UPDATE users
SET name = :name, email = :email
WHERE id = :id'
);
$statement->execute([
'id' => $user->id(),
'name' => $user->name(),
'email' => $user->email(),
]);
}
}
در اینجا PdoUserMapper مسئول تبدیل دادههای دیتابیس به Entity و تبدیل Entity به پارامترهای SQL است.
کلاس User همچنان از وجود PDO و SQL اطلاعی ندارد.
استفاده از Mapper
<?php
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=shop;charset=utf8mb4',
'root',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
$mapper = new PdoUserMapper($pdo);
$user = $mapper->findById(1);
if ($user !== null) {
echo $user->name();
}
در این کد، برنامه برای دریافت User مستقیماً SQL اجرا نمیکند. فقط از Mapper استفاده میکند.
ساخت Repository در کنار Data Mapper
برای اینکه کد برنامه از جزئیات Mapper نیز مستقل شود، میتوان یک Repository تعریف کرد:
<?php
declare(strict_types=1);
interface UserRepositoryInterface
{
public function findById(int $id): ?User;
public function save(User $user): void;
}
پیادهسازی Repository:
<?php
declare(strict_types=1);
final class UserRepository implements UserRepositoryInterface
{
public function __construct(
private readonly UserMapperInterface $mapper
) {
}
public function findById(int $id): ?User
{
return $this->mapper->findById($id);
}
public function save(User $user): void
{
$existingUser = $this->mapper->findById($user->id());
if ($existingUser === null) {
$this->mapper->insert($user);
return;
}
$this->mapper->update($user);
}
}
حالا Application Layer با Repository کار میکند و Repository از Mapper استفاده میکند.
ساختار:
Controller
│
▼
Application Service
│
▼
UserRepository
│
▼
UserMapper
│
▼
Database
نمونه Application Service
<?php
declare(strict_types=1);
final class UserService
{
public function __construct(
private readonly UserRepositoryInterface $users
) {
}
public function renameUser(
int $userId,
string $newName
): void {
$user = $this->users->findById($userId);
if ($user === null) {
throw new RuntimeException('User not found.');
}
$user->changeName($newName);
$this->users->save($user);
}
}
این Service فقط منطق کاربردی را اجرا میکند. هیچ اطلاعی از SQL یا جدول users ندارد.
تفاوت Data Mapper و Active Record
یکی از مهمترین موضوعات در این الگو، تفاوت آن با Active Record است.
در Active Record، Object معمولاً هم نماینده یک رکورد دیتابیس است و هم عملیات ذخیره، حذف و بازیابی را انجام میدهد.
در Data Mapper، Entity از دیتابیس مستقل است و عملیات ذخیرهسازی به Mapper سپرده میشود. <Cite refs={["turn0search0","turn0search5"]} />
| ویژگی | Data Mapper | Active Record |
|---|---|---|
| محل Queryها | Mapper یا Data Access Layer | معمولاً داخل Model |
| وابستگی Entity به دیتابیس | کم یا مستقل | زیاد |
| مناسب برای Domain پیچیده | معمولاً مناسبتر | ممکن است محدودکننده شود |
| سادگی شروع پروژه | پیچیدهتر | سادهتر |
| جداسازی مسئولیتها | بیشتر | کمتر |
| نمونه رایج | Doctrine | Eloquent در Laravel |
مثال Active Record در Laravel
<?php
use Illuminate\Database\Eloquent\Model;
final class User extends Model
{
protected $table = 'users';
}
استفاده:
$user = User::find(1);
$user->name = 'Ali';
$user->save();
در این مدل، User هم مدل Domain و هم نماینده رکورد دیتابیس است.
رویکرد Data Mapper
در رویکرد Data Mapper، Entity مستقل است:
$user = new User(
id: 1,
name: 'Ali',
email: 'ali@example.com'
);
سپس Mapper یا Repository وظیفه ذخیره آن را بر عهده میگیرد:
$repository->save($user);
هیچکدام از متدهای save یا find داخل Entity قرار ندارند.
آیا Laravel از Data Mapper استفاده میکند؟
Laravel بهصورت پیشفرض از Eloquent ORM استفاده میکند و Eloquent بیشتر به الگوی Active Record نزدیک است.
این موضوع به معنی بدبودن Eloquent نیست. Eloquent برای بسیاری از پروژههای Laravel ساده، سریع و کاربردی است.
اما اگر پروژه شما دارای شرایط زیر باشد، ممکن است بخواهید Entity و Persistence را بیشتر از هم جدا کنید:
- Domain پیچیده
- قوانین تجاری زیاد
- چند منبع داده
- نیاز به تست Domain بدون دیتابیس
- استفاده از دیتابیسهای مختلف
- وجود Legacy Database
- نیاز به مدلهایی متفاوت از ساختار جدولها
- استفاده از معماری Hexagonal یا Clean Architecture
در چنین شرایطی میتوان از Entityهای مستقل، Repository و Mapper اختصاصی استفاده کرد.
پیادهسازی ساده Data Mapper در Laravel
فرض کنید یک Entity برای محصول داریم:
<?php
namespace App\Domain\Product;
final class Product
{
public function __construct(
private readonly int $id,
private string $title,
private int $price
) {
}
public function id(): int
{
return $this->id;
}
public function title(): string
{
return $this->title;
}
public function price(): int
{
return $this->price;
}
public function changePrice(int $price): void
{
if ($price < 0) {
throw new \InvalidArgumentException(
'Price cannot be negative.'
);
}
$this->price = $price;
}
}
Interface مربوط به Mapper:
<?php
namespace App\Domain\Product;
interface ProductMapperInterface
{
public function findById(int $id): ?Product;
public function save(Product $product): void;
}
پیادهسازی با Query Builder:
<?php
namespace App\Infrastructure\Product;
use App\Domain\Product\Product;
use App\Domain\Product\ProductMapperInterface;
use Illuminate\Support\Facades\DB;
final class DatabaseProductMapper implements ProductMapperInterface
{
public function findById(int $id): ?Product
{
$row = DB::table('products')
->where('id', $id)
->first();
if ($row === null) {
return null;
}
return new Product(
id: (int) $row->id,
title: (string) $row->title,
price: (int) $row->price
);
}
public function save(Product $product): void
{
DB::table('products')->updateOrInsert(
[
'id' => $product->id(),
],
[
'title' => $product->title(),
'price' => $product->price(),
]
);
}
}
ثبت در Service Container:
<?php
use App\Domain\Product\ProductMapperInterface;
use App\Infrastructure\Product\DatabaseProductMapper;
$this->app->bind(
ProductMapperInterface::class,
DatabaseProductMapper::class
);
حالا در Service:
<?php
namespace App\Application\Product;
use App\Domain\Product\ProductMapperInterface;
final class ProductService
{
public function __construct(
private readonly ProductMapperInterface $products
) {
}
public function increasePrice(
int $productId,
int $amount
): void {
$product = $this->products->findById($productId);
if ($product === null) {
throw new \RuntimeException(
'Product not found.'
);
}
$product->changePrice(
$product->price() + $amount
);
$this->products->save($product);
}
}
در این ساختار، Domain Product از Laravel و دیتابیس مستقل است. فقط کلاس Infrastructure از Query Builder استفاده میکند.
مزایای Data Mapper Pattern
۱. جداسازی Domain از دیتابیس
Entityها به SQL، PDO یا ORM وابسته نیستند.
۲. تستپذیری بهتر
میتوان Entity و قوانین تجاری را بدون اتصال به دیتابیس تست کرد.
۳. انعطاف در تغییر دیتابیس
اگر روش ذخیرهسازی تغییر کند، لازم نیست منطق Domain بازنویسی شود.
۴. مناسب برای Domainهای پیچیده
وقتی قوانین تجاری زیاد هستند، مستقلبودن Entityها میتواند طراحی را واضحتر کند.
۵. رعایت بهتر Single Responsibility Principle
Entity مسئول Domain است و Mapper مسئول انتقال داده. این جداسازی با اصل Single Responsibility همراستا است. <Cite refs={["turn0search0","turn0search12"]} />
۶. مناسب برای Legacy Database
اگر ساختار دیتابیس قدیمی و نامنظم باشد، Mapper میتواند آن را به مدلهای تمیزتر Domain تبدیل کند.
۷. امکان استفاده از چند منبع داده
میتوان Mapperهای متفاوتی برای MySQL، API، فایل یا حافظه ایجاد کرد.
معایب Data Mapper Pattern
۱. تعداد کلاسهای بیشتر
ممکن است برای هر Entity به Mapper، Repository و DTO نیاز باشد.
۲. کدنویسی بیشتر
در مقایسه با Eloquent، پیادهسازی Data Mapper معمولاً کد بیشتری نیاز دارد.
۳. نیاز به طراحی دقیق
باید مشخص شود کدام مسئولیت در Entity، Mapper، Repository یا Service قرار میگیرد.
۴. پیچیدگی برای پروژههای کوچک
اگر پروژه ساده باشد، استفاده از Data Mapper ممکن است ارزش پیچیدگی اضافه را نداشته باشد.
۵. مدیریت Mapping دشوار
تبدیل دادههای پیچیده بین جدولها و Entityها میتواند نیازمند کد زیادی باشد.
چه زمانی از Data Mapper استفاده کنیم؟
Data Mapper در شرایط زیر انتخاب مناسبی است:
- منطق Domain از CRUD ساده پیچیدهتر است.
- Entityها باید مستقل از ORM باشند.
- تستکردن منطق بدون دیتابیس اهمیت دارد.
- دیتابیس Legacy دارید.
- ساختار Domain با ساختار جدولها متفاوت است.
- ممکن است دیتابیس یا منبع داده تغییر کند.
- از معماری Clean Architecture یا Hexagonal استفاده میکنید.
- یک Entity از چند جدول یا چند منبع داده ساخته میشود.
چه زمانی از Data Mapper استفاده نکنیم؟
برای یک پنل مدیریتی ساده با چند فرم CRUD، استفاده از Eloquent یا Query Builder ممکن است کافی باشد.
همچنین اگر تیم شما با Data Mapper آشنایی ندارد و پروژه نیاز به تحویل سریع دارد، بهتر است ابتدا نیاز واقعی به این معماری را بررسی کنید.
نباید صرفاً به دلیل حرفهایبهنظررسیدن معماری، تعداد لایهها را افزایش داد.
تست Entity بدون دیتابیس
یکی از مزایای مهم Data Mapper این است که میتوان قوانین Entity را بدون اتصال به دیتابیس تست کرد.
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class UserTest extends TestCase
{
public function test_user_can_change_name(): void
{
$user = new User(
id: 1,
name: 'Ali',
email: 'ali@example.com'
);
$user->changeName('Reza');
self::assertSame('Reza', $user->name());
}
public function test_empty_name_is_rejected(): void
{
$user = new User(
id: 1,
name: 'Ali',
email: 'ali@example.com'
);
$this->expectException(InvalidArgumentException::class);
$user->changeName('');
}
public function test_invalid_email_is_rejected(): void
{
$user = new User(
id: 1,
name: 'Ali',
email: 'ali@example.com'
);
$this->expectException(InvalidArgumentException::class);
$user->changeEmail('invalid-email');
}
}
این تستها بدون اجرای SQL و بدون نیاز به دیتابیس اجرا میشوند.
تست Mapper با Mock
برای تست Mapper میتوان از Mock مربوط به PDO استفاده کرد، یا برای تستهای واقعیتر از دیتابیس آزمایشی استفاده کرد.
در پروژههای Laravel میتوان از موارد زیر استفاده کرد:
- SQLite در حافظه
- Database Transactions
- Test Database
- Mock کردن Query Builder
- Integration Test
تست Entity معمولاً Unit Test است؛ اما تست Mapper اغلب به Integration Test نزدیکتر است، چون به لایه ذخیرهسازی وابستگی دارد.
اشتباهات رایج در Data Mapper
اشتباه اول: قرار دادن SQL داخل Entity
اگر Entity مستقیماً Query اجرا کند، جداسازی اصلی Data Mapper از بین میرود.
اشتباه دوم: تبدیل Mapper به کلاس بسیار بزرگ
Mapper نباید تمام منطق تجاری برنامه را در خود جای دهد. وظیفه اصلی آن انتقال داده است.
اشتباه سوم: ترکیب بیدلیل Data Mapper و Active Record
اگر پروژه از Eloquent استفاده میکند، مخفیکردن Eloquent پشت چند لایه اضافی لزوماً به معنی Data Mapper واقعی نیست.
اشتباه چهارم: قرار دادن اعتبارسنجی در Mapper
قوانین تجاری مانند حداقل قیمت، وضعیت سفارش یا محدودیت تغییر وضعیت بهتر است در Domain یا Service قرار بگیرند.
اشتباه پنجم: نادیدهگرفتن تراکنشها
اگر ذخیره یک Entity شامل چند Query است، باید تراکنش دیتابیس در لایه مناسب مدیریت شود.
اشتباه ششم: تبدیل مستقیم همه دادهها به آرایه
اگر Domain پیچیده است، استفاده از آرایههای بدون ساختار میتواند باعث ازبینرفتن مزایای Entityهای مستقل شود.
اشتباه هفتم: ساخت لایههای غیرضروری
برای پروژههای کوچک، Entity، Mapper، Repository، Service و Factory همزمان ممکن است بیش از نیاز باشند.
ساختار پیشنهادی پوشهها در Laravel
یک ساختار ساده برای پروژهای که از Data Mapper استفاده میکند:
app/
├── Domain/
│ └── Product/
│ ├── Product.php
│ └── ProductMapperInterface.php
│
├── Application/
│ └── Product/
│ └── ProductService.php
│
├── Infrastructure/
│ └── Product/
│ └── DatabaseProductMapper.php
│
└── Providers/
└── AppServiceProvider.php
در این ساختار:
Domainشامل Entity و قوانین اصلی است.Applicationشامل Use Caseها و سرویسهای کاربردی است.Infrastructureشامل دیتابیس و پیادهسازیهای فنی است.Providersوابستگیها را در Service Container ثبت میکند.
Data Mapper و معماری Clean Architecture
Data Mapper با معماریهای لایهای، Clean Architecture و Hexagonal Architecture سازگاری خوبی دارد؛ زیرا وابستگی به سمت Domain وارد نمیشود.
در یک طراحی مناسب:
Infrastructure → Application → Domain
Domain نباید برای اجرای قوانین اصلی خود به دیتابیس یا Framework وابسته باشد.
البته این موضوع به معنی حذف کامل Laravel نیست. میتوان از Laravel در لایه Application و Infrastructure استفاده کرد و Domain را تا حد امکان مستقل نگه داشت.
نمونه کامل Data Mapper در PHP
<?php
declare(strict_types=1);
final class Product
{
public function __construct(
private readonly int $id,
private string $title,
private int $price
) {
}
public function id(): int
{
return $this->id;
}
public function title(): string
{
return $this->title;
}
public function price(): int
{
return $this->price;
}
public function changePrice(int $price): void
{
if ($price < 0) {
throw new InvalidArgumentException(
'Price cannot be negative.'
);
}
$this->price = $price;
}
}
interface ProductMapperInterface
{
public function findById(int $id): ?Product;
public function save(Product $product): void;
}
final class InMemoryProductMapper implements ProductMapperInterface
{
/**
* @var array<int, Product>
*/
private array $products = [];
public function findById(int $id): ?Product
{
return $this->products[$id] ?? null;
}
public function save(Product $product): void
{
$this->products[$product->id()] = $product;
}
}
$mapper = new InMemoryProductMapper();
$product = new Product(
id: 1,
title: 'Laptop',
price: 50000000
);
$mapper->save($product);
$product->changePrice(52000000);
$mapper->save($product);
$storedProduct = $mapper->findById(1);
echo $storedProduct?->price();
در این نمونه به جای دیتابیس واقعی از حافظه استفاده شده است، اما ساختار کلی همان Data Mapper است. میتوان بعداً InMemoryProductMapper را با DatabaseProductMapper جایگزین کرد، بدون اینکه Entity تغییر کند.
جمعبندی
Data Mapper Pattern در PHP الگویی برای جداسازی Entity و منطق Domain از لایه ذخیرهسازی اطلاعات است.
در این الگو:
- Entity مسئول قوانین و وضعیت Domain است.
- Mapper دادهها را بین Entity و دیتابیس منتقل میکند.
- Repository میتواند Interface مناسب برای دسترسی به Entityها ارائه دهد.
- Application Service منطق Use Caseها را اجرا میکند.
- Infrastructure مسئول جزئیات فنی مانند PDO، Query Builder یا ORM است.
Data Mapper برای پروژههایی با Domain پیچیده، دیتابیس Legacy، نیاز به تست مستقل و معماریهای لایهای مناسب است. اما برای پروژههای ساده CRUD، استفاده از Eloquent یا Query Builder ممکن است انتخاب سادهتر و منطقیتری باشد.
مهمترین نکته این است که Data Mapper را فقط به خاطر نام یا پیچیدگی ظاهری آن انتخاب نکنید. ابتدا نیاز پروژه، اندازه Domain، سطح پیچیدگی قوانین تجاری و نیازهای تست را بررسی کنید.
سوالات متداول
Data Mapper Pattern در PHP چیست؟
Data Mapper الگویی است که انتقال داده بین دیتابیس و Entityهای برنامه را به یک لایه جداگانه میسپارد تا Domain از جزئیات ذخیرهسازی مستقل بماند.
تفاوت Data Mapper و Active Record چیست؟
در Active Record، مدل معمولاً هم نماینده رکورد دیتابیس است و هم عملیات ذخیره و بازیابی را انجام میدهد. در Data Mapper، Entity از دیتابیس مستقل است و Mapper مسئول انتقال داده است.
آیا Eloquent از Data Mapper استفاده میکند؟
Eloquent در Laravel بیشتر به الگوی Active Record نزدیک است. میتوان در Laravel معماری Data Mapper ساخت، اما باید Entity، Mapper و لایههای دسترسی به داده را جداگانه طراحی کرد.
آیا Data Mapper برای پروژههای کوچک مناسب است؟
معمولاً برای پروژههای کوچک CRUD ممکن است بیش از نیاز پیچیدگی ایجاد کند. این الگو زمانی ارزش بیشتری دارد که Domain پیچیده یا نیاز به جداسازی جدی از دیتابیس وجود داشته باشد.
آیا Repository و Data Mapper یکسان هستند؟
خیر. Mapper مسئول تبدیل داده بین Entity و Storage است، در حالی که Repository معمولاً یک Interface برای جستوجو و مدیریت Entityها ارائه میدهد. این دو میتوانند در کنار هم استفاده شوند.
مزیت اصلی Data Mapper چیست؟
مهمترین مزیت آن جداسازی منطق Domain از دیتابیس است. این جداسازی میتواند تستپذیری، انعطافپذیری و قابلیت نگهداری پروژه را بهتر کند.
آیا Data Mapper با Laravel سازگار است؟
بله. میتوان Entityهای مستقل از Laravel ساخت و در لایه Infrastructure از Query Builder، PDO یا حتی Eloquent برای پیادهسازی Mapper استفاده کرد.
آیا Data Mapper باعث افزایش سرعت برنامه میشود؟
هدف اصلی Data Mapper افزایش سرعت نیست؛ بلکه جداسازی مسئولیتها و استقلال Domain از Persistence است. بسته به پیادهسازی، ممکن است لایههای اضافی نیز ایجاد شود.





