کامپوننت ها

کامپوننت‌ها واحدهای اصلی عملکردی جوملا هستند و می‌توان آن‌ها را به‌عنوان برنامه‌های کوچک (mini-applications) در نظر گرفت. محتوایی که معمولاً در مرکز صفحه وب نمایش داده می‌شود، توسط یک کامپوننت ایجاد شده است.

بیشتر کامپوننت‌ها دو بخش اصلی دارند: بخش مدیریت و بخش سایت. بخش سایت برای نمایش صفحات سایت در زمان درخواست بازدیدکنندگان در طول عملکرد عادی سایت استفاده می‌شود. بخش مدیریت رابطی را برای پیکربندی و مدیریت جنبه‌های مختلف کامپوننت فراهم می‌کند و از طریق برنامه مدیریت جوملا قابل دسترس است.

جوملا دارای چندین کامپوننت اصلی است، برای مثال، com_content برای مقالات، com_contact برای مخاطبین و com_menus برای تنظیم منوها و آیتم‌های منوی سایت.

الگوی مدل-نما-کنترل‌گر (MVC) در جوملا

این بخش الگوی MVC را به عنوان پیاده‌سازی شده در کامپوننت‌های جوملا توضیح می‌دهد. اگرچه هنگام توسعه کامپوننت خودتان نیازی نیست الزماً این الگو را رعایت کنید، اما قویاً توصیه می‌شود که این کار را انجام دهید، زیرا در بلندمدت کارها را برای شما بسیار آسان‌تر خواهد کرد.

مرور کلی MVC

نمودار زیر الگوی MVC را نشان می‌دهد که در جوملا به کار می‌رود. این الگو هم برای بخش مدیریت (backend) و هم برای بخش سایت (frontend) صدق می‌کند.

MVC Overview

عناصر اصلی

در این بخش چهار نوع کلاس نشان داده شده در نمودار را بررسی می‌کنیم. احتمالاً در کامپوننت خود چندین کلاس Controller، View و Model دارید و اگر کامپوننت شما از جداول مخصوص خودش در پایگاه داده استفاده می‌کند، برای هر جدول یک کلاس Table خواهید داشت.

Controller (کنترل‌گر)

کد کنترل‌گر هر بار که یک درخواست HTTP به کامپوننت شما ارسال می‌شود اجرا می‌شود. کنترل‌گر مسئول تحلیل درخواست کاربر، بررسی مجوز انجام آن عمل و تعیین نحوه پاسخگویی به درخواست است. این کار می‌تواند شامل مواردی باشد:

- تعیین اینکه کدام مدل (یا مدل‌ها) برای پاسخگویی به درخواست لازم است و ایجاد نمونه‌ای از آن مدل

- فراخوانی متدهای مدل جهت انجام به‌روزرسانی‌های لازم در پایگاه داده

- تعیین اینکه کدام نما (View) برای نمایش به کاربر باید استفاده شود و ایجاد نمونه‌ای از آن

- یا در صورت نیاز، هدایت کاربر به آدرس دیگری (redirect)

View (نما)

قابلیت‌های نما به دو فایل تقسیم شده است:

- یک کلاس View که معمولاً فقط به عنوان View شناخته می‌شود.

- یک فایل tmpl که قالب یا لایه نمایشی است.

View مشخص می‌کند چه چیزی باید در صفحه وب نمایش داده شود و تمام داده‌های لازم برای پاسخ HTTP را جمع‌آوری می‌کند.

بعد از اینکه کنترل‌گر نمونه View را ایجاد کرد، متد setModel() روی View فراخوانی شده و نمونه مدل به آن داده می‌شود. بدین ترتیب، View می‌داند کدام مدل را استفاده کند و با فراخوانی متدهای مدل، داده‌های لازم را دریافت می‌کند. این داده‌ها در متغیرهای نمونه View ذخیره می‌شوند.

فایل tmpl (گاهی به آن template یا layout هم گفته می‌شود) مسئول تولید کد HTML واقعی صفحه است. خود View کد HTML را تولید نمی‌کند بلکه این کار به tmpl سپرده شده است.

کد PHP داخل فایل tmpl در زمینه View اجرا می‌شود. کلاس View معمولاً از Joomla\CMS\MVC\View\HtmlView مشتق می‌شود و متد display() این کلاس فایل tmpl مناسب را تعیین و بارگذاری می‌کند.

 

برای مثال اگر داده‌های پاسخ در متغیری مثل $this->items در View باشند، فایل tmpl می‌تواند به همان $this->items دسترسی داشته و آن‌ها را هنگام تولید HTML به کار ببرد.

جداسازی View و tmpl این امکان را می‌دهد که به راحتی لایه نمایشی را بازنویسی (override) کنید و داده‌های View را با HTML دلخواه خود نمایش دهید.

Model (مدل)

مدل داده‌های مورد استفاده کامپوننت را در بر می‌گیرد. معمولاً این داده‌ها از پایگاه داده جوملا یا یک پایگاه داده خارجی دریافت می‌شود، اما ممکن است مدل داده‌ها را از منابع دیگری مانند APIهای سرویس‌های وب هم بگیرد. مدل همچنین مسئول به‌روزرسانی پایگاه داده است. وظیفه مدل این است که جزئیات نحوه دریافت یا ویرایش داده‌ها را از کنترل‌گر و نما جدا کند.

اگر کامپوننت فرم‌هایی داشته باشد که با XML و روش فرم جوملا تعریف شده‌اند، مدل کار راه‌اندازی و پیکربندی نمونه فرم را انجام می‌دهد تا tmpl بتواند فیلدها را با متدهایی مثل $form->renderField() نمایش دهد.

Table (جدول)

اگر افزونه شما یک یا چند جدول پایگاه داده دارد، باید برای هر جدول یک کلاس Table تعریف کنید. این کلاس از کلاس Table کتابخانه جوملا ارث‌بری می‌کند و عملیات CRUD (ایجاد، خواندن، به‌روزرسانی، حذف) را روی جدول مربوطه فراهم می‌کند.

کلاس Table فقط برای دسترسی به رکوردهای منفرد استفاده می‌شود؛ بنابراین مدل در عملیات CRUD روی یک رکورد مشخص، از کلاس Table استفاده می‌کند.

اگر بخواهید چندین رکورد در جدول را پردازش کنید، مدل مستقیماً به پایگاه داده دسترسی خواهد داشت و از کلاس Table استفاده نمی‌کند.

پارامتر task در درخواست HTTP

جوملا از پارامتر task در درخواست HTTP برای تعیین کنترل‌گری که باید استفاده شود، بهره می‌برد. پارامتر task می‌تواند هم در درخواست GET و هم در POST ارسال شود و جوملا تفاوتی برای آن قائل نیست؛ این پارامتر صرفاً یک پارامتر عادی HTTP است و چیز خاصی نیست.

ساختار پارامتر task به شکل `<controllerType>.<method>` است. قسمت اول (controllerType) نوع کنترل‌گر مشخص شده را تعیین می‌کند و قسمت دوم (method) نام متدی است که از نمونه این کلاس فراخوانی می‌شود.

ممکن است نوع کنترل‌گر در این پارامتر حذف شده باشد، که در این صورت کلاس DisplayController استفاده می‌شود.

 

اگر پارامتر task اصلاً تنظیم نشده باشد، متد `display()` در کلاس DisplayController اجرا می‌شود.

اجرای MVC در درون جوملا

کد MVC مربوط به کامپوننت شما در بستر کتابخانه جوملا اجرا می‌شود، مثل گوشت درون یک ساندویچ. وقتی جوملا تصمیم می‌گیرد کامپوننت شما را اجرا کند، ابتدا کلاس‌های Extension و Dispatcher مربوط به کامپوننت شما را بارگذاری می‌کند. سپس تابع `dispatch()` در کلاس `Joomla ComponentDispatcher` پارامتر task را تحلیل می‌کند تا مشخص شود کدام یک از کلاس‌های Controller شما باید نمونه‌سازی شود (این موضوع در بخش Extension and Dispatcher classes توضیح داده شده است).

سپس `dispatch()` متد `execute()` کامپوننت شما را با پارامتر `<method>` از task فراخوانی می‌کند. در صورتی که کامپوننت شما از کلاس پایه `Joomla\CMS\MVC\Controller\BaseController` ارث‌بری کرده باشد، در حالت معمول باعث فراخوانی متد مربوط به کنترل‌گر شما خواهد شد.

