مرحله ۱۱: راه‌اندازی سرور به‌روزرسانی

در این مرحله یک سرور به‌روزرسانی برای ماژول mod_hello فراهم می‌کنیم. بهتر است ابتدا درباره سرورهای به‌روزرسانی (Update Servers) مطالعه کنید.

کد منبع این مرحله در mod_hello مرحله 11 موجود است.

( https://github.com/joomla/manual-examples/tree/main/module-tutorial/step11_update_server)

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

برای مثال، اگر وب‌سروری مثل WAMP یا XAMPP روی کامپیوتر خودتان نصب کرده‌اید، می‌توانید یک پوشه به نام "updateserver" داخل پوشه جوملای خود بسازید.

در این آموزش فرض می‌کنیم که پوشه جوملا شما "joom" نام دارد؛ اگر نام دیگری دارید باید آن را تغییر دهید.

ویرایش فایل مانیفست برای ارتباط با سرور به‌روزرسانی

برای مرتبط کردن mod_hello با سرور به‌روزرسانی باید خطوط زیر را به فایل مانیفست (manifest) اضافه کنید:

 
<updateservers>
    <!-- آدرس زیر را مطابق با آدرس محیط توسعه‌ی به‌روزرسانی خود تغییر دهید -->
    <server type="extension" name="Hello Module Updates">http://localhost/joom/updateserver/updates.xml</server>
</updateservers>
 

فایل مانیفست mod_hello به‌روزرسانده‌شده

 
<?xml version="1.0" encoding="UTF-8"?>
<extension type="module" client="site" method="upgrade">
    <name>MOD_HELLO_NAME</name>
    <!-- highlight-next=line -->
    <version>1.0.11</version>
    <author>me</author>
    <creationDate>today</creationDate>
    <description>MOD_HELLO_DESCRIPTION</description>
    <namespace path="src">My\Module\Hello</namespace>
    <files>
        <folder module="mod_hello">services</folder>
        <folder>src</folder>
        <folder>tmpl</folder>
        <folder>language</folder>
    </files>
    <scriptfile>script.php</scriptfile>
    <media destination="mod_hello" folder="media">
        <filename>joomla.asset.json</filename>
        <folder>js</folder>
    </media>
    <config>
        <fields name="params">
            <fieldset name="basic">
                <field
                    name="header"
                    type="list"
                    label="MOD_HELLO_HEADER_LEVEL"
                    >
                    <option value="h3">MOD_HELLO_HEADER_LEVEL_3</option>
                    <option value="h4">MOD_HELLO_HEADER_LEVEL_4</option>
                    <option value="h5">MOD_HELLO_HEADER_LEVEL_5</option>
                    <option value="h6">MOD_HELLO_HEADER_LEVEL_6</option>
                </field>
            </fieldset>
        </fields>
    </config>
    <updateservers>
        <!-- آدرس زیر را مطابق با آدرس محیط توسعه‌ی به‌روزرسانی خود تغییر دهید -->
        <server type="extension" name="Hello Module Updates">http://localhost/joom/updateserver/updates.xml</server>
    </updateservers>
</extension>

حالا این نسخه از mod_hello را نصب کنید.

ماژول ساده

اگر کاملاً تازه‌کار در توسعه جوملا هستید، احتمالاً بهتر است آموزش ماژول را که جزئیات بیشتری درباره مراحل لازم ارائه می‌دهد مطالعه کنید.

در این بخش، یک ماژول ساده می‌سازیم که یک رشته متنی را در بخش جلویی (frontend) نمایش می‌دهد.

فایل مانیفست (Manifest File)

برای اطلاعات کلی درباره فایل‌های مانیفست به بخش [Manifest Files] مراجعه کنید.

محتوای فایل `mod_example/mod_example.xml` به شکل زیر است:

 
<?xml version="1.0" encoding="utf-8"?>
<extension type="module" client="site" method="upgrade">
  <name>MOD_EXAMPLE</name>
  <creationDate>Today</creationDate>
  <author>Me</author>
  <authorEmail>email</authorEmail>
  <authorUrl>web</authorUrl>
  <copyright>(C) 2024 Open Source Matters, Inc.</copyright>
  <license>GNU General Public License version 2 or later</license>
  <namespace path="src">My\Module\Example</namespace>
  <version>1.0.0</version>
  <description><![CDATA[MOD_EXAMPLE_XML_DESCRIPTION]]></description>
  <files>
      <folder module="mod_example">services</folder>
      <folder>language</folder>
      <folder>src</folder>
      <folder>tmpl</folder>
      <file>mod_example.xml</file>
  </files>
  <languages>
      <language tag="en-GB">language/en-GB/mod_example.ini</language>
      <language tag="en-GB">language/en-GB/mod_example.sys.ini</language>
  </languages>
   <config>
      <fields name="params">
          <fieldset name="basic" addfieldprefix="My\Module\Example\Site\Field">
            <field name="my-message" type="text" label="MOD_EXAMPLE_FIELD_MY_MESSAGE_LABEL" description="MOD_EXAMPLE_FIELD_MY_MESSAGE_DESC" />
          </fieldset>
      </fields>
  </config>
</extension>
 

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

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

نوع افزونه (Extension type)

 
<extension type="module" client="site" method="upgrade">

نوع افزونه باید درست مشخص شود؛ برای ماژول روی سایت باید "module" باشد.

رشتههای زبانی (Language constants)

 
<name>MOD_EXAMPLE</name>
<description><![CDATA[MOD_EXAMPLE_XML_DESCRIPTION]]></description>

استفاده از رشته‌های زبان در اینجا الزامی نیست، اما اگر استفاده می‌کنید باید آن‌ها را در فایل زبان `.sys.ini` تعریف کنید.

نام و توضیحات در فرم مدیریت ماژول‌ها نمایش داده می‌شوند.

فضای نام (Namespace)

 
<namespace path="src">My\Module\Example</namespace>

رعایت الگوی پیشنهادی جوملا برای نام‌گذاری (مثل `<MyCompany>\Module\<module name>`) اجباری نیست، اما:

- پیشوند namespace باید با `use` در فایل `services/provider.php` و اعلام `namespace` در کلاس اصلی افزونه مطابقت داشته باشد.

- همه کلاس‌ها باید در فولدر `/src` باشند که در صفت `path` مشخص شده است.

اگر به مشکل namespace برخوردید، به فایل `administrator/cache/autoload_psr4.php` نگاه کنید تا مطمئن شوید پیشوند namespace شما به مسیر درست اشاره می‌کند. این فایل کش‌شده در هر بار نصب افزونه جدید بازسازی می‌شود (البته اگر پلاگین "Extension - Namespace Updater" فعال باشد). اگر مستقیماً در کدها تغییر می‌دهید ممکن است لازم باشد این فایل کش را پاک کنید تا دوباره ساخته شود.

نقطه ورود ماژول (Module entry point)

 
<files>
    <folder module="mod_example">services</folder>
    <folder>src</folder>
</files>

برای مشخص کردن نقطه ورود ماژول، باید از صفت `module="mod_example"` روی پوشه services استفاده کنید.

همچنین نام فایل مانیفست XML باید مطابق قرارداد نام‌گذاری شما باشد، یعنی `mod_example.xml`.

فایلهای زبان

در فایل مانیفست ما بخش زیر برای معرفی فایل‌های زبان داریم:

 
<languages>
  <language tag="en-GB">language/en-GB/mod_example.ini</language>
  <language tag="en-GB">language/en-GB/mod_example.sys.ini</language>
</languages>

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

ما در ماژول خود، رشته‌های زبانی زیر را تعریف می‌کنیم:

language/en-GB/mod_example.ini

 
MOD_EXAMPLE="Example"
MOD_EXAMPLE_XML_DESCRIPTION="An example Module for Joomla!"
MOD_EXAMPLE_FIELD_MY_MESSAGE_LABEL="Your Message"
MOD_EXAMPLE_FIELD_MY_MESSAGE_DESC="Description Text for your Message Field"

توجه داشته باشید که متن توضیح (description) همیشه باید توصیفی و قابل فهم باشد. به عنوان مثال، اگر فیلدی با عنوان «Company logo» دارید، همان نام کافی است و شاید نیاز به توضیح نداشته باشد.

language/en-GB/mod_example.sys.ini

 
MOD_EXAMPLE="Example"
MOD_EXAMPLE_XML_DESCRIPTION="An example Module for Joomla!"

فایل `mod_example.ini` شامل تمام رشته‌های زبانی و ترجمه‌هایی است که برای نمایش ماژول (هم در محیط مدیریت و هم در نمای سایت) استفاده می‌شود، در حالی که فایل `mod_example.sys.ini` برای متونی استفاده می‌شود که خارج از تنظیمات ماژول یا نمایش آن هستند، مانند عنوان ماژول و توضیحات آن در فرم مدیریت.

فایل Service Provider 

مسیر فایل: `mod_example/services/provider.php`

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

use Joomla\CMS\Extension\Service\Provider\HelperFactory;
use Joomla\CMS\Extension\Service\Provider\Module;
use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

return new class() implements ServiceProviderInterface
{
    /**
     * @param   Container  $container
     *
     * @since version
     */
    public function register(Container $container)
    {
        $container->registerServiceProvider( new ModuleDispatcherFactory('\\My\\Module\\Example'));
        $container->registerServiceProvider( new HelperFactory('\\My\\Module\\Example\\Site\\Helper'));
        $container->registerServiceProvider( new Module());
    }
};

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

خطوطی که باید در فایل `mod_example/services/provider.php` تغییر کنند:

 
$container->registerServiceProvider( new ModuleDispatcherFactory('\\My\\Module\\Example'));
$container->registerServiceProvider( new HelperFactory('\\My\\Module\\Example\\Site\\Helper'));

این‌ها باید منعکس‌کننده namespace واقعی پروژه‌ی شما باشند.

فایل Dispatcher 

فایل: `mod_example/src/Dispatcher/Dispatcher.php`

 
<?php
/**
 * @package           <mod_example>
 *
 * @author            <MyCompany> | <Me> <email>
 * @copyright         Copyright(R) year by  <MyCompany> | <Me>
 * @license           GNU General Public License version 2 or later; see LICENSE.txt
 * @link              <mywebsite>
 * @since             1.0.0
 *
 */

namespace My\Module\Example\Site\Dispatcher;

defined('_JEXEC') or die;

use Joomla\CMS\Dispatcher\AbstractModuleDispatcher;
use Joomla\CMS\Helper\HelperFactoryAwareInterface;
use Joomla\CMS\Helper\HelperFactoryAwareTrait;
use Joomla\Registry\Registry;

class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface
{
    use HelperFactoryAwareTrait;

    protected function getLayoutData()
    {
        // دریافت پارامترهای ماژول
        $params = new Registry($this->module->params);
        $data = parent::getLayoutData();

        $helperName = 'ExampleHelper';
        // استفاده از Helper برای گرفتن پیام تنظیم شده در ماژول
        $data['mymsg'] = $this->getHelperFactory()->getHelper($helperName)->getMessage($data['params'], $this->getApplication());

        return $data;
    }
}

توضیح

Dispatcher مدیریت اجرای ماژول را برعهده دارد و اطمینان حاصل می‌کند داده‌های موردنظر برای نمایش آماده شوند. اینکار با استفاده از کلاس کمکی (Helper) ما به نام `ExampleHelper` انجام می‌شود.

تابع `getLayoutData` می‌تواند قابلیت‌های بیشتری افزوده شود؛ به طور مثال می‌توانید در اینجا فایل‌های WebAssets json را بارگذاری کرده و منابع (assets) مورد نیاز ماژول را مدیریت کنید، کمک‌کننده‌های دیگر یا ماژول‌های دیگر را فراخوانی کنید و چیزهای بیشتری.

تمام کلیدهای موجود در آرایه `data` بعداً به طور مستقیم در قالب (template) ماژول قابل استفاده خواهند بود. برای مثال در قالب می‌توانیم پیام را با متغیر `mymsg` دریافت کنیم.

فایل ExampleHelper 

فایل: `mod_example/src/Helper/ExampleHelper.php`

 
<?php
/**
 * @package           <mod_example>
 *
 * @author            <MyCompany> | <Me> <email>
 * @copyright         Copyright(R) year by  <MyCompany> | <Me>
 * @license           GNU General Public License version 2 or later; see LICENSE.txt
 * @link              <mywebsite>
 * @since             1.0.0
 *
 */

namespace My\Module\Example\Site\Helper;

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;

class ExampleHelper
{
    /**
     * متد دریافت پیام  
     *  
     * @param   Registry  $params  پارامترهای ماژول
     * @param   object    $app     شیء اپلیکیشن
     *
     * @return  string
     *
     * @since   2.0
     */
    public function getMessage($params, $app)
    {
        // پیام را از پارامترها دریافت می‌کند و اگر نباشد مقدار پیش‌فرض را برمی‌گرداند
        $message = $params->get('my-message', 'Fallback Message can be noted here');

        return $message;
    }
}

توضیح:

هرچند این ساختار ممکن است کمی سنگین به نظر برسد فقط برای نمایش یک پیام ساده در قالب ماژول، اما نمونه‌ای است برای اینکه چگونه می‌توان یک helper در ماژول ساخت.

دقت کنید که نام فضای نام (namespace) مناسب حتماً تعریف شود تا جوملا این Helper را به درستی بشناسد و بارگذاری کند.

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