فرم ها

جوملا قابلیت های زیادی را برای شما فراهم می کند تا به راحتی فرم ها را توسعه دهید. در این بخش نحوه استفاده از کلاس فرم جوملا و کلاس های مرتبط برای توسعه و دستکاری فرم های html را توضیح می دهیم.

خود جوملا نیز رویکرد خاصی برای طراحی عملکرد فرم (بر اساس MVC) دارد و این بخش شامل مطالب آموزشی برای کمک به درک و توسعه کامپوننت خود برای هماهنگی با این اصول است.

مقدمه

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

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

مستطیل‌هایی با پس‌زمینه سفید شامل کدهای افزونه (اکستنشن) شما می‌باشند.

فرم پایه

فرم پایه

ابتدا باید فرم خود را در قالب XML تعریف کنید و از نوع فیلدهای استاندارد جوملا استفاده کنید. برای نمونه به کد کامپوننت در ادامه نگاه کنید. به طور کلی، هر عنصر field در فایل XML، متناظر با یک عنصر HTML (معمولاً input) در فرم است و ویژگی‌های فیلد XML به ویژگی‌های عنصر input در HTML نگاشت می‌شوند. بسیاری از ویژگی‌های ممکن فیلد در نوع فیلد Text فهرست شده‌اند.

مرحله ۱: بارگذاری فرم

در این مرحله، کاربر به صفحه‌ای مراجعه کرده که فرم در آن نمایش داده می‌شود.

ابتدا باید یک نمونه از کلاس Form را ایجاد کنید. این کار را با گرفتن FormFactory از Dependency Injection Container و فراخوانی متد createForm انجام می‌دهید:

 
$form = Factory::getContainer()->get(FormFactoryInterface::class)->createForm("sample", array("control" => "myform"));
 

 

در کد بالا (که از نمونه کد زیر گرفته شده) یک نمونه Form با نام "sample" ایجاد کردیم (شما می‌توانید هر نامی بگذارید، فقط باید یکتا باشد تا با فرم‌های دیگر در همان صفحه تداخل نداشته باشد). همچنین آرایه‌ای با "control" => "myform" به آن داده شده است. این باعث می‌شود عناصر input در HTML نامشان مانند "myform[message]"، "myform[email]" و غیره شود. وقتی فرم ارسال شود، داده‌ها به صورت پارامترهای HTTP POST به همین شکل فرستاده می‌شوند و بسیار آسان می‌توانید آنها را به یک آرایه PHP تبدیل کنید.

سپس باید کلاس Form فایل XML تعریف فرم را بارگذاری کند:

$form->loadFile("sample_form.xml");  // مسیر و نام فایل XML فرم را ارسال کنید

این شیء Form فایل را به صورت یک SimpleXMLElement PHP می‌خواند و تجزیه می‌کند تا از صحت فرمت XML اطمینان حاصل کند. SimpleXMLElement در نمودار با مستطیل آبی به نام "xml" نشان داده شده است.

مرحله ۲: ارائه داده‌های از پیش تکمیل شده (Pre-fill)

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

این کار با تنظیم یک آرایه انجمنی (associative) $data انجام می‌شود که هر کلید نام فیلد در فایل XML و مقدار آن مقدار از پیشت کمیل شده است.

آرایه داده‌ها را به متد bind فرم می‌دهید و فرم این داده‌ها را در این شیء ثبت می‌کند، که در نمودار با نوارهای آبی نشان داده شده است.

مرحله ۳: خروجی گرفتن فرم به صورت HTML

 

شما متد renderField را فراخوانی می‌کنید:

 
echo $form->renderField($name);

 

که در آن $name نام همان فیلد در فایل XML است. این متد HTML مربوط به آن فیلد را بازگردانی می‌کند که قابل ارسال به خروجی است. جوملا از نمایش XML فرم شما بخش مربوط به آن نام را می‌گیرد، HTML مناسب را تولید می‌کند و مقدار از پیش‌ تکمیل شده را به عنوان مقدار value وارد می‌کند.

همچنین باید عناصر ورودی درون یک عنصر `<form>` قرار داده شوند و یک دکمه submit اضافه شود.

مرحله ۴: ارسال فرم توسط کاربر

کاربر داده‌ها را در فرم HTML وارد کرده و دکمه ارسال را می‌فشارد. مرورگر یک درخواست HTTP POST به URL تعیین شده در تگ `<form>` می‌فرستد و داده‌های ورودی کاربر را در آرایه‌ای به نام myform (یا هر نامی که قبلاً انتخاب کردید) ارسال می‌کند، که کلید هر عنصر نام عنصر input در HTML است.

جوملا این درخواست POST را به کامپوننت شما ارسال می‌کند. چون این یک درخواست جدید HTTP است، نمونه قبلی Form دیگر موجود نیست، پس باید مرحله ۱ را دوباره تکرار کنید تا یک نمونه جدید Form ساخته و فایل XML فرم را بارگذاری کنید.

 مرحله ۵: پردازش داده‌های HTTP POST

در این مرحله داده‌های ارسال شده پردازش می‌شوند که شامل ۴ بخش است:

1. گرفتن داده‌های POST

   از قابلیت Input جوملا برای خواندن داده‌های وارد شده استفاده می‌کنید، مثلاً:

 
$app = Factory::getApplication();
$data = $app->input->post->get('myform', array(), "array");

 

   که پارامترهای POST فرم myform را به صورت آرایه انجمنی می‌خواند.

2. فیلتر کردن داده‌ها

برای جلوگیری از حملات تزریق (Injection) لازم است داده‌ها را پاک‌سازی کنید. بسیاری از روش‌های Input خود فیلترینگ انجام می‌دهند ولی اگر مستقیماً داده‌ها را در آرایه خواندید، باید به صورت دستی این کار را انجام دهید:

 
$filteredData = $form->filter($data);

 

این فیلتر روی هر مقدار ورودی اعمال می‌شود. نوع فیلتر هر فیلد با صفت "filter=…" در فایل XML فرم مشخص می‌شود؛ در صورت نبودن این صفت، فیلتر پیش‌فرض (حذف تگ‌های HTML و...) استفاده می‌شود. کلاس‌های فیلتر در مسیر libraries/src/Form/Filter قرار دارند. توجه کنید که این فیلترها با فیلترهای Input متفاوت هستند.

3. اعتبارسنجی داده‌ها

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

$result = $form->validate($data);

 

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

4. نمایش پیام به کاربر

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

کد نمونه کامپوننت

در ادامه کد یک کامپوننت کوچک را می‌بینید که می‌توانید آن را نصب کنید تا استفاده پایه‌ای از فرم‌های جوملا را نمایش دهید. این سه فایل را در پوشه‌ای به نام com_sample_form1 قرار دهید، سپس پوشه را زیپ کنید تا فایل com_sample_form1.zip ساخته شود و این فایل را در جوملا به عنوان یک کامپوننت نصب کنید.