بعد از اجرای `execute()`، متد `dispatch()` متد `redirect()` کنترل‌گر را فراخوانی می‌کند — اهمیت این موضوع بعداً بررسی خواهد شد.

در سمت خروجی، کد HTML تولید شده توسط فایل tmpl مستقیماً در پاسخ HTTP قرار نمی‌گیرد. بلکه جوملا با استفاده از تکنیک PHP Output Buffering این خروجی را در یک بافر ذخیره می‌کند و بعداً همراه با ماژول‌ها، پیام‌ها و سایر المان‌های مورد نیاز به صفحه HTML نهایی تزریق می‌کند.

مرور کلی MVC Factory

کلاس MVC Factory در جوملا برای ایجاد نمونه (instance) از کلاس‌های Controller، View، Model و Table در کامپوننت‌ها استفاده می‌شود.

هر کامپوننت یک نمونه اختصاصی از این کلاس MVCFactory دارد که با دریافت پیشوند namespace مربوط به آن کامپوننت ساخته می‌شود.

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

`createController`، `createView`، `createModel`، `createTable` و در ساده‌ترین حالت شما می‌توانید به هر کدام از این متدها: 

- نام کلاس (مثلاً "display"، "article" و ...) 

- پیشوند ("site" یا "administrator") 

را ارسال کنید. 

(می‌توانید نام و پیشوند را با حرف اول کوچک یا بزرگ وارد کنید، جوملا حرف اول را به صورت خودکار بزرگ می‌کند).

کلاس MVCFactory بر اساس نام و پیشوند دریافتی، نام کامل کلاس را تولید کرده و تلاش می‌کند آن را نمونه‌سازی کند.

مثلاً اگر کامپوننت شما com_example با namespace پیشوندی \Mycompany\Component\Example باشد، در کلاس Controller شما می‌توانید اینطور بنویسید (فرض کنیم $this->factory به نمونه MVCFactory شما اشاره دارد):

 
$model = $this->factory->createModel('Example', 'Administrator');

در این حالت، تابع MVCFactory سعی می‌کند نمونه‌ای از کلاس زیر را ایجاد نماید.

\Mycompany\Component\Example\Administrator\Model\ExampleModel

کتابخانه پایه MVC BaseController کار را ساده‌تر کرده و شما فقط کافی است این خط را فراخوانی کنید:

 
$model = $this->getModel('example', 'administrator');

نکته مهم: اگر کامپوننت شما در محیط فرانت‌اند (site) اجرا می‌شود، می‌توانید همچنان از مدل administrator استفاده کنید و بالعکس در بک‌اند (administrator) هم می‌توانید از مدل site استفاده کنید؛ هیچ محدودیتی وجود ندارد.

ایجاد نمونه MVCFactory

نمونه کلاس MVCFactory کامپوننت شما با تعریف آن به عنوان یک وابستگی (dependency) در فایل `services/provider.php` ساخته می‌شود (مطابق توضیحات بخش Dependency Injection). ولی برای استفاده مؤثر نیازی نیست همه جزئیات پیچیده تزریق وابستگی جوملا را بدانید.

ایجاد نمونه Controller

همانطور که در بخش کلاس های Extension وDispatcher گفته شد، نمونه کلاس Controller در داخل متد `dispatch` در کلاس ComponentDispatcher ساخته می‌شود. این کلاس یک متغیر نمونه به MVCFactory دارد و متد زیر را فراخوانی می‌کند:

 
$controller = $this->mvcFactory->createController($name, $client, ...);

که در آن `$name` بخشی از پارامتر task اول (یا "display" اگر پارامتر task وجود نداشته باشد) و `$client` مقدار "site" یا "administrator" است که بسته به اجرای کامپوننت در فرانت‌اند یا بک‌اند تعیین می‌شود.

Instantiating the Controller

نمودارهای مرتبط

- کلاس‌های Factory با رنگ آبی نشان داده شده‌اند و کلاس‌های معمولی MVC به رنگ زرد هستند. 

- خطوط نقطه‌چین آبی نشان می‌دهد یک کلاس دارای متغیر نمونه‌ای است که به نمونه کلاس دیگری اشاره دارد. 

- خطوط سیاه توپر نشان‌دهنده فراخوانی متدها هستند. 

- خطوط ضخیم قرمز پر رنگ نشان‌دهنده محل نمونه‌سازی کلاس توسط یک کلاس Factory است.

ایجاد نمونه‌های View، Model و Table با الگوی MVC Factory در جوملا

Instantiating View, Model, Table

 

نقش هر لایه در نمونه‌سازی کلاس‌ها

- Controller مسئول ایجاد نمونه‌های View و Model است و معمولاً با استفاده از متدهای `getView()` و `getModel()` این کار را انجام می‌دهد.

- Model مسئول ایجاد نمونه Table است و متد `getTable()` برای ساخت آن به کار می‌رود.

- همچنین، View می‌تواند مدل را دریافت کند، ولی فقط در صورتی که کنترل‌گر قبلاً آن مدل را ساخته و با متد `setModel()` به View داده باشد:

 
  $view->setModel($model);

نامهای پیشفرض کلاسهای View، Model و Table

- نام کنترل‌گر از پارامتر task درخواست HTTP گرفته می‌شود.

- نام پیش‌فرض کلاس‌های View، Model و Table از پارامتر view درخواست HTTP گرفته می‌شود.

اگر بدون پارامتر اضافی `getView()`، `getModel()` و `getTable()` را فراخوانی کنید، این کلاس‌های پیش‌فرض ساخته می‌شوند.

مثال: برای درخواست URL با `?option=com_example&view=viewname` و بدون پارامتر task:

کلاس

نام کلاس ساخته شده

Controller

<namespace>\Controller\DisplayController

View

<namespace>\View\Viewname\HtmlView

Model

<namespace>\Model\ViewnameModel

Table

<namespace>\Table\ViewnameTable

 

نمونه کد و نحوه استفاده در Controller

 
// دریافت مدل پیش‌فرض بر اساس پارامتر view
$model = $this->getModel();
// دریافت مدل با نام مشخص
$foomodel = $this->getModel('foo');
// دریافت مشاهده (View) پیش‌فرض بر اساس پارامتر view
$view = $this->getView();
// دریافت View با نام مشخص
$fooview = $this->getView('foo');
// لینک دادن مدل به View
$view->setModel($model, true);   // مدل پیش‌فرض view
$view->setModel($foomodel);      // مدل اضافی قابل دسترس در view با نام 'foo'
// دریافت چند مدل در صورت نیاز
$foomodel = $this->getModel('foo');
$barmodel = $this->getModel('bar');
// دریافت مدل Administrator در صورتی که کامپوننت در فرانت‌اند اجرا می‌شود
$model = $this->getModel('foo', 'administrator');

استفاده از مدل در View

 
// مدل پیش‌فرض
$model = $this->getModel();
// مدل با نام 'foo'
$foomodel = $this->getModel('foo');

 

ایجاد نمونه Table در مدل

 
// دریافت جدول پیش‌فرض با نام مطابق view= پارامتر درخواست
$table = $this->getTable();
// دریافت جدول خاص، مثلاً ExampleTable
$table = $this->getTable('example');
 

 نکته‌ها و مشکلات

- یکی از دلایل ایجاد کلاس MVCFactory حذف فراخوانی‌های قدیمی `static::getInstance()` در نمونه‌سازی کلاس‌ها بود.

- به هر حال ممکن است در برخی موارد با مشکلاتی مواجه شوید، به مثال زیر توجه کنید:

    هنگام ذخیره یک رکورد در کلاس Table (مثلاً در `Joomla\CMS\Table\Content::store()`) جوملا یک نمونه جدید برای بررسی یکتا بودن alias ایجاد می‌کند. ولی این نمونه جدید MVCFactory را دریافت نمی‌کند تا بتواند به‌درستی `createTable()` را فراخوانی کند.

- راه‌حل در جوملا 4 استفاده از متد منسوخ‌شده زیر بود:

$table = new self($this->getDbo(), $this->getDispatcher());
 
