توضیح :
Domain‑Oriented Design (DOD) روشی ساده و عملی برای سازماندهی کد در پروژههای لاراول است که به جای تمرکز صرف روی لایههای سنتی (Controllers, Models, Views) کل کد را حول "دامین" یا حوزهٔ کسبوکار (مثلاً Blog, Order, User) قرار میدهد. هر دامنه شامل همهٔ اجزای مرتبط است: مدلها، کنترلرها، ریکوئستها، منابع، اکشنها، سیاستها و غیره.
Domain‑Oriented Design (DOD) is a practical way to organize Laravel code by grouping everything around business domains (e.g., Blog, Order, User) instead of technical layers. Each domain contains related pieces: models, controllers, requests, resources, actions, policies, etc.
مثال برای دامنهٔ Blog:
app/
└── Domain/
└── Blog/
├── Actions/
├── Http/
│ ├── Controllers/
│ ├── Requests/
│ └── Resources/
├── Models/
├── Policies/
├── Providers/
└── Routes/
هر زیرپوشه هدف مشخصی دارد:
Actions— واحدهای کوچک، با مسئولیت واحد (use‑cases) — small single‑responsibility units (use‑cases).Http/Controllers— کنترلر که اکشنها را صدا میزنند — thin controllers that call actions.Http/Requests— فرمریکوئستها (اعتبارسنجی / authorization) — validation and authorization.Http/Resources— API Resources و Collections — API Resources and Collections.Models— Eloquent models و collectionها — Eloquent models and custom collections.Policies— دسترسیها (authorization) — authorization logic.Providers— Domain-specific service providers (بارگذاری routes، ثبت bindings) — domain service providers (load routes, register bindings).Routes— فایلهایweb.phpوapi.php— domain routes likeweb.phpandapi.php.
کوپه شدن کد بر اساس دامنه: همهٔ فایلهای مرتبط با یک حوزه کنار هماند؛ پیدا کردن و تغییر دادن سادهتر میشود.
قابلیت توسعه و نگهداری بهتر: هر دامنه میتواند مستقلاٌ تکامل یابد (bounded contexts).
تستپذیری بهتر: اکشن های کوچک و مستقل قابل نوشتن تست واحد راحتی دارند.
انعطاف در تیمهای بزرگ: تیمها میتوانند روی دامنهها جداگانه کار کنند.
- Cohesion by domain: All files related to a business domain are together; easier to locate and change.
- Better maintainability and evolution: Domains can evolve independently (bounded contexts).
- Improved testability: Small actions and clear boundaries facilitate unit testing.
- Team scalability: Teams can own domains instead of layers.
- Action: a single use‑case (e.g.,
CreatePost) containing the core business operation. - Controller: thin — receives request, may call Request for validation, invokes Action, returns Resource/Response.
- Request: validation and authorization; controllers or actions type‑hint them to get
$request->validated(). - Model: Eloquent models handle persistence and queries. A separate Repository is only useful for multiple data sources or swapping ORM.
- Policy: authorization rules for models/domain.
- Resource: transforms model/collection to array/JSON.
- Provider: load domain routes, register bindings, observers, policies.
- Models namespace:
App\Domain\{Domain}\Models. - Requests namespace:
App\Domain\{Domain}\Http\Requests. - Resources namespace:
App\Domain\{Domain}\Http\Resources. - Actions namespace:
App\Domain\{Domain}\Actions— each action hashandle()or__invoke(). - Keep controllers thin; put business logic in Actions or Services.
- Use a DomainServiceProvider to load routes and register bindings.
- Write tests for Actions and for any custom make:* commands.
این بخش از سند یک مرجع سریع و کاربردی برای استفاده از دستورات شخصیسازیشده پروژه (Domain‑Oriented Design) است. هر بخش شامل توضیح کوتاه، یک مثال عملی و لینک شده به مستند کامل است.
Generate commands and then copy the command code and paste it into the created files.
php artisan make:command MakeDomain
php artisan make:command MakeDomainAction
php artisan make:command MakeDomainController
php artisan make:command MakeDomainModel
php artisan make:command MakeDomainPolicy
php artisan make:command MakeDomainRequest
php artisan make:command MakeDomainResource
php artisan make:command MakeDomainServiceProvider
Scaffold domain folders under app/Domain/{Name} (Models, Http, Actions, Policies, Providers, Routes).
مثال کاربردی:
php artisan make:domain Blogایجاد: app/Domain/Blog/{Models,Actions,Http,Providers,Policies,Routes}
Create a Domain ServiceProvider.
مثال کاربردی:
php artisan make:d-provider Blog
🤓 More about providers in laravel
Create a domain model and optionally migration/factory/seeder.
مثال کاربردی:
php artisan make:d-model Post --domain=Blog -m -f -s
🤓 More about eloquent models in laravel
Scaffold an Action class (invokable or custom method) with optional model/request imports.
مثال کاربردی:
php artisan make:d-action CreatePost --domain=Blog --invokable --model=Post
Generate FormRequest classes placed inside the domain (not global app/Http/Requests).
مثال کاربردی:
php artisan make:d-request StorePost --domain=Blog
🤓 More about form request validation in laravel
Create controllers inside the domain. Supports resource controllers and rewrites imports to domain Requests and Models.
مثال کاربردی:
php artisan make:d-controller PostController --domain=Blog --model=Post --resource --requests
🤓 More about controllers in laravel
Create API Resources placed inside domain; supports collection mode and model association.
مثال کاربردی:
php artisan make:d-resource PostResource --domain=Blog --model=Post
php artisan make:d-resource PostCollection --domain=Blog --collection --model=Post
🤓 More about resources in laravel(in eloquent)
Create a domain policy; optionally scaffold methods with model type hints and show how to register it.
مثال کاربردی:
php artisan make:d-policy Post --domain=Blog --model=Post
🤓 More about policies in laravel(in authorization)
این بخش از سند نحوهٔ ثبت Provider، نگاشت مدل به جدول، استفاده از Action و Request در Controller، تعریف و ثبت Policy، بارگذاری Routeها، مدیریت دامنهها و دیگر تنظیمات لازم برای استفادهٔ عملی از ساختار Domain‑Oriented Design (DOD) را به صورت گامبهگام توضیح میدهد.
توضیح : DOD به شما کمک میکند همهٔ فایلهای مرتبط با یک حوزهٔ کسبوکار (Domain) را کنار هم نگه دارید. برای اینکه Laravel به درستی با این ساختار کار کند باید: namespaceها صحیح باشند، ServiceProviderهای دامنه را ثبت کنید (یا آنها را از طریق یک مکانیزم auto‑discover/loader بارگذاری کنید)، و در زمان تولید فایلها مسیرها را به namespace دامنه هدایت کنید.
DOD groups everything by business domains. To integrate with Laravel: make sure namespaces are consistent, register Domain ServiceProviders (or load them automatically), and ensure generated files use the domain namespaces.
چرا و چگونه؟
هر دامنه میتواند یک Provider مخصوص به خود داشته باشد که وظیفهٔ بارگذاری فایلهای route دامنه، ثبت bindingها، register کردن policyها، یا mount کردن امکانات domain را برعهده دارد. بهترین روش این است که هر دامنه یک Providers/DomainServiceProvider.php داشته باشد و شما آن را در bootstrap/providers.php یا از طریق auto‑registration ثبت کنید.
Registering Providers in laravel
Provider (app/Domain/Blog/Providers/DomainServiceProvider.php):
<?php
namespace App\Domain\Blog\Providers;
use Illuminate\Support\ServiceProvider;
class DomainServiceProvider extends ServiceProvider
{
public function register(): void
{
// bind domain interfaces here
// $this->app->bind(Contract::class, Impl::class);
}
public function boot(): void
{
// load domain routes (if exist)
if (file_exists(base_path('app/Domain/Blog/Routes/web.php'))) {
$this->loadRoutesFrom(base_path('app/Domain/Blog/Routes/web.php'));
}
if (file_exists(base_path('app/Domain/Blog/Routes/api.php'))) {
$this->loadRoutesFrom(base_path('app/Domain/Blog/Routes/api.php'));
}
// register policies here or via AuthServiceProvider
}
}Manual registration:
- فایل
bootstrap/providers.phpرا باز کنید و در آرایهٔprovidersخط زیر را اضافه کنید (با رعایت فاصله و کاما):
App\Domain\Blog\Providers\DomainServiceProvider::class,- نکته مهم: قبل از ویرایش فایل bootstrap/providers.php بهتر است از آن یک backup بگیرید.
cp bootstrap/providers.php bootstrap/providers.php.bakWhy & How?
Registering a DomainServiceProvider lets you load domain routes, register bindings and policies. You can register it manually in bootstrap/providers.php or via a central auto-loader.
Manual registration snippet (in bootstrap/providers.php providers array):
App\Domain\Blog\Providers\DomainServiceProvider::class,در DOD مدلها در App\Domain\{Domain}\Models قرار میگیرند.
- نام جدول: اگر از convention لاراول (
snake_caseجمع) پیروی کنید نیازی به تغییر نیست. مثال: مدلPostبه جدولpostsنگاشت میشود. برای override جدول ازprotected $table = 'my_table'در مدل استفاده کنید.
app/Domain/Blog/Models/Post.php:
<?php
namespace App\Domain\Blog\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'posts'; // optional
protected $fillable = ['title','body','user_id'];
public function author()
{
return $this->belongsTo(\App\Domain\Blog\Models\User::class, 'user_id');
}
}note:
- Models live under
App\Domain\{Domain}\Models. - Table name follows Laravel conventions; override with
$tableif needed. Use$connection,$fillable,$casts, etc. - Keep migrations in
database/migrationsunless you have a specific reason.
- Controllers should be thin: validate and delegate to Actions. Inject Action and FormRequest in method signature. Return Resources.
اصول کلی:
- کنترلرها کد کمی داشته باشند: فقط وظیفهٔ فراخوانی Action و برگرداندن Response را دارند.
- منطق بیزینسی داخل Actionها قرار میگیرد. Action میتواند invokable (
__invoke) یا دارای متدhandle()باشد. - برای اعتبارسنجی از FormRequestها استفاده کنید و آنها را در signature متد کنترلر type‑hint کنید تا لاراول خودکار validation را اجرا کند.
Controller :
<?php
namespace App\Domain\Blog\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Domain\Blog\Actions\CreatePost; // action
use App\Domain\Blog\Http\Requests\StorePostRequest; // form request
use App\Domain\Blog\Http\Resources\PostResource;
class PostController extends Controller
{
public function store(StorePostRequest $request, CreatePost $action)
{
// $request is validated automatically
$data = $request->validated();
// Business logic encapsulated inside Action
$post = $action->handle($data);
return new PostResource($post);
}
}public function store(StorePostRequest $request, CreatePost $createPost)
{
$post = $createPost->handle($request->validated());
return new PostResource($post);
}Action :
<?php
namespace App\Domain\Blog\Actions;
use App\Domain\Blog\Models\Post;
class CreatePost
{
public function handle(array $data): Post
{
return Post::create($data);
}
}شرح:
- با
CreatePostبه عنوان یک کلاس Action کهhandle(array $data)را پیاده میکند، منطق ایجاد یک پست در یک مکان متمرکز قرار میگیرد. StorePostRequestمسئول validation و authorization است.- نتیجه توسط
PostResourceبرگردانده میشود.
Create policy, register it (AuthServiceProvider or Domain provider), use authorize() or can middleware.
روند کار:
- ایجاد Policy داخل
app/Domain/{Domain}/Policiesتوسط دستورmake:d-policyیا دستی. - ثبت Policy ها در داخل
DomainServiceProviderباGate::policy(). - در کنترلرها یا مسیرها از
canیاauthorize()استفاده کنید.
boot():
use Illuminate\Support\Facades\Gate;
public function boot()
{
Gate::policy(\App\Domain\Blog\Models\Post::class, \App\Domain\Blog\Policies\PostPolicy::class);
}usage in controller:
public function update(StorePostRequest $request, Post $post)
{
$this->authorize('update', $post); // uses PostPolicy::update
// ...
}Place domain routes in domain-specific route files and load them from the DomainServiceProvider.
روند کار:
- قرار دادن routeهای مربوط به دامنه در
app/Domain/{Domain}/Routes/web.phpوapi.phpمعمولاً بهترین روش است. DomainServiceProvider::boot()باید این فایلها را باloadRoutesFrom()بارگذاری کند.
example routes file (app/Domain/Blog/Routes/api.php):
<?php
use Illuminate\Support\Facades\Route;
Route::prefix('api/blog')->middleware('api')->group(function () {
Route::apiResource('posts', \App\Domain\Blog\Http\Controllers\PostController::class);
});