برای سادگی، این کامپوننت از روش جوملا 3 برای تعریف کامپوننت استفاده می‌کند که روی جوملا 5 کار نمی‌کند. اگر نسخه‌ای می‌خواهید که برای جوملا 5 مناسب باشد، می‌توانید فایل زیپ آماده را دانلود و نصب کنید.

فایل com_sample_form1.xml (فایل مانیفست کامپوننت)

 
<?xml version="1.0" encoding="utf-8"?>  
<extension type="component" version="3.1.0" method="upgrade">  

<name>com_sample_form1</name>  
<version>1.0.0</version>  
<description>Sample form 1</description>  

<administration>  
</administration>  

<files folder="site">  
<filename>sample_form1.php</filename>  
<filename>sample_form.xml</filename>  
</files>  
</extension>
 

 

 

فایل sample_form.xml (تعریف فرم به صورت XML)

 
<?xml version="1.0" encoding="utf-8"?> 

<form>  
<field  
name="message"  
type="text"  
label="Enter message"  
size="40"  
class="inputbox"  
required="true" />  
<field name="email"  
type="email"  
label="Enter email"  
required="true"  
size="40"  
class="inputbox" />  
<field name="telephone"  
type="telephone"  
label="Enter telephone number"  
required="true"  
size="40"  
class="inputbox"  
validate="tel" />  
</form>
 

 

فایل sample_form1.php (کد کامپوننت)

 
<?php  
defined('_JEXEC') or die('Restricted access');  

use Joomla\CMS\Form\Form;  
use Joomla\CMS\Factory;  

$form = Form::getInstance("sample", __DIR__ . "/sample_form.xml", array("control" => "myform"));  
$prefillData = array("email" => ".@.");  

if ($_SERVER['REQUEST_METHOD'] === 'POST')  
{  
$app   = JFactory::getApplication();  
$data = $app->input->post->get('myform', array(), "array");  
echo "Message was " . $data["message"] .  
", email was " . $data["email"] .  
", and telephone was " . $data["telephone"] . "<br>";  
$filteredData = $form->filter($data);  
$result = $form->validate($filteredData);  
if ($result)  
{  
echo "Validation passed ok<br>";  
}  
else  
{  
echo "Validation failed<br>";  
$errors = $form->getErrors();  
foreach ($errors as $error)  
{  
echo $error->getMessage() . "<br>";  
}  
// در فرم نمایش مجدد، مقادیر فیلتر شده‌ای که کاربر وارد کرده را نشان می‌دهیم  
$prefillData = $filteredData;  
}  
}  

$form->bind($prefillData);  
?>  
<form action="<?php echo JRoute::_('index.php?option=com_sample_form1'); ?>"  
    method="post" name="sampleForm" id="adminForm" enctype="multipart/form-data">  

<?php echo $form->renderField('message');  ?>  

<?php echo $form->renderField('email');  ?>  

<?php echo $form->renderField('telephone');  ?>  

<button type="submit">Submit</button>  
</form>
 

 

نکات استفاده

پس از نصب، به سایت خود رفته و پارامتر زیر را به آدرس اضافه کنید: 

?option=com_sample_form1

سپس باید فرم شامل سه فیلد اجباری نمایش داده شود:

- یک فیلد متنی عمومی برای پیام 

- یک فیلد ایمیل که به صورت پیش‌فرض مقدار ".@." را دارد 

- یک فیلد شماره تلفن

با استفاده از ابزارهای توسعه‌دهنده مرورگرتان می‌توانید ویژگی‌های HTML ایجاد شده را با مشخصات فایل XML فرم مقایسه کنید.

توجه داشته باشید مرورگرهای مدرن به شکل خودکار مقداری اعتبارسنجی انجام می‌دهند، مثلاً ایمیل را اعتبارسنجی می‌کنند و وارد کردن مقدار در فیلدهای دارای صفت "required" را اجباری می‌کنند، اما معمولاً اعتبارسنجی شماره تلفن را انجام نمی‌دهند.

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

الگوی MVC و سایر ملاحظات 

مقدمه

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

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

تقسیم‌بندی MVC در جوملا

به طور کلی، جوملا کامپوننت‌ها را به بخش‌های جداگانه‌ای تقسیم می‌کند:

- کنترلر (Controller): منطق تصمیم‌گیری را درباره نحوه پاسخ به درخواست HTTP در خود دارد، به‌خصوص مشخص می‌کند کدام View و Model باید استفاده شوند.

- نما (View): تعیین می‌کند کدام داده‌ها باید در صفحه وب نمایش داده شوند و به Model برای دریافت آن داده‌ها فراخوانی می‌کند.

- مدل (Model): دسترسی به داده‌ها را فراهم می‌کند.

- فایل tmpl: بخش فرعی از نما است (در قالب نمونه کلاس View اجرا می‌شود و به متغیر `$this` نمای View دسترسی مستقیم دارد). این فایل خروجی HTML کامپوننت را تولید می‌کند و داده‌هایی که توسط View گردآوری شده‌اند را نمایش می‌دهد. به صورت جداگانه نگهداری می‌شود تا بتوان خروجی HTML را از طریق قالب (Template override) به‌راحتی سفارشی کرد.

الگوی Post/Request/Get

در جوملا تمام خروجی HTML (مانند نمایش فرم) به صورت پاسخ به درخواست HTTP GET انجام می‌شود، که از الگوی Post/Redirect/Get پیروی می‌کند. کد نمونه بخش قبل این الگو را رعایت نمی‌کرد و در واکنش به POST، خطاهای اعتبارسنجی را نمایش می‌داد و فرم را دوباره می‌کشید.

برای رعایت الگوی جوملا، در کدی که POST را مدیریت می‌کند باید یک ریدایرکت HTTP GET به آدرس فرم اضافه شود. چون GET جدید یک درخواست/پاسخ HTTP تازه است، باید داده‌های لازم برای نمایش مجدد فرم (خطاها و داده‌های وارد شده) در جلسه کاربری ذخیره شوند:

- پیام‌های خطای اعتبارسنجی با استفاده از متد `enqueueMessage()` ذخیره و نمایش داده می‌شوند (که به طور خودکار داده را در session کاربر نگهداری می‌کند):

$app = Factory::getApplication();
$app->enqueueMessage('some message text');
 

- داده‌های وارد شده توسط کاربر با استفاده از `setUserState()` ذخیره و با `getUserState()` بازیابی می‌شوند، به همراه کلیدی یکتا برای این فرم، مثلاً:

$app->setUserState('com_sample_form2.sample', $data);

کدی که داده‌ها را برای متد bind فرم فراهم می‌کند باید ابتدا با `getUserState()` چک کند که آیا داده‌ای در سشن هست یا خیر، چون این داده‌ها همان مواردی است که کاربر پیش‌تر وارد کرده و باید دوباره نمایش داده شود.