$table = Table::getInstance('Content', 'JTable', ['dbo' => $this->getDbo()]);

 - در جوملا 5 آن را به شکل زیر جایگزین کردند:

  

- بنابراین شما هم می‌توانید همین روش را استفاده کنید یا مستقیماً کوئری SQL روی جدول پایگاه داده اجرا نمایید تا نیاز به استفاده از متد منسوخ `getInstance()` نباشد.

الگوی Post-Request-Get

جوملا از الگوی Post/Redirect/Get پیروی می‌کند، بدین معنا که وقتی کاربر یک فرم را با روش HTTP POST ارسال می‌کند، جوملا به‌جای پاسخ دادن به همان درخواست POST با یک صفحه HTML، کاربر را به صفحه‌ای دیگر هدایت می‌کند که مرورگر آن را با روش HTTP GET درخواست می‌کند. در این بخش چند مثال از این روند را بررسی می‌کنیم و می‌بینیم چگونه این الگو با استفاده از پارامتر task و بعدها با کلاس‌های MVC موجود در کتابخانه جوملا هماهنگ است.

اگرچه جوملا به طور گسترده‌ای از الگوی Post-Request-Get استفاده می‌کند، اما این به این معنی نیست که شما باید آن را در همه بخش‌های کامپوننت خود به کار ببرید. برای مثال، اگر کامپوننت شما یک فرم در بخش جلوی سایت دارد که برای ارسال سفارش استفاده می‌شود، ممکن است منطقی باشد که متن تأیید سفارش را مستقیماً به عنوان پاسخ HTTP به درخواست POST ارسال کنید.

مثال ۱: انتشار مقالهها (Publish Articles)

نمودار مراحل مربوط به انتشار مقاله‌ها در بخش مدیریت جوملا را نشان می‌دهد. احتمالاً برای درک بهتر روند، انجام این مراحل روی یک نسخه جوملا‌ی خودتان و بررسی درخواست‌ها و پاسخ‌های HTTP در ابزار توسعه‌دهنده (DevTools) مرورگرتان مفید خواهد بود.

Publishing Articles

مرحله ۱

مدیر سایت روی Content / Articles کلیک می‌کند تا فهرست مقاله‌ها نمایش داده شود. این یک درخواست HTTP GET ساده به صفحه com_content در بخش مدیریت با پارامتر view مساوی با articles است. (اگر از URL های SEF استفاده شود، روتر جوملا با تجزیه URL ورودی، پارامتر view را تنظیم می‌کند). پارامتر task در این درخواست تنظیم نشده است، بنابراین DisplayController از com_content ساخته شده و متد display() فراخوانی می‌شود. بر اساس پارامتر view، کلاس View پیش‌فرض برابر است با:

Joomla\Component\Content\Administrator\View\Articles\HtmlView

و مدل پیش‌فرض برابر است با:

Joomla\Component\Content\Administrator\Model\ArticlesModel

نکته مهم این است که این نمای (View) دکمه‌های مختلفی در بالای فرم نمایش می‌دهد. هنگام انتخاب یک یا چند مقاله، این دکمه‌ها در منوی کشویی Actions در بالای صفحه ظاهر می‌شوند. این دکمه‌ها باعث ارسال یک درخواست HTTP POST به سرور می‌شوند و پارامتر task در آن POST روی مقدار خاصی قرار می‌گیرد.

مرحله ۲

مدیر چند مقاله را انتخاب کرده و سپس دکمه Publish (انتشار) را می‌زند. در این مرحله مفید است که DevTools مرورگر خود را فعال کرده و پیام‌ها را بررسی کنید. خواهید دید که فشار دادن دکمه Publish باعث موارد زیر می‌شود:

- ارسال درخواست HTTP POST به سرور با پارامتر task که روی "articles.publish" تنظیم شده است 

- ارسال آرایه cid[] شامل شناسه (ID) مقالات انتخاب‌شده 

- به همراه چند پارامتر دیگر از صفحه‌بندی، فیلترها و گزینه‌های دسته‌ای که در اینجا مهم نیستند

این درخواست به کنترلر ArticlesController در بخش مدیریت com_content هدایت می‌شود و متد publish() آن فراخوانی خواهد شد.

اگر کد فایل administrator/components/com_content/src/Controller/ArticlesController.php را بررسی کنید، فانکشن publish() را در آن نمی‌بینید، پس در واقع تابع publish() در کلاس والد که است یعنی Joomla\CMS\MVC\Controller\AdminController که فضای نامی است که در فایل libraries/src/MVC/Controller/AdminController.php اجرا می‌شود. بخشی از این متد publish() به این صورت است:

 
$cid = (array) $this->input->get('cid', [], 'int');

 

در این خط، شناسه‌های انتخاب‌شده دریافت می‌شوند.

بعد:

 
$model = $this->getModel(); 
$model->publish($cid, $value);

 

تابع getModel به شکل زیر در ArticlesController تعریف شده است:

 
public function getModel($name = 'Article', $prefix = 'Administrator', $config = ['ignore_request' => true])
{
    return parent::getModel($name, $prefix, $config);
}

 

و با توجه به اینکه مقدار پیش‌فرض $name برابر 'Article' هست، مدل ArticleModel در مسیر com_content بخش مدیریت انتخاب می‌شود (و نه ArticlesModel که مدل پیش‌فرض است). اگر این فایل را بررسی کنید، متد publish() در آنجا هست که فقط خط زیر را اجرا می‌کند:

 
return parent::publish($pks, $value);

 

کار اصلی انجام عملیات انتشار (publish) در کلاسی است که ArticleModel از آن ارث می‌برد، یعنی کلاس Joomla\CMS\MVC\Model\AdminModel که در مسیر libraries/src/MVC/Model/AdminModel.php قرار دارد و متد publish آنجا پیاده‌سازی شده است.

بخش بعدی از کد AdminController.php

در ادامه کد این فایل، داریم:

 
$ntext = $this->text_prefix . '_N_ITEMS_PUBLISHED';
$this->setMessage(Text::plural($ntext, \count($cid)));
 

 در اینجا، کد در حال آماده‌سازی پیامی است که به مدیر سایت نمایش داده می‌شود و اساساً تعداد رکوردهای موفق به انتشار را تأیید می‌کند.

در پایان متد publish در AdminController.php:

 
$this->setRedirect(
    Route::_(
        'index.php?option=' . $this->option . '&view=' . $this->view_list
        . $this->getRedirectToListAppend(),
        false
    )
);

 

در اینجا الگوی Post-Request-Get به وضوح دیده می‌شود: جوملا به درخواست POST با نمایش یک صفحه وب پاسخ نداده، بلکه یک ریدایرکت (هدایت مجدد) تنظیم کرده است. در این مورد، کاربر به صفحه‌ای هدایت می‌شود که لیست مقاله‌ها را نمایش می‌دهد.

خلاصه روند:

همانطور که در بخش‌های مربوط به مرور کلی MVC و Dispatcher Component گفته شد، پس از اتمام متد execute کامپوننت، دیسپچر (Dispatcher) ، متد redirect کامپوننت را فراخوانی می‌کند. این متد (که در Joomla\CMS\MVC\Controller\BaseController قرار دارد) دو کار انجام می‌دهد:

- استفاده از تابع enqueueMessage در برنامه جوملا برای ذخیره پیام تأیید (مثلاً "n مقاله منتشر شد") در داده‌های نشست (session)

- دستور دادن به برنامه جوملا برای ریدایرکت به URL ای که در setRedirect ذخیره شده است

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

1. متد publish() در AdminController نه تنها برای انتشار مقاله‌ها است بلکه برای تنظیم وضعیت‌های دیگر مثل unpublish هم به کار می‌رود. در کلاس BaseController جوملا یک متغیر محافظت‌شده $taskmap وجود دارد که بخش <method> پارامتر task را به فانکشنی که باید اجرا شود نگاشت می‌کند. در متد سازنده AdminController خط زیر دیده می‌شود:

 
$this->registerTask('unpublish', 'publish');

 

که به این معنی است اگر task برابر "articles.unpublish" باشد، متد publish اجرا می‌شود.

این امکان به اشتراک‌گذاری کد بین دو عملیات مشابه را می‌دهد، هرچند در جزئیات تفاوت‌هایی وجود دارد. در متد publish همچنین داریم:

 
$task = $this->getTask();

 

