لاراول که به دلیل سینتکس زیبا و ویژگی های قدرتمندش مشهور است، همچنین پایه ای قوی برای معماری مدولار فراهم می کند. ماژولار کردن برنامه لاراول مزایایی مانند بهبود قابلیت نگهداری، مقیاس پذیری و سازماندهی را ارائه می دهد. در این مقاله، به جنبه های کلیدی پیاده سازی معماری مدولار در لاراول و یک پروژه عملی خواهیم پرداخت.
ماژول ها چیست؟
در context لاراول، ماژول ها اجزای مستقلی هستند که عملکردهای خاص یک برنامه کاربردی را در بر می گیرند. آنها جداسازی دقیق نگرانی ها را امکان پذیر می کنند و پایگاه کد را قابل خواندن تر و قابل نگهداری تر می کنند.
برای مثال :
// Example of a simple module in Laravel
// app/Modules/ExampleModule/Controllers/ExampleController.php
namespace App\Modules\ExampleModule\Controllers;
use App\Http\Controllers\Controller;
class ExampleController extends Controller
{
public function index()
{
return view('example-module::index');
}
}
تفکیک نگرانی ها در معماری ماژولار
یکی از اصول اساسی معماری مدولار، تفکیک دغدغه ها است. رویکرد ماژولار لاراول به توسعه دهندگان این امکان را می دهد تا جنبه های مختلف برنامه مانند تعاملات پایگاه داده، منطق تجاری و لایه های provider ها را جدا کنند.
مثال:
// Separating concerns in a module
// app/Modules/ExampleModule/Models/ExampleModel.php
namespace App\Modules\ExampleModule\Models;
use Illuminate\Database\Eloquent\Model;
class ExampleModel extends Model
{
// Model logic here
}
ساختار دایرکتوری در معماری ماژولار
سازماندهی ماژول ها در پروژه لاراول برای حفظ وضوح بسیار مهم است. یک ساختار دایرکتوری تمیز ایجاد کنید که مؤلفههای مدولار برنامه شما را منعکس میکند و به توسعهدهندگان کمک میکند تا پایگاه کد را درک کنند.
مثال:
- app
- Modules
- ExampleModule
- Controllers
- Models
- Views
autoload
در لاراول
ویژگی های autoload
لاراول نقش مهمی در توسعه ماژولار ایفا می کند. اطمینان حاصل کنید که ماژول های شما به طور خودکار بارگذاری می شوند تا عملکرد کلی و پاسخگویی برنامه شما را افزایش دهند.
مثال:
// composer.json
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "app/Modules/"
}
}
}
ارتباط بین ماژول ها
تسهیل ارتباط بین ماژول ها برای ایجاد یک برنامه منسجم ضروری است. لاراول مکانیسم هایی مانند رویدادها، ارائه دهندگان سرویس و سایر ویژگی ها را برای فعال کردن تعامل یکپارچه بین اجزای مختلف فراهم می کند.
مثال:
// Broadcasting an event from one module
event(new \App\Modules\ExampleModule\Events\ExampleEvent($data));
تست و نگهداری در معماری ماژولار
معماری مدولار تست و نگهداری را ساده می کند. هر ماژول را می توان به طور مستقل آزمایش کرد و شناسایی و رفع مشکلات را آسان تر می کند. بهعلاوه، بهروزرسانیها و پیشرفتها را میتوان بدون تأثیر بر کل برنامه پیادهسازی کرد.
ایجاد یک پروژه ماژولار در لاراول
هنگام ایجاد یک پروژه لاراول، متوجه خواهید شد که لاراول به طور پیش فرض پوشه ها را بر اساس آرک تایپ گروه بندی می کند. بدیهی است که خوب کار می کند، اما برای پروژه های بزرگتر با فایل هایی که توسط یک ماژول از همه جا به هم متصل شده اند کمی گم می شوید.
ساختار مورد نظر من به این صورت است:
app/Modules/{Module}/
├── {Module}.php (model)
├── {Module}Controller.php
├── {Module}Policy.php
├── {Module}Request.php
├── {Module}Routes.php
├── ...
└── Tests/
├── {Module}Factory.php
├── {Module}FeatureTest.php
├── {Module}Seeder.php
└── {Module}UnitTest.php
برای مورد استفاده من، seeder ها فقط در تست ها قابل استفاده هستند.
ما در این مقاله قصد ندارم متدهای Controller را پیاده سازی کنم، تمرکز این پست تغییر ساختار پوشه پیش فرض برای یک API است.
نصب لاراول
با ایجاد یک پروژه جدید شروع کنید:
composer create-project laravel/laravel laravel-modular
ما از SQLite برای این کار استفاده خواهیم کرد. که در لاراول 11 به صورت پیش فرض ایجاد می شود اگر نبود آن را ایجاد کنید:
touch database/database.sqlite
سپس env.
خود را ویرایش کنیم (اگر به طور خودکار از env.example.
کپی کنید)، این vars را به روز کنید:
DB_CONNECTION=sqlite
DB_HOST=database/database.sqlite
حالا بیایید یک namespace برای پوشه ماژول های خود ایجاد کنیم، composer.json
خود را ویرایش کنید:
"autoload": {
"psr-4": {
"App\\": "app/",
+ "Modules\\": "app/Modules/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
همچنین در صورت تمایل میتوانید آن را خارج از پوشه برنامه قرار دهید، فقط کارهایی را که در اینجا انجام میدهیم بهروزرسانی کنید.
هر زمان که موارد autoload
کامپوزر را به روز می کنید، این دستور را اجرا کنید:
composer dump-autoload
اکنون می توانید برنامه خود را با دستور زیر اجرا کنید:
php artisan serve
ایجاد ماژول ما
اجازه دهید یک ماژول Car ایجاد کنیم:
mkdir -p app/Modules/Car/Tests
php artisan make:model --all Car
فایل ها در ساختار پیش فرض در دایرکتوری Laravel ایجاد می شوند، هر فایل را به پوشه ای که ایجاد کردیم منتقل کنید:
mv -t app/Modules/Car app/Models/Car.php app/Http/Controllers/CarController.php
app/Http/Requests/StoreCarRequest.php app/Policies/CarPolicy.php
mv -t app/Modules/Car/Tests database/factories/CarFactory.php database/seeders/CarSeeder.php
برای این آموزش، مایگرشن را در مسیر پیشفرض میگذارم، ترجیح میدهم همه مایگرشن ها را به ترتیب زمانی باشد، اما در صورت تمایل میتوانید به پوشه ماژول نیز بروید.
ما همچنین فقط به یک FormRequest
برای ذخیره و به روز رسانی نیاز داریم:
rm app/Http/Requests/UpdateCarRequest.php
mv app/Modules/Car/StoreCarRequest.php app/Modules/Car/CarRequest.php
# also update class name
پس از آن، ما باید هر namespace ی را در پوشه جدید خود بهروزرسانی کنیم، همه فایلهای موجود در app/Modules/Car
را بهروزرسانی کنیم:
namespace Modules\Car;
و همه فایلهای موجود در "app/Modules/Car/Tests
" به:
namespace Modules\Car\Tests;
شما باید این کار را برای هر ماژول جدید انجام دهید. و اگر فایلها را در زیر پوشهها قرار میدهید، باید آنها را نیز تغییر دهید. همچنین هر گونه خطای وارد کردن را که ممکن است داشته باشید برطرف کنید، ماژول اول همیشه بیشترین زمان را می گیرد.
composer dump-autoload
را اجرا کنید تا ببینید آیا فایلی از PSR-4
خاموش است یا خیر.
راه اندازی مسیرها
بیایید یک مسیر مدولار ایجاد کنیم:
touch app/Modules/Car/CarRoutes.php
و فایل را آپدیت کنید:
<?php
use Illuminate\Support\Facades\Route;
use Modules\Car\CarController;
Route::resource('cars', CarController::class);
برای اینکه کار کند ما به یک ServiceProvider
نیاز داریم، یکی ایجاد کنید:
php artisan make:provider ModuleServiceProvider
و یک متد بوت برای جستجوی مسیرها در ماژولهای ما اضافه کنید (در صورت تمایل میتوانید همین کار را برای مایگرشن ها انجام دهید):
public function boot(): void
{
// Can also use (**) wildcard if you have subfolders
foreach (glob(base_path('app/Modules/*')) ?: [] as $dir) {
$modelClassName = class_basename($dir);
$path = Str::before($dir, "\\$modelClassName");
$moduleRouteFile = "$path/$modelClassName" . 'Routes.php';
if (!file_exists($moduleRouteFile)) continue;
$this->loadRoutesFrom($moduleRouteFile);
}
}
و آن را به config/app.php
در زیر Provider
اضافه کنید:
App\Providers\ModuleServiceProvider::class
اکنون می توانید مسیر خود را آزمایش کنید! باید کار کند. دقت کنید حتما اصول سالید و کد نویسی تمیز را نیز رعایت کنید، برای آشنایی بیشتر مقاله اصول سالید در لاراول را بررسی کنید.
Seeder و Factory ها را راه اندازی کنید
به روز رسانی مایگرشن:
Schema::create('cars', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
سیدر را به روز کنید:
public function run(): void
{
Car::factory()
->count(10)
->create();
}
آن را در پایگاه داده /seeders/DatabaseSeeder.php
ثبت کنید:
public function run(): void
{
// Note the leading slash
$this->call([
\Modules\Car\Tests\CarSeeder::class
]);
}
و Factory:
protected $model = Car::class;
public function definition(): array
{
return [
'name' => fake()->name()
];
}
از protected $model
استفاده کنید، چون ما از یک ساختار فایل سفارشی استفاده می کنیم، باید آن را اعلام کنیم. ما همچنین باید یک متد register
را به سرویس پروایدر های خود اضافه کنیم:
public function register(): void
{
Factory::guessFactoryNamesUsing(function (string $modelName) {
$modelClassName = class_basename($modelName);
$namespace = Str::before($modelName, "\\$modelClassName");
return "$namespace\\$modelClassName\\Tests\\$modelClassName" . 'Factory';
});
اکنون می توانید migration و seeder را اجرا کنید:
php artisan migrate:fresh --seed
تست کردن
قسمت آخر، بیایید چند تست اضافه کنیم، اجرا کنید:
php artisan make:test CarFeatureTest
mv tests/Feature/CarFeatureTest.php app/Modules/Car/Tests/CarFeatureTest.php
فراموش نکنید که namespace ها را به روز کنید!
یک تابع به فایل تست اضافه کنید:
/** @test */
public function get_cars_should_return_success(): void
{
$response = $this->get('/cars');
$response->assertStatus(200);
}
به /** @test */
توجه کنید، اگر این نظر را اضافه نکنید، PHPUnit تست را پیدا نمی کند. اگر میخواهید با PEST تست نویسی را انجام دهید این مقاله را بررسی کنید.
اکنون باید phpunit.xml
را به روز کنیم تا تست های خود را کشف کنیم:
<testsuites>
<testsuite name="Unit">
- <directory suffix="Test.php">./tests/Unit</directory>
+ <directory suffix="UnitTest.php">./app/Modules</directory>
</testsuite>
<testsuite name="Feature">
- <directory suffix="Test.php">./tests/Feature</directory>
+ <directory suffix="FeatureTest.php">./app/Modules</directory>
</testsuite>
</testsuites>
شما باید از پسوند UnitTest.php
یا FeatureTest.php
استفاده کنید یا phpunit.xml
را برای مورد استفاده خود تغییر دهید.
اکنون می توانید تست کنید:
php artisan test
با توسعه تست محور در لاراول چقدر آشنا هستید؟ مقاله توسعه تست محور در لاراول را بررسی کنید.
معایب معماری ماژولار در لاراول
معماری ماژولار در لاراول به تمرین تجزیه یک برنامه لاراول به ماژول های کوچکتر و مستقل اشاره دارد که می توانند به طور مستقل توسعه، آزمایش و نگهداری شوند. در حالی که معماری ماژولار می تواند چندین مزیت مانند سازماندهی کد بهبود یافته و قابلیت استفاده مجدد را ارائه دهد، برخی از معایب بالقوه نیز وجود دارد که باید در نظر گرفته شوند:
پیچیدگی: معرفی ماژول ها می تواند پیچیدگی برنامه شما را افزایش دهد، به خصوص اگر به درستی مدیریت نشود. هر ماژول ممکن است وابستگیها، فایلهای پیکربندی و مسیرهای خاص خود را داشته باشد، که میتواند سیستم کلی را پیچیدهتر و درک آن را سختتر کند، بهویژه برای تازه واردان به پروژه.
منحنی یادگیری: توسعه دهندگانی که در پروژه شما جدید هستند ممکن است نیاز داشته باشند نه تنها مفاهیم اصلی لاراول بلکه ساختار مدولار خاص شما را نیز درک کنند. این به طور بالقوه می تواند منحنی یادگیری را برای اعضای جدید تیم افزایش دهد و ممکن است به اسناد اضافی و تلاش های داخلی نیاز داشته باشد.
سربار: معماری ماژولار می تواند مقداری سربار را از نظر راه اندازی و نگهداری خود سیستم ماژول معرفی کند. ممکن است لازم باشد مکانیسمهایی برای ثبت ماژول، مدیریت وابستگی و مدیریت ارتباطات بین ماژولها پیادهسازی کنید.
استقرار و نسخه سازی: مدیریت استقرار یک برنامه ماژولار لاراول می تواند پیچیده تر باشد. اطمینان از به روز رسانی و سازگاری همه ماژول ها با یکدیگر می تواند چالش برانگیز باشد، به ویژه با رشد و تکامل برنامه.
عملکرد: بسته به نحوه پیادهسازی ماژولها، ممکن است به دلیل بارگذاری و مسیریابی پویا ماژولها، یک سربار عملکرد جزئی وجود داشته باشد. با این حال، این سربار معمولاً ناچیز است و میتوان آن را از طریق کش کردن مناسب و استراتژیهای بهینهسازی کاهش داد.
مدیریت وابستگی: مدیریت وابستگی ها بین ماژول ها می تواند مشکل باشد. اگر ماژولهای مختلف وابستگیهای متناقضی داشته باشند یا به نسخههای متفاوتی از یک بسته نیاز داشته باشند، میتواند منجر به مشکلات سازگاری شود که باید حل شوند.
تست و کنترل کیفیت: در حالی که ماژول ها را می توان به صورت جداگانه آزمایش کرد، اطمینان از اینکه آنها به طور یکپارچه با هم کار می کنند ممکن است به آزمایش یکپارچه سازی گسترده نیاز داشته باشد. این ممکن است وقت گیر باشد و همچنین ممکن است مشکلات پنهانی را که فقط در هنگام تعامل ماژول ها به وجود می آیند را آشکار کند.
قابلیت نگهداری: در حالی که هدف معماری ماژولار بهبود قابلیت نگهداری است، توجه به این نکته مهم است که نگهداری چندین ماژول اگر به درستی سازماندهی و مستند نشده باشد، می تواند چالش برانگیز باشد. پیگیری روابط و وابستگی های ماژول برای نگهداری طولانی مدت بسیار مهم است.
انجمن و مستندات: در حالی که لاراول خود دارای یک جامعه قوی و فعال است، اکوسیستم برنامه های ماژولار لاراول ممکن است به خوبی تثبیت نشده باشد. یافتن راهحلهایی برای مسائل خاص مربوط به راهاندازی مدولار ممکن است به دلیل منابع و اسناد کمتر موجود، چالشبرانگیزتر باشد.
در نتیجه، در حالی که معماری مدولار می تواند چندین مزیت را ارائه دهد، مهم است که با دقت این موارد را در مقابل معایب احتمالی پروژه خاص خود بسنجید. برنامه ریزی، سازماندهی و مستندسازی مناسب کلید اجرای موفقیت آمیز یک برنامه ماژولار لاراول و کاهش بسیاری از این اشکالات است.
در حالی که استفاده از رویکرد ماژولار با لاراول می تواند به سازماندهی و ساختار پروژه های بزرگ کمک کند، ممکن است معایبی نیز به همراه داشته باشد. یکی از معایب احتمالی این است که می تواند پیچیدگی پروژه را افزایش دهد، زیرا توسعه دهندگان باید با ساختار ماژولار و نحوه تعامل ماژول های مختلف با یکدیگر آشنا باشند.
علاوه بر این، استفاده از یک رویکرد ماژولار ممکن است به تنظیمات و پیکربندی اضافی نیاز داشته باشد، که می تواند زمان و تلاش مورد نیاز برای شروع یک پروژه را افزایش دهد.
با این حال، این معایب ممکن است با مزایای استفاده از یک رویکرد مدولار، مانند بهبود قابلیت نگهداری و استفاده مجدد از کد، جبران شود. هنگام تصمیم گیری در مورد استفاده از رویکرد ماژولار در پروژه لاراول، مهم است که به دقت معاوضه ها را در نظر بگیرید.
نتیجه
پیاده سازی معماری ماژولار در لاراول یک رویکرد ساختاریافته و مقیاس پذیر برای توسعه برنامه ارائه می دهد. با درک و به کارگیری این اصول، توسعه دهندگان می توانند برنامه های لاراول قابل نگهداری، توسعه پذیرتر و سازماندهی شده تری ایجاد کنند. همانطور که می بینید، لاراول بسیار قدرتمند است و می تواند ساختارهای سفارشی بسیار خوبی را با IMO کمی دیگ بخار اداره کند. متأسفانه دستورات *:php artisan make
به درستی در ماژول ها کار نمی کنند، اما می توانید دستورات جدیدی اضافه کنید تا آن را برای شما کار کند.