همچنین اگر داده‌ها اعتبارسنجی را با موفقیت گذراندند، باید `setUserState()` را با مقدار null فراخوانی کنید تا داده‌های از پیش تکمیل شده پاک شوند؛ در غیر این صورت داده‌ها دوباره هنگام نمایش بعدی فرم ظاهر خواهند شد.

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

کنترلرهای جداگانه

جوملا درخواست‌های HTTP را بر اساس مقدار پارامتر `task` که در URL ارسال می‌شود، به کنترلرهای جداگانه مسیریابی (Routing) می‌کند. این پارامتر معمولاً توسط جاوااسکریپت هسته جوملا و بر اساس دکمه ارسال تنظیم می‌شود، مثلاً در مثال زیر:

onclick="Joomla.submitbutton('myform.submit')"

وقتی دکمه ارسال کلیک می‌شود، رویداد `onclick` تابع جاوااسکریپت `Joomla.submitbutton` را با پارامتر `'myform.submit'` فراخوانی می‌کند و این باعث می‌شود پارامتر `task` مقدار `"myform.submit"` دریافت کند.

به طور کلی مقدار پارامتر `task` شکل `<controller type>.<method>` دارد، و در این حالت درخواست HTTP POST حاوی داده‌های فرم توسط کنترلر `MyformController` و متد `submit` آن پردازش خواهد شد.

کلاس‌های MVC جوملا

جوملا کلاس‌های قدرتمند و دارای امکانات زیاد Controller، View و Model را فراهم می‌کند که کنترلرها، نماها و مدل‌های کامپوننت شما می‌توانند از آنها ارث‌بری کنند. کد مدل در `com_sample_form2` از کلاس `FormModel` ارث می‌برد که تا حدی API فرم جوملا (که در بخش قبل توضیح داده شد) را پوشش می‌دهد.

 

در این حالت، مدل ما متد `loadForm()` از `FormModel` را فراخوانی می‌کند و این متد به صورت callback متد `loadFormData()` ما را اجرا می‌کند تا داده‌هایی که باید به فرم bind شوند را فراهم کند. بنابراین در این کد، فراخوانی مستقیمی به `bind()` وجود ندارد.

توکن امنیتی(Security Token)

جوملا از توکن امنیتی در فرم‌ها برای جلوگیری از حملات CSRF استفاده می‌کند. توکن امنیتی در فایل لایه‌بندی (layout) فرم خروجی داده می‌شود:

 
$this->checkToken();

 

و در کنترلری که درخواست POST را مدیریت می‌کند، بررسی می‌شود:

 
$this->checkToken();
 

 اگر توکن نامعتبر تشخیص داده شود، متد `checkToken()` یک هشدار نمایش داده و کاربر را به صفحه قبلی ریدایرکت می‌کند.

اعتبارسنجی

موضوع اعتبارسنجی در بخش‌های بعدی پوشش داده می‌شود.

در ادامه، شرح و تبیین کد نمونه کامپوننت `com_sample_form2` که مطابق با الگوی MVC و ریدایرکت پس از ارسال پیاده‌سازی شده است، به فارسی آمده است:

کد نمونه

امکان دانلود و نصب این کامپوننت به صورت فایل زیپ وجود دارد. این کامپوننت عملکردی مشابه با `com_sample_form1` در بخش قبل دارد، اما طبق اصول گفته شده در مورد MVC طراحی مجدد شده است. اگرچه در نگاه اول پیچیده‌تر به نظر می‌رسد ولی وقتی کامپوننت بزرگ‌تر شد، باعث می‌شود کد بسیار قابل فهم‌تر و سازمان‌یافته‌تر باشد.

پس از نصب کامپوننت، به صفحه اصلی سایت خود رفته و پارامتر `?option=com_sample_form2` را به آدرس اضافه کنید تا کامپوننت اجرا شود.

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

نحوه عملکرد هر فایل در یک فرم

در اینجا توضیحاتی در مورد عملکرد هر فایل ارائه شده است.

 ساختار فایل‌ها و شرح مختصر کارکرد آنها

admin/services/provider.php 

یک فایل استاندارد مربوط به تزریق وابستگی (Dependency Injection) در جوملا است.

site/src/Controller/DisplayController.php

این کلاس کنترلری است که متد `display()` آن وقتی صفحه کامپوننت برای اولین بار باز می‌شود، اجرا می‌شود:

 
$model = $this->getModel('sample');  
$view = $this->getView('sample', 'html');  
$view->setModel($model, true);  
$view->display();
 

 

- `$model` و `$view` با نام "sample" ساخته می‌شوند. این رشته برای جوملا حکم Fully Qualified Name (FQN) یا نام کامل کلاس مدل و نما را دارد. 

- `setModel` صدا زده می‌شود تا مدل به کد نمای ویو ارجاع داده شده و `true` به معنای مدل پیش‌فرض است. 

- در انتها متد `display()` در نمای ویو فراخوانی می‌شود. 

نکته: این دو نمونه ساخته‌شده (`$model` و `$view`) در واقع توسط کلاس `MVCFactory` که در `services/provider.php` تعریف شده، ساخته می‌شوند.

 

site/src/View/Sample/HtmlView.php

در متد `display` نمای ویو:

 
$this->form = $this->getModel()->getForm();  
parent::display($tpl);

 

- ابتدا از مدل، فرم گرفته می‌شود (`getForm()`) 

- سپس `parent::display()` فراخوانی می‌شود که مسئول اجرای فایل template است (به طور معمول فایل `tmpl/default.php`)

site/src/Model/SampleModel.php

در مدل، متد `getForm()` به شکل زیر است:

 
$form = $this->loadForm(  
    'com_sample_form2.sample',  
    'sample_form',      // فایل XML تعریف فرم (پوشه site/forms)  
    array(  
        'control' => 'jform',   // نام آرایه پارامترهای POST  
        'load_data' => $loadData // اگر true باشد، فراخوانی loadFormData انجام می‌شود  
    )  
);

 

- متد `loadForm` (تعریف شده در `libraries/src/MVC/Model/FormModel.php`) از `FormBehaviorTrait` استفاده می‌کند 

- فرم جوملا ساخته شده، فایل XML فرم (در `site/forms/sample_form.xml`) بارگزاری می‌شود 

- اگر `load_data` مقدار true داشته باشد، بابت تهیه داده‌ها، متد `loadFormData()` فراخوانی می‌شود:

 
$data = Factory::getApplication()->getUserState(  
    'com_sample_form2.sample',  
    array("email" => ".@.")  
);
 

 - اینجا داده‌های فرم از سشن جوملا با کلید `com_sample_form2.sample` خوانده می‌شود، اگر نباشد پیش‌فرض مقدار `email` برابر با ".@." قرار می‌گیرد. 

نکته: با فعال کردن حالت Debug سیستم جوملا، می‌توانید در صفحه، داده‌های سشن را مشاهده کنید.