که بخش <method> از پارامتر task را دریافت می‌کند تا بر اساس آن تفاوت‌ها کدگذاری شود. توجه داشته باشید که در این بخش از کد "task" اشاره دارد به فقط بخش <method> پارامتر task؛ جوملا در نامگذاری گاهی ناهماهنگ است.

2. مقدار بسیار کمی از کد لازم برای انجام عملیات انتشار در کد کامپوننت com_content بود! تقریباً تمام کد داخل کلاس‌های MVC موجود در کتابخانه جوملا است. انتخاب دقیق نام فیلدهای کامپوننت و نحوه ارث‌بری کلاس‌های MVC کامپوننت شما از این کلاس‌های کتابخانه‌ای، می‌تواند کار با کمترین تلاش برنامه‌نویسی، قابلیت‌های زیادی را برایتان فراهم کند.

دوباره مرحله 1

ریدایرکت URL در انتهای مرحله 2 باعث می‌شود که دوباره لیست مقالات نمایش داده شود. اما این بار کاربر پیامی مانند «2 مقاله منتشر شد» را در بالای فرم مشاهده خواهد کرد.

ممکن است دو مدیر به طور همزمان وارد سیستم شده باشند و هر دو تقریباً همزمان لیست مقالات را مشاهده کنند. حال سوال این است که چگونه جوملا تشخیص می‌دهد که پیام «2 مقاله منتشر شد» باید به کدام مدیر نمایش داده شود؟ پاسخ این است که جوملا از کوکی‌ها استفاده می‌کند. وقتی مرورگر مدیر، درخواست HTTP GET برای نمایش لیست مقالات را ارسال می‌کند، تمام کوکی‌هایی که قبلاً توسط سرور برای آن فرستاده شده‌اند را همراه درخواست می‌فرستد. یکی از این کوکی‌ها توسط قابلیت Session جوملا برای یافتن داده‌های جلسه کاربر مربوطه استفاده می‌شود. تابع enqueueMessage که پیش‌تر توضیح داده شد، یک پیام داخل داده‌های جلسه ذخیره می‌کند و وقتی جوملا درخواست HTTP بعدی را پردازش می‌کند، متوجه می‌شود که چنین پیامی ذخیره شده و آن را در صفحه نمایش می‌دهد.

شما می‌توانید محتوای داده‌های جلسه خود را با فعال کردن Debug جوملا در تنظیمات کلی (Global Configuration) مشاهده کنید، سپس روی علامت کوچک جوملا در گوشه پایین سمت چپ هر صفحه کلیک کنید. اما هیچ پیام ذخیره شده‌ای نخواهید دید، چون وقتی جوملا پیام ذخیره شده را نمایش می‌دهد، آن را از جلسه حذف می‌کند تا در درخواست‌های بعدی مجدداً نشان داده نشود.

مثال 2: ویرایش مقاله

مرحله 1

Editing Articles

مانند قبل، لیست مقالات نمایش داده می‌شود.

مرحله 3

مدیر روی یک مقاله کلیک می‌کند تا آن را ویرایش کند. اگر گزینه Search Engine Friendly (SEF) URL‌ها را در تنظیمات کلی سایت غیرفعال کرده باشید، لینک پشت عنوان هر مقاله چیزی شبیه به این خواهد بود: 

`http://yourdomain.org/administrator/index.php?option=com_content&task=article.edit&id=1` 

بنابراین درخواست HTTP GET ای که به سرور ارسال می‌شود، مقدار task برابر "article.edit" دارد و باعث می‌شود کنترلر ArticleController اجرا شود و تابع edit() آن فراخوانی گردد.

همانطور که قبلاً دیدیم، تابع edit در ArticleController.php تعریف نشده است، بنابراین تابع edit متعلق به کلاسی که ArticleController از آن ارث می‌برد، یعنی کلاس `Joomla\CMS\MVC\Controller\FormController` در فایل `libraries/src/MVC/Controller/FormController.php` اجرا می‌شود. این تابع بررسی می‌کند که آیا کاربر اجازه انجام این عملیات را دارد یا نه، سپس مقاله را قفل می‌کند (با تنظیم ستون‌های checked_out و checked_out_time در رکورد مقاله داخل دیتابیس) و ریدایرکت به صفحه فرم ویرایش مقاله را تنظیم می‌کند.

مرحله 4

ریدایرکت باعث ارسال یک درخواست HTTP GET به آدرسی شبیه  به آدرس زیر می شود:

`http://yourdomain.org/administrator/index.php?option=com_content&view=article&layout=edit&id=1` 

همانطور که می بینید پارامتر task وجود ندارد، بنابراین این درخواست توسط کنترلر DisplayController کامپوننت com_content در تابع display() پردازش می‌شود. این تابع از کلاس View مقاله در `src/View/Article/HtmlView.php` استفاده می‌کند و فایل قالب (tmpl) مورد استفاده `tmpl/article/edit.php` است (بر اساس پارامتر layout). این صفحه، فرم ویرایش یک مقاله را نمایش می‌دهد.

مرحله 5

وقتی مدیر روی دکمه «ذخیره و بستن» کلیک می‌کند، یک درخواست HTTP POST به سرور ارسال می‌شود که شامل اطلاعات فیلدهای مقاله و پارامتر task با مقدار "article.save" است. این درخواست به کنترلر ArticleController و تابع save() آن ارسال می‌شود. دوباره این تابع در ArticleController تعریف نشده، پس تابع save از کلاس پدر یعنی `Joomla\CMS\MVC\Controller\FormController` اجرا می‌شود. این تابع مراحل زیر را انجام می‌دهد (در مسیر معمول موفقیت‌آمیز):

- بررسی اینکه کاربر اجازه انجام عملیات را دارد 

- اعتبارسنجی داده‌ها (فیلدهای ارسالی مقاله) 

- ذخیره داده‌ها (از طریق ArticleModel) 

- بازکردن قفل مقاله 

- افزودن پیام تأییدیه موفقیت‌آمیز بودن ذخیره به صف پیام‌ها 

- تنظیم ریدایرکت به صفحه لیست مقالات

مرحله 1 دوباره

مانند قبل، لیست مقالات به همراه پیام صف شده نمایش داده می‌شود.

کتابخانه جوملا: کلاس‌های MVC

جوملا چندین کلاس Controller، View و Model در کتابخانه دارد. این بخش یک مرور کلی بر این کلاس‌ها ارائه می‌دهد و توضیح می‌دهد در چه زمانی کامپوننت شما باید از هرکدام استفاده کند. با این حال، تلاش نمی‌کند شرح کامل کارکرد هر کلاس را ارائه دهد. این کلاس‌ها را می‌توانید در مسیر `libraries/src/MVC` پیدا کنید.

کلاسهای پایه MVC

از نظر عملی، کمترین سطح کلاس‌هایی که احتمالاً استفاده می‌کنید عبارتند از:

- `BaseController` در مسیر `libraries/src/MVC/Controller/BaseController.php`

- `HtmlView` در مسیر `libraries/src/MVC/View/HtmlView.php` (برای نمایش صفحات وب)

- `BaseDatabaseModel` در مسیر `libraries/src/MVC/Model/BaseDatabaseModel.php`

(اگر کامپوننت شما به یک درخواست Ajax با یک شیء کد شده JSON پاسخ می‌دهد، باید به جای آن از `libraries/src/MVC/View/JsonView.php` استفاده کنید.)

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

BaseController

عملکردهای موجود در `BaseController` شامل موارد زیر است:

- متد `execute()` که بر اساس بخش `<method>` پارامتر `task` (که به آن فرستاده می‌شود) تابع مناسب Controller را اجرا می‌کند.

- توابعی برای تعیین کلاس‌های View و Model مناسب (براساس تنظیم پارامتر `view` در درخواست HTTP) و فراخوانی کلاس `MVCFactory` برای ایجاد آن‌ها.

- متد پیش‌فرض `display()`, که نمونه‌ای از کلاس‌های View و Model را دریافت کرده (شامل لینک دادن نمونه View به نمونه Model) و سپس متد `display()` کلاس View را فراخوانی می‌کند.

HtmlView

عملکردهای `HtmlView` شامل موارد زیر است:

- متد پیش‌فرض `display()` که فایل tmpl را اجرا می‌کند.

