یکی از مزایای ماژولار بودن یک فریمورک آن است که به سادگی قادر خواهیم بود تا فیچرهایی که مرتبط با یکدیگر هستند را در قالب یک ماژول یا کامپوننت تعریف کرده به طوری که مستقل از سایر ماژولها خواهند بود و این در حالی است میتوانیم ماژول مربوطه را کپی کرده و در سایر پروژهها مورد استفاده قرار داد.
همانطور که در طی این دورهٔ آموزشی دیدیم، فریمورکی که بر پایهٔ معماری سهلایهٔ MVC توسعه دادیم دارای یک ماژول اصلی به نام Base
بود. حال در این آموزش قصد داریم ببینیم که به چه شکل میتوان ماژولی جدید و مستقل از ماژول اصلی این فریمورک ساخت.
برای این منظور، داخل فولدر app
فولدر جدیدی با نامی دلخواه همچون Api
میسازیم که میتواند برای توسعهٔ یک وب سرویس مورد استفاده قرار گیرد (جهت آشنایی بیشتر با این اصطلاح، میتوانید به آموزش API چیست؟ مراجعه نمایید.) از این پس، ساختار فولدر app
به صورت زیر خواهد بود:
app
├── Api
├── Base
└── Core
با توجه به اینکه در توسعهٔ وب سرویس کلیهٔ تبادل اطلاعات از طریق پروتکل HTTP صورت میگیرد، مسلماً نیازی به لایهٔ ویو نخواهم داشت و از همین روی داخل فولدر Api
اقدام به ساخت دو پوشه به منظور نگهداری کنترلرها و مدلها میکنیم:
app
├── Api
│ ├── Controllers
│ └── Models
├── Base
└── Core
در ادامه و صرفاً جهت تست، یک کنترلر پیشفرض داخل پوشهٔ Controllers
ساخته و آن را مورد بررسی قرار میدهیم. برای این منظور، کنترلری با نامی دلخواه همچون ApiController
به صورت زیر میسازیم:
<?php
namespace Api\Controllers;
use Core\BaseController;
class ApiController extends BaseController
{
public function articles()
{
echo "ApiController articles action";
}
}
همانطور که ملاحظه میشود، ابتدا به ساکن و طبق روال گذشته نِیماِسپیس این فایل را تعریف کردهایم به طوری که پس از نوشتن کیورد namespace
ابتدا نام پوشهای که داخل آن قرار داریم یا به عبارتی Api
را نوشته سپس نام پوشهٔ زیرشاخه یا همان Controllers
را آوردهایم.
ثبت نِیماِسپیس جدید از طریق کامپوزر
نکتهای که در اینجا حائز اهمیت است اینکه کِرنِل فریمورک در این مرحله از کار هرگز چنین نِیماِسپیس را نخواهد شناخت چرا که همچون دو نِیماِسپیس گذشته آن را در فایل composer.json
ثبت نکردهایم. برای این منظور، فایل composer.json
را باز کرده و آن را به صورت زیر تکمیل میکنیم:
{
"autoload": {
"psr-4": {
"Core\\": "app/Core",
"Base\\": "app/Base",
"Api\\": "app/Api"
}
}
}
همچون دو کامپوننت گذشته، نامی همچون Api
برای نِیماِسپیس جدید در نظر گرفته و مسیر آن را برابر با پوشهٔ app/Api
قرار دادهایم.
هشدار |
همواره به خاطر داشته باشیم که در این فایل پس از درج آخرین نِیماِسپیس هرگز نباید علامت , گذاشت که در این صورت کامپوزر قابلیت اجرا نخواهد داشت. |
کماکان به این نِیماِسپیس دسترسی نخواهیم داشت چرا که کامند dump-autoload
را اجرا نکردهایم که برای این منظور دستور را زیرا در مسیر mvc
اجرا میکنیم:
/var/www/mvc$ composer dump-autoload -o
Generated optimized autoload files containing 9 classes
اکنون چنانچه به فایل autoload_classmap.php
رجوع کنیم، خواهیم داشت:
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Api\\Controllers\\ApiController' => $baseDir . '/app/Api/Controllers/ApiController.php',
'Base\\Config\\Database' => $baseDir . '/app/Base/Config/Database.php',
'Base\\Controllers\\DefaultController' => $baseDir . '/app/Base/Controllers/DefaultController.php',
'Base\\Models\\User' => $baseDir . '/app/Base/Models/User.php',
'Core\\App' => $baseDir . '/app/Core/App.php',
'Core\\BaseController' => $baseDir . '/app/Core/BaseController.php',
'Core\\Interfaces\\ControllerInterface' => $baseDir . '/app/Core/Interfaces/ControllerInterface.php',
'Core\\Interfaces\\UserInterface' => $baseDir . '/app/Core/Interfaces/UserInterface.php',
'Core\\Routing' => $baseDir . '/app/Core/Routing.php',
);
میبینیم که بر اساس حروف الفبا و درخط اول آرایهٔ فوق نِیماِسپیس مرتبط با ماژول جدید Api
افزوده شده است به طوری که از این پس به سادگی قادر خواهیم بود از کلاسهای تعریفشده داخل این ماژول در سایر بخشها استفاده کرده و کامپوزر هم به صورت خودکار آنها را ایمپورت خواهد کرد.
در تفسیر کدهای فایل ApiController.php
میتوان گفت که پس از تعریف نِیماِسپیس، اقدام به use
کردن BaseController
کردهایم چرا که قرار است تا ApiController
از آن ارثبری کند که برای این منظور و در حین ایجاد این کلاس، پس از درج نام کلاس کلیدواژهٔ extends
را نوشته سپس کلاسی را آوردهایم که قصد داریم خصوصیات آن را در این کنترلر به ارث ببریم.
این کنترلر صرفاً حاوی یک متد یا اَکشن به نام ()articles
است که به نوعی میتواند به منظور دریافت ریکوئستهایی مرتبط با نمایش لیست مقالات مورد استفاده قرار گیرد. داخل بدنهٔ این متد صرفاً یک متن ساده را چاپ کردهایم که چنانچه یوآرال مربوطه با این کنترلر و اَکشن مپ شود، این متن نمایش داده خواهد شد.
در تکمیل این ماژول، برای آنکه بتوانیم به این کنترلر و اَکشن دست پیدا کنیم، میباید فایل Routing.php
را به صورت زیر بهروزرسانی کنیم:
<?php
namespace Core;
class Routing
{
public $routes = [
[
'route' => '',
'module' => 'Base',
'controller' => 'DefaultController',
'action' => 'homepage',
],
[
'route' => 'default/homepage',
'module' => 'Base',
'controller' => 'DefaultController',
'action' => 'homepage',
],
[
'route' => 'default/about',
'module' => 'Base',
'controller' => 'DefaultController',
'action' => 'about',
],
[
'route' => 'default/users',
'module' => 'Base',
'controller' => 'DefaultController',
'action' => 'users',
],
[
'route' => 'api/articles',
'module' => 'Api',
'controller' => 'ApiController',
'action' => 'articles',
],
];
public function __construct()
{
return $this->routes;
}
}
همانطور که ملاحظه میشود، در پراپرتی routes$
اِلِمان جدیدی حاوی یکسری Key/Value به صورت زیر تعریف کردهایم:
- کلید
route
با مقدارapi/articles
که به منزلهٔ لینکی است که میتوانیم با مراجعه به آن به این ماژول جدید دست پیدا کنیم. - کلید
module
که دربرگیرندهٔ نام ماژول جدید تحت عنوانApi
است. - کلید
controller
که حاوی مقدارApiController
است. - کلید
action
که در آن نام تنها متد موجود در این کنترلر تحت عنوانarticles
را نوشتهایم.
به منظور تست صحت کارکرد این ماژول جدید، لینک http://mvc.local/api/articles
را در مرورگر وارد میکنیم و به طوری که خواهیم دید استرینگی که در بندهٔ تابع ()articles
در نظر گرفته بودیم چاپ شده است:
ApiController articles action
همچنین اگر لینکی همچون http://mvc.local/api/test
را در نظر بگیریم، با خروجی زیر مواجه خواهیم شد:
404
The page you`re looking for is not found
میبینیم که سیستم روتینگ به درستی کار کرده و از آنجا که چنین اَکشنی داخل کنترلر این ماژول تعریف نشده است، با صفحهٔ 404 مواجه خواهیم شد. به همین منوال، بسته به نیاز/نیازهای خود میتوانیم کنترلرها و مدلهای مختلفی به این ماژول اضافه نموده و آنها را مورد استفاده قرار داد.