site/tmpl/sample/default.php

 
<form action="<?php echo Route::_('index.php?option=com_sample_form2'); ?>"  
    method="post" name="adminForm" id="adminForm" enctype="multipart/form-data">  

<?php echo $this->form->renderField('message');  ?>  
<?php echo $this->form->renderField('email');  ?>  
<?php echo $this->form->renderField('telephone');  ?>  

<button type="button" class="btn btn-primary" onclick="Joomla.submitbutton('myform.submit')">Submit</button>  

<input type="hidden" name="task" />  
<?php echo HtmlHelper::_('form.token'); ?>  
</form>
 

 

نکات مهم در این فرم:

1. صفت action فرم: 

آدرس ارسال فرم به همان کامپوننت ما برمی‌گردد (`com_sample_form2`). وقتی فرم ارسال شود، آدرس به این کامپوننت اشاره می‌کند.

2. رندر کردن فیلدها: 

هر فیلد فرم با استفاده از متد `renderField` از شیء فرم که نمای View در `$this->form` دارد رندر شده‌اند.

3. دکمه ارسال: 

دکمه ارسال دارای listener روی `onclick` است که وقتی کلیک شود، تابع جاوااسکریپت `Joomla.submitbutton('myform.submit')` فراخوانی می‌شود. 

   این باعث می‌شود پارامتر `task` در URL به مقدار `'myform.submit'` تنظیم شود.

4. فیلد مخفی task: 

   برای اینکه جوملا بفهمد کدام اکشن باید اجرا شود، یک فیلد مخفی با نام `task` در فرم داریم.

5. توکن امنیتی (CSRF Token): 

توکن امنیتی جهت جلوگیری از حملات جعل درخواست (CSRF) با دستور `HtmlHelper::_('form.token')` در فرم گنجانده شده و همراه درخواست POST ارسال می‌شود. در سمت کنترلر باید اعتبار آن بررسی شود.

فایل کنترلر ارسال فرم: 

`site/src/Controller/MyformController.php`

روند کلی متد submit در کنترلر:

 
$this->checkToken();
 

 

- ابتدا توکن امنیتی فرم چک می‌شود. اگر توکن نادرست باشد، ارسال فرم رد شده و کاربر به صفحه قبلی هدایت می‌شود.

 
$model = $this->getModel('sample');
$form = $model->getForm(null, false);
 

- مدل فرم به نام 'sample' بارگذاری می‌شود. تنها فرم دریافت می‌شود بدون پر کردن دیتا (پارامتر دوم false است تا callback از پیش تکمیل کردن داده انجام نشود).

 
// آرایه داده‌های ارسال شده باید نامش با 'control' در مدل هماهنگ باشد (اینجا jform) 
$data  = $this->input->post->get('jform', array(), 'array');
 

 

- اطلاعات ارسال شده در فرم (POST) از آرایه‌ی `jform` دریافت می‌شود.

// اعتبارسنجی فرم با استفاده از متد validate مدل (که هم فیلترینگ و هم اعتبارسنجی را انجام می‌دهد) 
$validData = $model->validate($form, $data);

 

رفتار بعد از اعتبارسنجی:

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

 
if ($validData === false)  
{  
    $errors = $model->getErrors();  

    foreach ($errors as $error)  
    {  
        if ($error instanceof \Exception)  
        {  
            $app->enqueueMessage($error->getMessage(), 'warning');  
        }  
        else  
        {  
            $app->enqueueMessage($error, 'warning');  
        }  
    }  

    // ذخیره داده‌های فرم در جلسه کاربر با شناسه یکتا  
    $app->setUserState('com_sample_form2.sample', $data);  
}  
else  
{  
    $app->enqueueMessage("Data successfully validated", 'notice');  
    // پاکسازی داده‌های فرم ذخیره‌شده در جلسه کاربر  
    $app->setUserState('com_sample_form2.sample', null);  
}

 

توضیح روند عملکرد

- اگر داده‌ها نامعتبر باشند (`$validData === false`)، ابتدا پیام‌های خطا از مدل گرفته می‌شود و با استفاده از متد `enqueueMessage` به عنوان هشدار (warning) به کاربر نمایش داده می‌شود. این پیام‌ها می‌توانند یا اشیاء استثنا (`Exception`) باشند یا متن ساده، که در هر دو حالت به درستی نمایش داده می‌شوند.

- سپس داده‌هایی که کاربر وارد کرده در نشست (Session) ذخیره می‌شود تا در نمایش مجدد فرم، فرم با همان داده‌های قبلی پر شود و کاربر مجبور به وارد کردن مجدد اطلاعات نشود. ذخیره داده‌ها با کلید یکتای `'com_sample_form2.sample'` انجام می‌شود.

- اگر داده‌ها اعتبارسنجی شده و صحیح باشند، پیام موفقیت (`Data successfully validated`) نمایش داده می‌شود و داده‌های فرم ذخیره‌شده در جلسه پاکسازی می‌شود؛ بنابراین بار بعدی که فرم نمایش داده شود، داده‌های پیش‌فرض خالی نمایش داده می‌شود.

در نهایت، برای رعایت الگوی Post/Redirect/Get، در همه حالتها (چه در صورت خطا و چه موفقیت) درخواست به همان فرم برگشت داده می‌شود:

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

این کار باعث می‌شود پس از ارسال فرم، صفحه مجدداً به صورت یک درخواست GET بارگذاری شود، که این فرآیند جلوی ارسال دوباره داده‌ها هنگام رفرش صفحه و مشکلات مشابه را می‌گیرد و تجربه کاربری بهتری ایجاد می‌کند.

اعتبارسنجی سمت سرور (Server-side Validation)

جوملا چارچوبی برای پیاده‌سازی اعتبارسنجی هم در سمت کلاینت (مرورگر) و هم در سمت سرور فراهم می‌کند.

- اعتبارسنجی سمت کلاینت به کمک جاوااسکریپت انجام می‌شود که همراه صفحه وب به مرورگر کاربر ارسال شده و در آنجا اجرا می‌شود. 

- اعتبارسنجی سمت سرور در زبان PHP و روی سرور انجام می‌شود، زمانی که داده‌های فرم از طریق درخواست HTTP POST به سرور ارسال می‌شوند.

از این دو نوع اعتبارسنجی، اعتبارسنجی سمت سرور اهمیت بیشتری دارد، زیرا هکرها می‌توانند با استفاده از ابزارهایی مثل `curl` یا نرم‌افزارهای مشابه، داده‌ها را مستقیماً به سرور ارسال کنند و اعتبارسنجی سمت کلاینت را دور بزنند.

نحوه فعالسازی اعتبارسنجی سمت سرور در جوملا

در تعریف فایل XML فرم (فرم دیفینیشن)، با اضافه کردن ویژگی `validate="..."` به تگ فیلد (field) می‌توان اعتبارسنجی سمت سرور را مشخص کرد.