- کدی برای یافتن فایل tmpl با توجه به پوشه‌بندی اورراید(override) شده در قالب (template).

- کدی برای تنظیم و دریافت نمونه مدل (model instance).

BaseDatabaseModel

عملکردهای `BaseDatabaseModel` شامل موارد زیر است:

- کدی برای دریافت نمونه‌ای از کلاس Table (از طریق کلاس MVCFactory)

- کد پایه برای ایجاد "حالت" مدل (model "state"). این ویژگی هنگامی مفید است که کامپوننت و/یا چندین ماژول در صفحه وب، از داده‌های پایه مشترک استفاده کنند. در این حالت آن‌ها ممکن است از یک نمونه Model مشترک بهره ببرند و مدل "حالت" مانند محفظه‌ای برای به اشتراک‌گذاری مقادیر بین کامپوننت و ماژول‌ها عمل می‌کند.

کلاسهای کنترلر در سطح بالاتر

دو کلاس کنترلر در سطح بالاتر وجود دارد که هر دو از `BaseController` ارث‌بری می‌کنند.

AdminController

کلاس `AdminController` شامل متدهایی است که عملیات‌هایی را مدیریت می‌کند که می‌توان روی چندین مورد انجام داد، مانند:

- حذف (delete)

- انجام فرآیند چک‌این (checking-in)

- تغییر وضعیت انتشار (publishing state)

- تغییر ترتیب نسبی رکوردها (relative ordering)

کد معمولاً متد مرتبط در مدل را برای انجام این عملیات فراخوانی می‌کند، سپس پیام موفقیت یا شکست عملیات مدل را تنظیم کرده و بازگشت به همان صفحه را انجام می‌دهد (ریدایرکت). به همین دلیل، این کلاس برای عملیاتی مانند «عملیات ۲» که در بخش الگوی Post/Request/Get در دیاگرام بالا آمده، بسیار مفید است.

نام `AdminController` ممکن است القا کند که این کنترلر فقط برای بخش مدیریت (بک‌اند) استفاده می‌شود، اما این درست نیست و می‌توان از آن در بخش فرانت‌اند سایت نیز استفاده کرد.

توجه داشته باشید که این کنترلر عملیات‌هایی که توسط دکمه Batch در صفحاتی مانند Content/Articles فعال می‌شوند را پشتیبانی نمی‌کند؛ این درخواست‌های POST توسط `FormController` مدیریت می‌شوند.

FormController

کلاس `FormController` شامل متدهایی است که مربوط به ویرایش یک مورد منفرد می‌باشند:

- مدیریت درخواست ویرایش یک مورد: شامل بررسی این موضوع است که آیا کاربر اجازه ویرایش دارد و مورد موردنظر در حال حاضر چک‌اوت نیست؛ اگر این بررسی‌ها موفق باشد، مورد چک‌اوت شده (در صورت فعال بودن قابلیت چک‌اوت در کامپوننت) و سپس ریدایرکت به فرم ویرایش انجام می‌شود.

- مدیریت درخواست افزودن مورد جدید: بررسی اینکه کاربر اجازه ایجاد آن را دارد و در صورت امکان، ریدایرکت به فرم ویرایش خالی (جدید).

- مدیریت ذخیره‌سازی (Save) یک مورد در حال ویرایش یا تازه ایجاد شده: کد بررسی می‌کند که کاربر اجازه انجام عملیات را دارد و سپس متد مناسب مدل را برای ذخیره مورد فراخوانی می‌کند.

- مدیریت لغو (Cancel) ویرایش، که کاربر را به صفحه مناسب بازمی‌گرداند و در صورت نیاز رکورد را چک‌این می‌کند.

- مدیریت عملیات آغاز شده توسط دکمه Batch

بر همین اساس، `FormController` برای «عملیات ۳» و «عملیات ۵» در الگوی Post/Request/Get (که در دیاگرام‌های بالا آمده) بسیار مناسب است.

کلاسهای View در سطح بالاتر

به جز `CategoryFeedView` که برای تولید فید استفاده می‌شود، دو کلاس View سطح بالاتر کاربرد بیشتری دارند:

- `CategoryView` – برای نمایش یک دسته‌بندی و زیرمجموعه‌های آن

- `CategoriesView` – برای نمایش تمام دسته‌بندی‌ها در یک سطح مشخص از سلسله‌مراتب دسته‌ها و همچنین تعداد آیتم‌های مرتبط با هر دسته

دو کلاس `ListView` و `FormView` به نظر می‌رسد برای عملکردهای نمایش لیست رکوردها (مثل View مقالات مدیر کامپوننت `com_content`) و فرم ویرایش یک رکورد طراحی شده‌اند. با این حال، تا زمان نگارش این مقاله (نسخه آلفای Joomla 5 اخیراً منتشر شده)، این کلاس‌ها در هیچ یک از کامپوننت‌های جوملا به کار گرفته نشده‌اند، بنابراین توصیه نمی‌شود دست‌کم فعلاً از آن‌ها استفاده کنید.

کلاسهای مدل در سطح بالاتر

Model Class Hierarchy

نمودار نشان‌دهنده درخت ارث‌بری مدل‌های MVC کتابخانه جوملا

سلسله مراتب کلاس مدل‌ها

کلاس ItemModel تقریباً مشابه BaseDatabaseModel است، با این تفاوت که یک متد اضافی به نام `getStoreId()` دارد که زمانی کاربرد دارد که کامپوننت و/یا چند ماژول از مدل یکسانی استفاده می‌کنند و می‌خواهید بین مجموعه داده‌های مربوط به هر کدام تفکیک قائل شوید.

علاوه بر `getStoreId()`، کلاس ListModel قابلیت‌هایی برای گرفتن مجموعه‌ای از رکوردها جهت نمایش در صفحه وب دارد، از جمله پشتیبانی از صفحه‌بندی (pagination). توجه داشته باشید که قابلیت صفحه‌بندی ممکن است میان بخش فرانت‌اند و بک‌اند کمی متفاوت باشد. ListModel برای پشتیبانی از «عملیات 1» در دیاگرام‌های بخش الگوی Post/Request/Get کاربردی است.

کلاس FormModel شامل پشتیبانی برای فرم‌های جوملا است، هم برای آماده‌سازی فرم جهت نمایش و هم برای اعتبارسنجی داده‌های ارسالی در POST. علاوه بر این، متدهایی برای مدیریت چک‌این و چک‌اوت رکوردهای پایگاه داده دارد. بنابراین، برای «عملیات 3» و «عملیات 4» در دیاگرام‌ها مناسب است.

کلاس AdminModel از FormModel ارث می‌برد، پس تمام قابلیت‌های مدیریت فرم را دارد، اما به علاوه متدهایی برای به‌روزرسانی پایگاه داده شامل اضافه کردن، به‌روزرسانی و حذف رکوردها و پشتیبانی از عملیات دسته‌ای دارد. پس برای «عملیات 2» و «عملیات 5» مناسب است. درست مانند `AdminController`، این مدل فقط مناسب بخش مدیریت نیست و می‌توان آن را در بخش فرانت‌اند نیز استفاده کرد.

با این وجود، اگرچه `FormModel` و `AdminModel` برای مراحل مختلف جریان ویرایش رکورد طراحی شده‌اند، اما در عمل معمولاً از یک مدل یکسان برای همه مراحل استفاده می‌شود. تمام کامپوننت‌های هسته جوملا نیز همین کار را می‌کنند و مدلشان را از `AdminModel` توسعه می‌دهند نه `FormModel`.

چیزی که باید بدانید این است که وقتی مدل را در جریان “ویرایش آیتم” یکسان استفاده می‌کنید، کد مدل دو وظیفه انجام می‌دهد:

- آماده‌سازی داده برای نمایش در صفحه وب

- آماده‌سازی فرم برای نمایش یا اعتبارسنجی داده‌های POST

اگر مدل برای انجام یک عملیات POST (مثلاً «عملیات 3» و «عملیات 5») استفاده شود، تلاش برای آماده‌سازی داده برای صفحه وب هدر رفته است. (در واقع، در متد `getModel()` از کنترلر فرم، پارامتر `$config` به صورت پیش‌فرض `array('ignore_request' => true)` تنظیم شده که باعث می‌شود متد `populateState` مدل فراخوانی نشود تا از این کار اضافی جلوگیری شود.)