برای مثال، در فرم نمونه قبلی، فیلد شماره تلفن اینگونه تعریف شده است:

 
<field name="telephone"  
    type="telephone"  
    label="Enter telephone number"  
    required="true"  
    size="40"  
    class="inputbox"  
    validate="tel" />
 

 

خط `validate="tel"` باعث می‌شود اعتبارسنجی شماره تلفن در این فیلد فعال شود. این اعتبارسنجی با استفاده از تابع `test` در کلاس `TelRule` که در مسیر `libraries/src/Form/Rule` قرار دارد انجام می‌شود؛ این تابع بررسی می‌کند که مقدار وارد شده در فیلد معتبر باشد.

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

جوملا مجموعه‌ای از قوانین آماده اعتبارسنجی را در مسیر `libraries/src/Form/Rule` دارد، هر یک از این کلاس‌ها مسئول اعتبارسنجی نوع خاصی از داده‌ها هستند.

برای مثال، اگر بخواهید فیلد ایمیل را اعتبارسنجی کنید، می‌توانید در تعریف فیلد مربوطه صفت `validate="email"` را قرار دهید تا قانون `EmailRule` اجرا شود.

مراحل افزودن قانون اعتبارسنجی سفارشی در جوملا

1. اضافه کردن صفت validate به فیلد در فایل XML فرم

در تعریف فیلد، صفت `validate="custom"` (یا هر نام دلخواه که برای قانونتان انتخاب کردید) را مشخص کنید.

همچنین به کمک صفت `addruleprefix` به جوملا اعلام کنید کلاس قانون اعتبارسنجی خود را از کجا بارگذاری کند.

مثال کامل برای فیلدی به نام تلفن:

 
<field   
    addruleprefix="Mycompany\Component\Example\Administrator\Rule"  
    name="telephone"  
    type="telephone"  
    label="Enter telephone number"  
    required="true"  
    size="40"  
    class="inputbox"  
    validate="custom"  
    message="The telephone number field is wrong" />
 

 

توجه کنید تنظیم `addruleprefix` مسیر Namespace کلاس قانون اعتبارسنجی شما را مشخص می‌کند.

2. نوشتن کلاس قانون اعتبارسنجی (CustomRule.php)

- فایل را در مسیر `src/Rule/CustomRule.php` در پوشه ادمین کامپوننت ذخیره کنید.

administrator/components/com_example/src/Rule/CustomRule.php 

- نام فضا (Namespace) باید مطابق با `addruleprefix` که در فایل XML تعریف کردید باشد:

 
namespace Mycompany\Component\Example\Administrator\Rule;  
use Joomla\CMS\Form\FormRule;  
class CustomRule extends FormRule  
{  
    // اگر می‌توانید از regex استفاده کنید، ساده‌ترین روش همین است:  
    protected $regex = '^[0-9\*\#]+$';  // فقط ارقام و * و # مجاز است  
    // یا اگر لازم است اعتبارسنجی پیچیده‌تری انجام دهید، متد test را بازنویسی کنید:  
    /*  
    public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null)  
    {  
        // اجرای اعتبارسنجی شما روی مقدار $value  
        // دسترسی به اطلاعات فرم و سایر پارامترها از طریق ورودی های متد امکان‌پذیر است  
        // اگر مقدار معتبر بود، true، در غیر این صورت false برگردانید  
        if ( /* شرط اعتبارسنجی شما */ ) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
    */  
}
 

 

توضیحات:

- کلاس می‌تواند از کلاس `FormRule` ارث‌بری کند و تنها با بازنویسی متغیر `$regex` یک قانون ساده نظم‌دهی شده توسط عبارت‌های منظم (Regular Expression) بسازد. 

- اگر اعتبارسنجی شما پیچیده‌تر است، روش `test` را بازتعریف کنید. این متد مقداری که باید اعتبارسنجی شود، اطلاعات فرم، گروه‌ها و سایر جزئیات را می‌گیرد و باید مقدار بولی برگرداند.

3. موارد مهم در متد `test`:

پارامترهای متد به شرح زیر هستند:

 
public function test(  
    \SimpleXMLElement $element, // تعریف XML فیلد (فیلد فرم)  
    $value,                    // مقدار ورودی برای اعتبارسنجی  
    $group = null,             // گروه نام فیلد (اگر وجود داشته باشد)  
    Registry $input = null,    // شیء رجیستری حاوی کل داده‌های فرم  
    Form $form = null          // شیء فرم کامل  
) { ... }
 

 

- می‌توانید ویژگی‌های سفارشی تعریف شده در فایل XML را از طریق `$element` بخوانید (مثلاً اگر مقدار خاصی در XML برای قانونتان تنظیم کرده‌اید).

- پس از پیاده‌سازی اعتبارسنجی، باید `true` یا `false` برگردانید؛ `true` یعنی مقدار معتبر است و `false` یعنی اعتبارسنجی ناموفق بوده است.

بررسی‌های اضافی جوملا در اعتبارسنجی فیلدها

- اگر در تعریف فیلد در XML، صفت `required` تنظیم شده باشد، جوملا بررسی می‌کند که برای آن فیلد حتما مقداری وارد شده باشد (خالی نباشد).

- اگر صفت `disabled` تنظیم شده باشد، جوملا تأیید می‌کند که مقدار ارسال شده، مقدار پیش‌فرض یا غیرفعال نباشد (معمولا اجازه تغییر داده نمی‌شود).

پیام خطاهای اعتبارسنجی

- به صورت پیش‌فرض، در صورت شکست اعتبارسنجی، جوملا پیام عمومی `"Invalid Field"` را نمایش می‌دهد.

- برای تعریف پیام خطای مشخص و سفارشی، می‌توانید از صفت `message` در المان فیلد در XML استفاده کنید:

 
<field  
    name="telephone"  
    ...  
    message="Wrong telephone number" />
 

- همچنین امکان تغییر پیام خطا در زمان اجرا (داخل کد اعتبارسنجی) وجود دارد. چون المان XML فیلد به متد `test` پاس داده می‌شود، می‌توانید مقدار `message` را در آن تغییر دهید.

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

 
<?php  
namespace Mycompany\Component\SampleForm2\Site\Rule;  

defined('_JEXEC') or die('Restricted access');  

use Joomla\CMS\Form\FormRule;  
use Joomla\Registry\Registry;  
use Joomla\CMS\Form\Form;  

class TelephoneRule extends FormRule  
{  
    // فقط ارقام، # و * مجازند  
protected $regex = '^[0-9\#\*]+$';  