خلاصه

جوملا کلاس‌های کنترلر و مدل سطح بالایی دارد که قابلیت‌های فراوانی فراهم می‌کنند و می‌توانند کد شما را بسیار ساده‌تر کنند (که می‌توان از آن‌ها هم در بخش فرانت‌اند و هم بک‌اند استفاده کرد).

انتخاب اینکه کدام کلاس کنترلر و مدل را توسعه دهید در بک‌اند راحت‌تر است چون می‌توانید الگوی کامپوننت‌های هسته جوملا را دنبال کنید.

اما در فرانت‌اند راهنمای کلی برای انتخاب مناسب‌ترین کلاس‌ها به شرح زیر است؛ در هر مورد شما از `HtmlView` استاندارد به عنوان کلاس پایه View استفاده می‌کنید:

نمایش ساده

فقط نمایش یک رکورد یا مجموعه‌ای از رکوردها بدون اینکه امکان تغییر ایجاد شود.

- کنترلر: توسعه یافته از `BaseController`

- مدل: توسعه یافته از `BaseDatabaseModel` یا (اگر مدل بین کامپوننت و ماژول‌ها مشترک است) `ItemModel` (اگر رکورد تکی است) یا `ListModel` (اگر رکوردهای متعدد است).

نمایش رکوردها به همراه عملیات روی رکوردهای انتخاب شده

نمایش یک فرم شامل چند رکورد (که فرم در فایل XML تعریف نشده باشد) و ارائه امکان انتخاب چند رکورد و اعمال عملیاتی مانند حذف یا انتشار:

- کنترلر: توسعه یافته از `BaseController`

- مدل: توسعه یافته از `ListModel` – مگر اینکه بخواهید همان مدل را برای نمایش فرم و انجام به‌روزرسانی‌ها استفاده کنید؛ در این صورت از `AdminModel` استفاده کنید.

مدیریت POSTهای مرتبط با حالت بالا

- کنترلر: توسعه یافته از `AdminController`

- مدل: توسعه یافته از `AdminModel`

ویرایش یک رکورد

نمایش فرم با یک رکورد که فرم در فایل XML تعریف شده و کاربر بتواند آن را ویرایش کند یا فرم خالی برای ایجاد رکورد جدید:

- کنترلر: توسعه یافته از `BaseController`

- مدل: توسعه یافته از `FormModel` – مگر اینکه همان مدل را برای نمایش فرم و انجام به‌روزرسانی‌ها استفاده کنید (که معمولاً همین است)؛ در این صورت از `AdminModel` استفاده کنید.

مدیریت POSTهای مرتبط با حالت بالا

- کنترلر: توسعه یافته از `FormController`

- مدل: توسعه یافته از `AdminModel`

نمونه‌های کامپوننت

این بخش شامل نمونه‌های عملی از انواع مختلف کامپوننت‌ها است. برای دریافت کد منبع این نمونه‌ها به منظور بررسی یا نصب، می‌توانید مخزن `manual-examples` را کلون کنید یا یک فایل زیپ قابل نصب برای هر نمونه جداگانه دانلود کنید.

کلون کردن مخزن

به محلی در رایانه توسعه خود که می‌توانید چندین مخزن (repository) را نگهداری کنید، بروید. ممکن است یک پوشه به نام `repos` یا `git` یا چیز دیگری داشته باشید. در پنجره ترمینال، دستور زیر را وارد کنید:

git clone https://github.com/joomla/manual-examples.git

این کار بسیار سریع انجام می‌شود و یک کلون از مخزن `manual-examples` در اختیار شما قرار می‌دهد که بررسی آن در محیط توسعه IDE بسیار ساده است. در ادامه، نمونه‌ای از تصویر کلون باز شده در VSCode آمده است:

screenshot of manual examples folder in vscode

ایجاد فایل زیپ قابل نصب

برای ایجاد یک فایل زیپ قابل نصب، پوشه زیرمجموعه شامل کد نمونه، مانند پوشه `com_exampleform` را فشرده (compress) کنید.

 دانلود فایل زیپ قابل نصب

1. به مخزن `manual-examples` در گیت‌هاب بروید.

2. نمونه مورد نظر خود، مثلاً `component-exampleform` را انتخاب کنید.

3. پوشه زیرمجموعه شامل نمونه، مثلاً `com_exampleform` را انتخاب کنید.

4. آدرس URL را از نوار آدرس مرورگر کپی کنید.

5. به سایتی برای دانلود مانند DownGit مراجعه کنید.

6. آدرس URL کپی شده را در فرم مربوطه جای‌گذاری کنید.

7. دکمه Download را انتخاب کنید.

8. فایل زیپ دانلود شده را ذخیره کنید. این فایل را می‌توانید در یک نصب جوملا نصب کنید یا با باز کردن آن در IDE به بررسی کد‌ها بپردازید.

کامپوننت نمونه فرم

این کامپوننت مثال MVC جنبه‌های زیر در دستکاری فرم را نشان می‌دهد: 

- استفاده از فرم‌های جوملا برای دریافت داده‌ها در فرم 

- استفاده از چند فیلد استاندارد فرم 

- نوشتن یک فیلد سفارشی 

- نوشتن یک قانون اعتبارسنجی سمت سرور سفارشی 

- نوشتن یک قانون اعتبارسنجی سمت کلاینت سفارشی 

- نوشتن یک فیلتر فرم سفارشی 

یک فایل ZIP قابل نصب را می‌توان از طریق DownGit دریافت کرد. پس از نصب، به آدرس زیر بروید تا آن را در نمونه جوملا خود اجرا کنید. 

your domain>/index.php?option=com_exampleform

تصویر زیر فرم نمونه را با داده‌های وارد شده نشان می‌دهد: 

example form with added data

خلاصه‌ای کوتاه از فایل‌های اصلی کد در ادامه آمده است. در سراسر کد نیز توضیحات بیشتری وجود دارد. 

ارائهدهنده سرویس مدیر 

مسیر: administrator/components/com_exampleform/services/provider.php 

این کد اولیه برای یک کامپوننت پایه MVC است. برای کامپوننت‌ها، این فایل در مسیر /administrator در ساختار جوملا قرار می‌گیرد. اگر می‌خواهید آن را کامل متوجه شوید، بخش تزریق وابستگی (Dependency Injection) را مطالعه کنید. 

جوملا از این فایل کلاس‌های پیش‌فرض Extension و Dispatcher را نمونه‌سازی می‌کند و همچنین یک کلاس MVC Factory که مدل، نما و کنترلر کامپوننت ما را می‌سازد. 

کنترلر نمایش سایت 

مسیر: components/com_exampleform/src/Controller/DisplayController.php 

این فایل زمانی اجرا می‌شود که به صفحه سایت خود که فرم را نمایش می‌دهد بروید (یعنی به آدرس URL .../index.php?option=com_exampleform مراجعه کنید). 

این کنترلر کلاس‌های مرتبط مدل و نما را دریافت می‌کند و متد display() را روی نمونه نما فراخوانی می‌کند. 

نمای مثال فرم سایت 

مسیر: components/com_exampleform/src/View/Exampleform/HtmlView.php 

این نما مدل را برای آماده‌سازی فرم فراخوانی می‌کند، سپس متد display() را برای اجرای فایل tmpl فراخوانی می‌کند. 

مدل مثال فرم سایت 

مسیر: components/com_exampleform/src/Model/ExampleformModel.php 

این مدل فرم را طبق توضیحات بخش فرم‌ها (Forms) تنظیم می‌کند. 

فایل tmpl فرم نمونه سایت 

مسیر: components/com_exampleform/tmpl/exampleform/default.php

این فایل از Web Asset Manager برای تنظیم اسکریپت‌های اعتبارسنجی سمت کلاینت استفاده می‌کند.

سپس تگ `<form>` را خروجی می‌دهد و فیلدها را با استفاده از تابع `renderFieldset` نمایش می‌دهد.

دکمه ارسال (Submit) یک رویداد onclick دارد که تابع `Joomla.submitbutton('exampleform.submit')` را فراخوانی می‌کند. این تابع یک درخواست HTTP POST به سمت سرور می‌فرستد، همراه با مقادیر فیلدها به عنوان پارامترهای POST، که شامل پارامتر `task` با مقدار `'exampleform.submit'` است.