    public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null)  
    {  
        // بررسی مقدار ورودی طبق regex  
        if (preg_match(\chr(1) . $this->regex . \chr(1) . $this->modifiers, $value)) {  
            return true; // معتبر است  
        }  
        
        // در صورت نامعتبر بودن، پیام خطای سفارشی می‌سازیم  
        $attr = $element->attributes();  
        $error_message = 'The telephone number ' . $value . ' is wrong';  
        
        // اگر صفت message از قبل وجود دارد، مقدار آن را تغییر می‌دهیم، در غیر این صورت اضافه می‌کنیم  
        if (isset($attr['message'])) {  
            $element->attributes()->message = $error_message;  
        } else {  
            $element->addAttribute('message', $error_message);  
        }  
        
        // مقدار نامعتبر است  
        return false;  
    }  
}

 

توضیح: 

- متد `test()` مقدار ورودی را بررسی می‌کند. اگر معتبر بود `true` برمی‌گرداند. 

- در صورت نامعتبر بودن، پیام خطای سفارشی می‌سازد و در صفت `message` المان XML قرار می‌دهد تا هنگام نمایش خطا، از این پیام استفاده شود. 

- متغیر `$this->modifiers` می‌تواند مقدار `i` (ignore case) یا خالی باشد و از کلاس `FormRule` به ارث برده می‌شود. 

- `\chr(1) ` کاراکتر جداکننده برای فرمول regex در تابع `preg_match` است (شکل استاندارد برای کار با regex در جوملا).

تأیید اعتبار سمت کاربر

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

می‌توانید تأیید اعتبار سمت کاربر را با انجام ۳ مرحله زیر در فرم‌های خود پیاده‌سازی کنید:

1. اضافه کردن کتابخانه جاوااسکریپت validate جوملا از طریق Web Asset Manager:

 
Factory::getApplication()->getDocument()->getWebAssetManager()->useScript('form.validate');

 

اگر این خط را در یک فایل tmpl می‌نویسید، معمولاً سند (Document) در دسترس است:

 
$this->document->getWebAssetManager()->useScript('form.validate');
 

 این خط باعث می‌شود فایل `media/system/js/fields/validate.js` به مرورگر کاربر ارسال شود.

2. اعلام اینکه می‌خواهید تأیید اعتبار روی فرم انجام شود با افزودن کلاس  `form-validate` به فرم:

 
<form class="form-validate"> ... </form>

 

3. مشخص کردن نوع تأیید اعتبار برای هر فیلد فرم. این کار در فایل XML تعریف فرم با افزودن کلاس‌های `validate-...` به فیلد انجام می‌شود. برای مثال، اگر بخواهید فیلد شماره تلفن فقط عددی باشد:

 
<field   
    name="telephone"  
    type="telephone"  
    class="inputbox validate-numeric"  
    …  
/>
 

انواع تأیید اعتبار قابل استفاده عبارتند از:

- validate-username

- validate-password

- validate-numeric

- validate-email

تمام این‌ها از عبارات منظم (regex) جاوااسکریپت برای بررسی مقدار وارد شده استفاده می‌کنند. (اگر نیاز به بررسی جزئیات regex داشتید، می‌توانید در فایل `media/system/js/fields/validate.js` و درون سازنده کلاس `JFormValidator` نگاه کنید).

توجه داشته باشید که اگر از فیلدی با نوع `email` استفاده کنید، کلاس `validate-email` به صورت خودکار اضافه خواهد شد. (با این حال، باید مراحل ۱ و ۲ را برای عملکرد آن انجام دهید).

همچنین اگر فیلد را به صورت `required="true"` تعریف کنید، جاوااسکریپت بررسی می‌کند که حتماً مقداری در آن وارد شده باشد، مثلاً:

 
<field 
    name="telephone"
    type="telephone"
    required="true"
    …
/>
 

 تأیید اعتبار هر زمان که روی دکمه‌ای مربوط به ذخیره‌سازی داده فرم کلیک شود، انجام می‌شود، برای مثال:

 
<button type="button" class="btn btn-primary" onclick="Joomla.submitbutton('myform.submit')">Submit</button>
 

و تأیید اعتبار در داخل تابع جاوااسکریپت `Joomla.submitbutton` اجرا می‌شود.

همچنین ممکن است دکمه‌ای برای لغو وجود داشته باشد که تأیید اعتبار را فعال نکند:

<button type="button" class="btn btn-primary" onclick="Joomla.submitbutton('myform.cancel')">Cancel</button>

وقتی دکمه‌های نوار ابزار ایجاد می‌شوند، تنها دکمه‌هایی که مربوط به ذخیره داده هستند، صفت کلاس `form-validation` به عنصر HTML آن‌ها اضافه می‌شود. زمانی که دکمه‌ای فشار داده شود، کلاس آن بررسی می‌شود. اگر کلاس `form-validation` وجود داشته باشد، تابع `Joomla.submitbutton` با پارامتر `validate` برابر با `true` فراخوانی می‌شود، و در غیر این صورت با `validate` برابر با `false` خواهد بود.

اعتبارسنجی سفارشی با استفاده از الگو (pattern)

برای فیلدهایی مانند `type="text"` و `type="telephone"` که مربوط به عنصر `<input>` در HTML هستند، می‌توانید یک عبارت منظم (regex) جاوااسکریپت تعریف کنید که داده وارد شده توسط کاربر باید با آن مطابقت داشته باشد. برای مثال:

 
<field   
    name="message"  
    type="text"  
    pattern="[^x]+"  
    ... />
 

این عبارت باعث رد شدن داده‌هایی می‌شود که درونشان حرف "x" وجود داشته باشد.

توجه داشته باشید این فقط روی اعتبارسنجی سمت کاربر تأثیر دارد و هیچ تأثیری روی اعتبارسنجی سمت سرور ندارد!

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

می‌توانید تابع اعتبارسنجی خود را به صورت جاوااسکریپت بنویسید. کامپوننت نمونه `com_exampleform` (که می‌توانید آن را دانلود کنید) یک مثال عملی از اعتبارسنجی سمت کاربر ارائه می‌دهد.

مرحله 1: نوشته تابع جاوااسکریپت

(اگرچه در مثال زیر از regex استفاده شده، اما محدود به آن نیستید.) مقدار فیلد به پارامتر `value` داده می‌شود و شما باید اگر مقدار معتبر بود `true` و در غیر اینصورت `false` برگردانید.

 

مثال `no-uppercase.js`:

 
window.onload = (event) => {  
    document.formvalidator.setHandler('noUppercase',  
        function (value) {  
            // جستجو برای حروف بزرگ  
            regex=/[A-Z]/g;  
            // اگر حروف بزرگ یافت شد، رد اعتبارسنجی  
            return !regex.test(value);  
        });  
};

 

تمام فایل‌های js را باید در پوشه `media` ذخیره کنید؛ مثلاً `media/js/no-uppercase.js` در ساختار توسعه کامپوننت شما.

مرحله 2: افزودن فایل js به لیست اسکریپت‌ها

فرض کنید در حال نوشتن برای کامپوننت `com_example` هستید؛ فایل js را در `media/joomla.asset.json` به این صورت اضافه کنید (وابسته به `form.validate`):

 
{  
  "name": "com_example.validate-no-uppercase",  
  "type": "script",  
  "uri": "com_example/no-uppercase.js",  
  "dependencies": [  
    "form.validate"  
  ],  
  "attributes": {  
    "defer": true  
  },  
  "version": "1.0.0"  
}
 

مرحله 3: استفاده از اسکریپت در قالب (tmpl)

در فایل قالب خود این اسکریپت را فراخوانی کنید:

 
$this->document()->getWebAssetManager()->useScript('com_example.validate-no-uppercase');
 

مرحله 4: اعمال اعتبارسنجی روی فیلد در فایل XML فرم

در فایل XML فرم، فیلدی که می‌خواهید اعتبارسنجی سفارشی روی آن اعمال شود را با کلاس `validate-noUppercase` مشخص کنید. این کلاس باید بعد از حذف پیشوند `validate-` با پارامتر اولین مرحله (`setHandler`) مطابقت داشته باشد:

 
<field   
    name="message"  
    type="text"  
    class="inputbox validate-noUppercase"  
    ... />
 

 همانطور که گفته شد، این اعتبارسنجی فقط سمت کاربر است و روی اعتبارسنجی سمت سرور تاثیری ندارد!

مدیریت فرم‌ها

مقدمه

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

- تعیین مسیر فایل برای اینکه جوملا بتواند تعریف فرم شما را پیدا کند، در صورتی که استانداردهای معمول جوملا را دنبال نکنید.

- تعریف گروه‌بندی‌های فیلدها — جوملا دو نوع گروه‌بندی اصلی ارائه می‌دهد: Fieldsetها و Field Groupها.

- تغییر داینامیک (پویا) فرم پس از اینکه از فایل XML بارگذاری شد.

- روش‌های بازتابی (reflection-like) برای استخراج اطلاعات از ساختار و داده‌های فرم.

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

مسیر فایل‌ها (File Paths)

به طور پیش‌فرض، جوملا فرم‌ها را در پوشه `…/forms` کامپوننت شما جستجو می‌کند تا تعریف XML فرم را پیدا کند (و همچنین در `…/models/form` برای سازگاری با جوملا ۳)، در فایل‌های سایت اگر فرم در بخش جلویی (Front-end) نمایش داده شود، و در پوشه‌های administrator اگر فرم در بخش مدیریت (Back-end) نمایش داده شود.

تابع استاتیک `addFormPath()` به شما امکان می‌دهد مسیر یا پوشه‌ای غیر از پوشه‌های پیش‌فرض را به لیست پوشه‌هایی که جوملا برای فرم‌ها جستجو می‌کند اضافه کنید.

به همین ترتیب:

- `addFieldPath()` مسیر دلخواه برای تعریف فیلدهای سفارشی فرم را مشخص می‌کند (پیش فرض در جوملا ۳: `…/models/fields`)

- `addRulePath()` مسیر دلخواه برای تعریف قوانین اعتبارسنجی سفارشی را تعیین می‌کند (پیش فرض در جوملا ۳: `…/models/rules`)

اما در جوملا ۴ با معرفی namespace، اضافه کردن attributes مانند `addfieldprefix` و `addruleprefix` در فرم آسان‌تر شده تا جوملا بتواند فیلدها و قوانین سفارشی را پیدا کند.

Fieldsets (مجموعه فیلدها)

Fieldsetها مربوط به عنصر `<fieldset name="myfieldset">` در تعریف XML فرم هستند. مزیت استفاده از fieldsets این است که در فایل قالب (layout) می‌توانید به جای فراخوانی جداگانه `renderField()` برای هر فیلد، برای کل مجموعه از کد زیر استفاده کنید:

$form->renderFieldset("myfieldset");

که تمام فیلدهای داخل بازه `<fieldset>` را خروجی می‌دهد.