وقتی این درخواست HTTP به سرور برسد، جوملا پارامتر `task` را بررسی می‌کند و در نتیجه همانطور که در معماری MVC جوملا توضیح داده شد، متد `ExampleformController::submit()` را فراخوانی می‌کند.

فرم نمونه XML 

مسیر: components/com_exampleform/forms/example_form.xml

اکثر این فایل شامل استفاده از فیلدهای استاندارد فرم جوملا است.

شما به راحتی می‌توانید فیلدهای استاندارد دیگر فرم را به آن اضافه کنید و با آن‌ها آزمایش کنید.

همچنین این فایل شامل موارد زیر است:

- تعریف یک فیلد سفارشی: 

 
addfieldprefix="My\Component\Exampleform\Site\Field"
name="time"
type="mytime"

 

- تعریف یک فیلتر سفارشی: 

 
addfilterprefix="My\Component\Exampleform\Site\Filter"
filter="lettersonly"

 

- تعریف یک قانون اعتبارسنجی سمت کلاینت سفارشی: 

 
class="inputbox validate-noUppercase"
data-validation-text="Error: No uppercase letters are allowed"

 

- تعریف یک قانون اعتبارسنجی سمت سرور سفارشی: 

 
addruleprefix="My\Component\Exampleform\Site\Rule"
validate="noasterisk"

 

- استفاده از صفت `showon` برای نمایش مشروط فیلدها.

کنترلر فرم نمونه سایت 

مسیر: components/com_exampleform/src/Controller/ExampleformController.php

زمانی که داده‌های فرم از طریق درخواست HTTP POST به سرور ارسال می‌شوند، جوملا پارامتر `task` را بررسی می‌کند و چون مقدار آن `'exampleform.submit'` است، متد `submit()` از نمونه کلاس `ExampleformController` فراخوانی می‌شود.

این متد آرایه پارامترهای POST را دریافت می‌کند و مدل را برای تنظیم مجدد فرم از تعریف موجود در `example_form.xml` فراخوانی می‌کند.

سپس عملیات اعمال فیلترها و قوانین اعتبارسنجی روی فیلدها را آغاز می‌کند.

اگر داده‌ها در اعتبارسنجی قبول نشوند، داده‌های ورودی در نشست (session) ذخیره شده و یک ریدایرکت به فرم صادر می‌شود. وقتی درخواست GET برای بازنمایی فرم دریافت شود، متد `loadFormData` در `ExampleformModel` داده‌های ذخیره شده در نشست را بازیابی کرده و فیلدها را با مقادیر قبلی پر می‌کند.

اگر داده‌ها اعتبارسنجی را بگذرانند، نما (view) `ExampleformReturn` ساخته شده و داده‌های خام و فیلتر شده به آن ارسال می‌شوند.

نمای ExampleformReturn سایت 

مسیر: components/com_exampleform/src/View/ExampleformReturn/HtmlView.php

این کلاس فقط یک تابع دارد که داده‌های ارسالی از کنترلر را دریافت و به صورت محلی ذخیره می‌کند.

فایل tmpl نمای exampleformreturn سایت 

مسیر: components/com_exampleform/tmpl/exampleformreturn/default.php

این فایل فقط داده‌های خام و فیلتر شده‌ای را که به نما ارسال شده‌اند، نمایش می‌دهد.

توجه داشته باشید که نما (View) و فایل tmpl در یک کانتکس (context) تابع مشترک قرار دارند، بنابراین متغیرهایی که در نما ساخته شده‌اند در فایل tmpl نیز در دسترس هستند.

فیلد سفارشی 

مسیر: components/com_exampleform/src/Field/MytimeField.php

این فایل شامل کد منبع فیلد سفارشی `mytime` است.

فیلتر سفارشی 

مسیر: components/com_exampleform/src/Filter/LettersonlyFilter.php

این فایل شامل کد منبع فیلتر سفارشی `lettersonly` است.

قانون اعتبارسنجی سفارشی 

مسیر: components/com_exampleform/src/Rule/Noasterisk.php

این فایل شامل کد منبع قانون اعتبارسنجی سفارشی سمت سرور به نام `noasterisk` است.

فایل joomla.asset.json مربوط به مدیا 

مسیر: media/com_exampleform/joomla.asset.json

این فایل دارایی‌های (assets) جاوااسکریپت (و CSS) کامپوننت را همراه با وابستگی‌های آن‌ها تعریف می‌کند، همانطور که توسط Web Asset Manager مورد نیاز است.

برای کامپوننت‌ها این فایل همیشه به صورت خودکار توسط جوملا پردازش می‌شود.

کد جاوااسکریپت اعتبارسنجی سمت کلاینت 

مسیر: media/com_exampleform/js/no-uppercase.js

این فایل شامل کد جاوااسکریپت مربوط به قانون اعتبارسنجی سفارشی سمت کلاینت است.

کامپوننت Ajaxdemo 

این کامپوننت نمونه نحوه استفاده از Ajax برای تعامل با سرور بدون نیاز به بارگذاری مجدد صفحه را نشان می‌دهد. برای اطلاعات بیشتر، بخش مفاهیم کلی درباره Ajax و JsonResponse را ببینید.

این کامپوننت به سادگی قابل تنظیم است تا استفاده از com_ajax را برای افزونه‌ها و قالب‌ها نشان دهد. کافی است آدرس URL در فایل `media/js/divide.js` را به جای `com_ajaxdemo` به `com_ajax` تغییر دهید و سایر پارامترهای URL لازم را تنظیم کنید.

یک فایل ZIP قابل نصب از طریق DownGit قابل دریافت است. پس از نصب، به آدرس زیر بروید تا آن را در نمونه جوملا خود اجرا کنید.

<your domain>/index.php?option=com_ajaxdemo

تصویر زیر فرم نمونه را همراه با داده‌هایی که وارد شده‌اند نشان می‌دهد: 

example form with added data

کامپوننت یک فرم نمایش می‌دهد که دو عدد A و B را دریافت می‌کند و یک دکمه برای محاسبه تقسیم A بر B دارد. عملیات تقسیم از طریق یک درخواست Ajax به سرور ارسال می‌شود، و اگر مقدار B صفر باشد، یک استثنا (خطا) ایجاد می‌شود.

خلاصه‌ای کوتاه از فایل‌های اصلی منبع برنامه در ادامه آمده است.

ارائه‌دهنده سرویس مدیر 

مسیر: administrator/components/com_ajaxdemo/services/provider.php 

این کد اولیه برای یک کامپوننت ساده با معماری MVC است. برای کامپوننت‌ها، این فایل در مسیر /administrator در ساختار جوملا قرار می‌گیرد. اگر می‌خواهید آن را کامل متوجه شوید، بخش تزریق وابستگی (Dependency Injection) را مطالعه کنید. 

جوملا از این فایل کلاس‌های پیش‌فرض Extension و Dispatcher را نمونه‌سازی کرده و همچنین یک کلاس کارخانه MVC ایجاد می‌کند که مدل، نما و کنترلر را برای کامپوننت می‌سازد. 

کلاس Dispatcher پیش‌فرض پارامتر task در URL را بررسی می‌کند و بر اساس آن تصمیم می‌گیرد کدام کنترلر را نمونه‌سازی نماید. کنترلر پیش‌فرض زمانی که پارامتر task وجود نداشته باشد، `DisplayController` است. وقتی دکمه Divide فشار داده می‌شود، کد جاوااسکریپت یک درخواست Ajax ارسال می‌کند که پارامتر task آن برابر `"ajax.divide"` است. بر این اساس، Dispatcher پیش‌فرض کنترلر Ajax این کامپوننت یعنی `AjaxController` را نمونه‌سازی کرده و متد `divide` آن را فراخوانی می‌کند.

کنترلر نمایش سایت 

مسیر: components/com_ajaxdemo/src/Controller/DisplayController.php 

متد display این کنترلر زمانی اجرا می‌شود که به صفحه سایت بروید و فرم را ببینید (مثلاً به آدرس URL .../index.php?option=com_ajaxdemo مراجعه کنید). 

این کنترلر کلاس‌های مدل و نما را می‌گیرد و متد display() را روی نمونه‌ نما اجرا می‌کند.