Fieldset را می‌توان به مجموعه‌ای از فیلدها تشبیه کرد که باید با هم نمایش داده شوند، و مشابه عنصر`<fieldset>` درHTML   است. ولی توجه کنید که `renderFieldset()` تگ <fieldset>` درHTML   یا تگ‌های مرتبط را تولید نمی‌کند.

Field Groups (گروه‌های فیلد)

Field groups مربوط به عنصر `<fields name="mygroup">` در تعریف XML فرم هستند. این موضوع روی مقدار ویژگی نام `name` در تگ‌های ورودی HTML (input) تأثیر می‌گذارد و بدین ترتیب نام پارامترهای ارسالی از طریق فرم (POST) را تعیین می‌کند.

اگر هنگام ساخت فرم گزینه ` "control" => "myform"` را تنظیم کنید، ورودی‌ها به این شکل به سرور ارسال می‌شوند:

myform[field1]
myform[field2]
myform[field3]

 

اما اگر این فیلدها را داخل تگ `<fields name="mygroup">` قرار دهید، پارامترهای POST به این صورت ارسال خواهند شد:

myform[mygroup][field1]
myform[mygroup][field2]
myform[mygroup][field3]

 

اگر کامپوننت شما دارای جدول دیتابیس است و چندین پارامتر را به صورت رشته JSON در یک ستون ذخیره می‌کنید، می‌توانید فیلدهای مرتبط را داخل `<fields>` با نام ستون مربوطه گروه‌بندی کنید. این کار باعث می‌شود تبدیل آرایه‌های ترتیبی PHP که از پارامترهای POST تشکیل می‌شوند، به رشته JSON و ذخیره آن در دیتابیس بسیار آسان شود.

پارامتر `$group` که در چندین متد API فرم وجود دارد، اشاره به مقدار `name` تگ `<fields>` در XML فرم دارد.

نکته مهم

Fieldsets و Field Groups مستقل از هم هستند. در فایل XML فرم می‌توانید:

- تگ‌های `<fields>` را داخل `<fieldset>` قرار دهید

- یا بالعکس، `<fieldset>` را داخل `<fields>` بگذارید.

تغییر داینامیک (پویا) فرم‌ها

اگر فرم خود را به صورت استاتیک در یک فایل XML تعریف کرده‌اید، پس از بارگذاری فرم می‌توانید در کد PHP خود به صورت داینامیک آن را تغییر دهید. برای این کار از امکانات API فرم جوملا استفاده می‌شود؛ عملیاتی نظیر:

- افزودن فیلدهای جدید با بارگذاری یک فایل تعریف فرم جدید (XML),

- تغییر فیلد یا فیلدهای موجود،

- حذف یک فیلد یا گروهی از فیلدها.

افزودن فیلدها از طریق تعریف فرم

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

 
$form->loadFile($filename);
 

 

که در آن `$filename` مسیر فایل XML است که ساختاری مشابه فایل اصلی فرم دارد.

همچنین می‌توانید از یک شیء `SimpleXMLElement` استفاده کرده و آن را مستقیماً بارگذاری کنید:

$form->load($xml);

(در واقع `loadFile()` ابتدا فایل را می‌خواند و داخل `SimpleXMLElement` قرار می‌دهد و سپس `load()` را فراخوانی می‌کند).

 هر دو متد امکان دریافت پارامترهای اضافی دارند:

- `$replace` (در متد `load()`) یا `$reset` (در `loadFile()`): اگر در فرم بارگذاری شده فیلدی با نام مشابه فیلدی قبلی وجود داشته باشد، در صورت `true` شدن مقدار، فیلد جدید جایگزین قبلی می‌شود؛ در غیر این صورت فیلد جدید نادیده گرفته خواهد شد.

- `$xpath`: برای بارگذاری فقط بخشی از ساختار XML، می‌توانید xpath آن بخش را مشخص کنید تا فقط همان قسمت بارگذاری شود.

تغییر داینامیک فیلدها

برای افزودن یا جایگزینی یک فیلد می‌توانید از متد `setField()` استفاده کنید:

 
$xml = new SimpleXMLElement('<field name="newfield" ... />');
$form->setField($xml);
 

همچنین برای افزودن یا تغییر چند فیلد به صورت همزمان می‌توانید از متد `setFields()` استفاده کنید که آرایه‌ای از عناصر XML مربوط به فیلدها را می‌پذیرد.

پارامترهای `$group` و `$fieldset` را می‌توانید مشخص کنید تا فیلد جدید در گروه فیلدی یا fieldset خاصی قرار گیرد.

پارامتر `$replace` مشخص می‌کند که آیا در صورت وجود فیلد با همان نام و گروه، فیلد جدید جایگزین شود یا نادیده گرفته شود.

تنظیم ویژگی‌ها و مقادیر فیلدها

- `setFieldAttribute()` امکان تغییر یا افزودن یک ویژگی (attribute) مربوط به فیلد در تعریف فرم جوملا را می‌دهد. توجه کنید که این ویژگی‌ها مربوط به ویژگی‌های خود فیلد جوملا هستند، نه ویژگی‌های HTML.

مثال: برای تنظیم ویژگی placeholder در HTML باید ویژگی hint در فیلد جوملا را تنظیم کنید که البته فقط برای فیلدهایی که از این ویژگی پشتیبانی می‌کنند موثر است.

- مقدار HTML مربوط به `value` کمی متفاوت است؛ چون داده‌ی پیش‌فرض تعریف شده در فرم (که در XML فرم مشخص شده) از طریق `setFieldAttribute()` قابل تنظیم است ولی مقدار واقعی فیلد هنگام رندر شدن فرم از طریق داده‌های pre-fill که به متد `bind()` داده می‌شود، تعیین می‌شود.

برای تغییر داده pre-fill فیلد باید از متد `setValue()` استفاده شود.

حذف فیلدها

حذف فیلد از تعریف فرم با متد زیر امکان‌پذیر است:

- `removeField($name, $group = null)` برای حذف یک فیلد خاص؛

- `removeGroup($group)` برای حذف تمام فیلدهای یک گروه خاص.

روش‌های بازتابی (Reflection Methods) در فرم جوملا

جوملا مجموعه‌ای از متدها را برای دسترسی به جنبه‌های مختلف داده‌ها و ساختار نمونه فرم (Form instance) فراهم کرده است. بیشتر این متدها ساده و قابل فهم هستند، اما در ادامه مواردی که ممکن است کمی پیچیده‌تر باشد توضیح داده می‌شود.

متدهای اصلی

- getData()

این متد داده‌های pre-fill فرم را که قبلاً با فراخوانی متد `bind()` به فرم داده شده‌اند، به صورت یک شیء از کلاس `Joomla\Registry\Registry` برمی‌گرداند. یعنی داده‌های ورودی فرم که برای پرکردن اولیه فرم استفاده شده‌اند.

- getField($name, $group = null)

این متد یک فیلد مشخص از فرم را به صورت شیء `FormField` برمی‌گرداند. توجه کنید که این شیء نمایشی از فیلد است و متفاوت از نحوه داخلی ذخیره فیلدها در فرم است.

- getFieldset($name) و getGroup($name)

مشابه `getField`، این‌ها مجموعه‌ای از فیلدها (به صورت `FormField` ها) را بازمی‌گردانند که در یک fieldset یا در یک گروه فیلد (field group) در فرم قرار دارند.

- getFieldsets()

این متد تمام fieldsetهای فرم را به صورت آرایه‌ای از اشیاء Fieldset بازمی‌گرداند، که هر شیء ویژگی‌هایی دارد که به تگ `<fieldset>` در فایل تعریف فرم مرتبط است.

مثال:

 
$fieldsets = $form->getFieldsets();  
echo $fieldsets['myfieldset']->label;        // خروجی: مقدار attribute label (مثلاً "myfieldsetLabel")  
echo $fieldsets['myfieldset']->description;  // خروجی: مقدار attribute description

 

- getFormControl()

مقدار رشته‌ای که به پارامتر `control` (مثلاً ` "control" => "jform"`) هنگام ساخت نمونه فرم داده‌اید را برمی‌گرداند.

اگر استاندارد جوملا یعنی ` "control" => "jform"` را استفاده کرده باشید، این متد رشته `"jform"` را بازمی‌گرداند.

- getInput($name, $group = null) و getLabel($name, $group = null)

این متدها به ترتیب کد HTML مربوط به تگ `<input>` و `<label>` یک فیلد مشخص را برمی‌گردانند.

- توجه: این متدها برای فیلدهای سفارشی (Custom Field) کار نمی‌کنند و با متدهای `getInput()` و `getLabel()` مربوط به خود فیلد (که برای فیلدهای سفارشی باید تعریف کنید) متفاوت خواهند بود.

- getValue($name, $group = null)

مقدار (value) فعلی یک فیلد مشخص را برمی‌گرداند که از داده‌های pre-fill (اطلاعات داده شده در `bind()`) خوانده می‌شود.

- نکته: مقدار default که در خود تعریف فیلد وجود دارد (attribute default که در فایل XML تعریف شده) در این متد لحاظ نمی‌شود. فقط اگر داده pre-fill وجود نداشته باشد، مقدار default در خروجی HTML به کار می‌رود.

فایل نمونه کامپوننت

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

- این کامپوننت الگوی استاندارد MVC جوملا را دنبال نمی‌کند و همه چیز در یک کلاس به نام Extension قرار داده شده است.

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

نحوه استفاده

پس از نصب کامپوننت:

- به صفحه اصلی سایت خود بروید.

- پارامتر `?option=com_sample_form3` را به URL صفحه اضافه کنید.

مثلاً:

https://yoursite.com/index.php?option=com_sample_form3

این کار فرم را نمایش می‌دهد که می‌توانید داده‌ها را وارد و ارسال کنید.

کد نمونه همراه با توضیحات خوبی است که روند کار را به خوبی نشان می‌دهد.