مطلبی که فرستادی درباره توسعه یک کامپوننت جوملا با نام Ajaxdemo هست. من برات بخش به بخش به فارسی ترجمه می‌کنم:

Site Ajaxdemo View

مسیر: `components/com_ajaxdemo/src/View/Ajaxdemo/HtmlView.php` 

این فایل، مدل را فراخوانی می‌کند تا فرم را آماده کند، سپس تابع `display()` را اجرا می‌کند تا فایل قالب (tmpl) را نمایش دهد.

Site Ajaxdemo Model

مسیر: `components/com_ajaxdemo/src/Model/AjaxdemoModel.php` 

این فایل فرم را همانطور که در بخش «Forms» توضیح داده شده، تنظیم می‌کند.

Site Ajaxdemo tmpl file

مسیر: `components/com_ajaxdemo/tmpl/ajaxdemo/default.php` 

در این فایل، از Web Asset Manager برای الحاق فایل جاوااسکریپت `divide.js` استفاده شده است که تماس Ajax را راه‌اندازی می‌کند. 

آدرس ریشه (root URL) سایت جوملا به کد جاوااسکریپت ارسال می‌شود تا ساخت URLها ساده‌تر شود. 

سپس فرم HTML شامل دکمه‌ای با رویداد onclick که کد `divide.js` را اجرا می‌کند، در صفحه خروجی داده می‌شود.

بله، حتماً. در ادامه ترجمه بخش ارسالی شما درباره «لینک و آیکون Quicktask» در توسعه جوملا را می‌بینید:

لینک و آیکون Quicktask

به طور کلی، یک کامپوننت دارای یک یا چند لینک به ویوهای خود است. این لینک‌ها در فایل مانیفست (manifest) تعریف شده و هنگام نصب به منو اضافه می‌شوند. 

یک لینک به کامپوننت شما:

 
<administration>
<menu>
COM_EXAMPLE
</menu>
[..]
</administration>

 

گاهی اوقات افزودن یک لینک به اصطلاح Quicktask مفید است. این لینک به کاربر اجازه می‌دهد تا عملی را مستقیماً از منو انجام دهد بدون اینکه ابتدا به صفحه نمای کلی (Overview) برود. 

برای نمونه، در کامپوننت‌های اصلی جوملا مانند مقالات در `com_content`، Quicktask به صورت آیکون «+» است که با یک کلیک امکان افزودن مقاله جدید را فراهم می‌کند. لینک منوی شما در فایل مانیفست هنگام نصب اضافه می‌شود.

لینک و عنوان Quicktask

لینک و عنوان Quicktask به عنوان پارامتر به آیتم منو اضافه می‌شوند.

 
<menu link="option=com_example&amp;view=examples">
    COM_EXAMPLE
    <params>
        <menu-quicktask-title>COM_EXAMPLE_MENU_QUICKTASK_TITLE</menu-quicktask-title>
        <menu-quicktask>index.php?option=com_example&amp;view=example&amp;layout=edit</menu-quicktask>
    </params>
</menu>

 

رشته ترجمه عنوان باید در فایل زبان `*.sys.ini` مربوط به افزونه وجود داشته باشد.

آیکون Quicktask

آیکون پیش‌فرض، علامت «+» است که معمولاً به معنای ایجاد یک آیتم جدید است، چون بیشترین کاربرد را در کامپوننت‌های داخلی دارد.

شما می‌توانید یک آیکون متفاوت مشخص کنید، یا به صورت نام ساده‌ای از آیکون‌های رایج تعریفی که پیشوند `icon-` به طور خودکار به آن اضافه می‌شود، یا به صورت مشخصه فونت آوسام (font-awesome).

لینک و آیکون Quicktask

 
<menu link="option=com_example&amp;view=examples">
    COM_EXAMPLE
    <params>
        <menu-quicktask-title>COM_EXAMPLE_MENU_QUICKTASK_TITLE</menu-quicktask-title>
        <menu-quicktask-icon>eye</menu-quicktask-icon>
        <menu-quicktask>index.php?option=com_example&amp;view=example&amp;layout=view</menu-quicktask>
    </params>
</menu>
 

 مثال

این مثال یک ورودی کامل منو را با داشبورد، زیرمنو و یک Quicktask نشان می‌دهد. آیتم دوم که دارای Quicktask است شامل آیکون فونت‌آوسامی است که قبلاً ایلیا‌س نشده است.

 
<menu>
    COM_EXAMPLE
    <params>
        <dashboard>example</dashboard>
    </params>
</menu>
<submenu>
    <menu link="option=com_example">
        COM_EXAMPLE_MENU
        <params>
            <menu-quicktask-title>COM_EXAMPLE_MENU_QUICKTASK_TITLE</menu-quicktask-title>
            <menu-quicktask>index.php?option=com_example&amp;view=example&amp;layout=edit</menu-quicktask>
        </params>
    </menu>
    <menu link="option=com_categories&amp;extension=com_example">
        COM_EXAMPLE_MENU_CATEGORIES
        <params>
            <menu-quicktask-title>COM_EXAMPLE_MENU_CATEGORIES</menu-quicktask-title>
            <menu-quicktask-icon>fas fa-person-hiking</menu-quicktask-icon>
            <menu-quicktask>index.php?option=com_categories&amp;view=category&amp;layout=edit&amp;extension=com_example</menu-quicktask>
        </params>
    </menu>
    <menu link="option=com_fields&amp;view=fields&amp;context=com_example,example">COM_EXAMPLE_MENU_FIELDS</menu>
    <menu link="option=com_fields&amp;view=groups&amp;context=com_example,example">COM_EXAMPLE_MENU_FIELDS_GROUP</menu>
</submenu>

 

مسیریابی(Routing)

سازگار با موتور جستجو (SEF)

آدرس‌های اینترنتی خوانا یا تمیز، آدرس‌هایی هستند که هم برای انسان و هم برای موتورهای جستجو قابل فهم هستند، زیرا مسیر رسیدن به صفحه خاصی را که به آن اشاره می‌کنند، توضیح می‌دهند.

این بخش ناتمام است، لطفاً از لینک «ویرایش این صفحه» در پایین این صفحه برای مفیدتر کردن آن استفاده کنید.

مخفی کردن ستون‌های جدول 

تمام کامپوننت‌های اصلی دارای دکمه‌ای هستند که به کاربر اجازه می‌دهد انتخاب کند کدام ستون‌های جدول نمایش داده شود.

افزودن قابلیت مخفی کردن ستون‌های جدول به کامپوننت شما

افزودن این قابلیت به کامپوننت خودتان بسیار ساده است و معمولاً فقط کافی است کد زیر را به فایل `tmpl` مربوط به جدول اضافه کنید.

بررسی استفاده از WebAssetManager

در بلوک PHP بالای فایل `tmpl` به دنبال این خط کد بگردید:

 
$wa = $this->document->getWebAssetManager();

 

اگر قبلاً از WebAssetManager استفاده می‌کنید

خط زیر را به کد موجود خود اضافه کنید:

 
useScript('table.columns')

  

نکته: به پایان خط دقت کنید. کد نهایی شما معمولاً مشابه این مثال خواهد بود:

 
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns')
    ->useScript('multiselect');

 

اگر هنوز از WebAssetManager استفاده نمی‌کنید

کد زیر را در هر جای بلوک PHP بالای فایل `tmpl` اضافه کنید:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns');

 

نکات

- جدول شما باید یک جدول HTML معتبر با تگ `<thead>` باشد و هر ستون باید داخل تگ `<th>` تعریف شده باشد. 

- جدول شما نمی‌تواند شامل تگ‌های `<tfoot>` یا `<colgroup>` یا ویژگی‌هایی مانند `colspan` باشد. این موارد باعث نمایش ستون‌های خالی در انتهای ردیف شده و کلاسبندی‌ها یا استایل‌های تعریف‌شده در `<colgroup>` را خراب می‌کنند. (مسئله‌ای که برای رفع آن پیگیری شده است) 

- اگر چند جدول در صفحه دارید و می‌خواهید از بارگذاری اسکریپت روی یکی از آن جداول جلوگیری کنید، می‌توانید کلاس `columns-order-ignore` را به آن جدول اضافه کنید.