步骤 10 使用 AbstractModuleDispatcher
如果您查看过任何 Joomla 模块的代码,您可能会注意到它们的 Dispatcher 代码看起来与我们在本模块教程中开发的代码非常不同。这是因为它们继承自 AbstractModuleDispatcher 类。
在此步骤中,我们将了解 AbstractModuleDispatcher 以及如何使用它简化我们的代码。
源代码可在 mod_hello 步骤 10 中找到。
AbstractModuleDispatcher 功能
\Joomla\CMS\Dispatcher\AbstractModuleDispatcher 的代码位于 libraries/src/Dispatcher/AbstractModuleDispatcher.php 中,此类又扩展了 libraries/src/Dispatcher/Dispatcher.php 中的 \Joomla\CMS\Dispatcher\Dispatcher。
关于 AbstractModuleDispatcher 有几点需要注意
-
它在其构造函数中传递了模块
$module
、应用程序$app
和输入$input
变量,并将这些变量存储在实例变量中。 -
它有一个函数
loadLanguage
,用于加载模块的 .ini 语言文件。 -
它有一个函数
getLayoutData
,用于返回一个包含 5 个变量(模块、应用程序、输入、参数和模板)的数组。
return [
'module' => $this->module,
'app' => $this->app,
'input' => $this->input,
'params' => new Registry($this->module->params),
'template' => $this->app->getTemplate(),
];
(在 Joomla 4 之前,这 5 个变量可用于模块代码,因此为了向后兼容而保留)。
- 它有一个函数
dispatch
,执行以下操作- 通过
loadLanguage
加载语言 - 调用
getLayoutData
并将返回的数组分配给变量$displayData
- 使用 PHP
extract
将$displayData
的数组元素提取到变量中 - 执行
require ModuleHelper::getLayoutPath($module->module, $params->get('layout', 'default'));
,运行 tmpl 文件。
- 通过
最后两个操作在单独的函数内执行以创建干净的作用域。
使用 AbstractModuleDispatcher
由于我们的 mod_hello Dispatcher 和 AbstractModuleDispatcher 非常相似,因此我们可以使用后者为我们执行以下操作
- 存储构造函数参数,使
$module
、$app
和$input
变量可用 - 加载语言
- 加载 tmpl 文件
我们只需覆盖 getLayoutData
以将“hello”元素添加到 $data
数组中,当执行 PHP extract
时,该元素将成为 $hello
变量。
我们的更新后的 Dispatcher 文件删除了几行,变为
<?php
namespace My\Module\Hello\Site\Dispatcher;
\defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\AbstractModuleDispatcher;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\Input\Input;
use Joomla\Registry\Registry;
use Joomla\CMS\Helper\HelperFactoryAwareInterface;
use Joomla\CMS\Helper\HelperFactoryAwareTrait;
class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface
{
use HelperFactoryAwareTrait;
protected function getLayoutData(): array
{
$data = parent::getLayoutData();
$username = $this->getHelperFactory()->getHelper('HelloHelper')->getLoggedonUsername('Guest');
$data['hello'] = Text::_('MOD_HELLO_GREETING') . $username;
return $data;
}
}
在我们的 tmpl 文件中,我们只需要记住使用 $app
而不是 $this->app
访问应用程序。当对 $data
数组执行 extract
时,将定义 $hello
变量。
<?php
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
$document = $app->getDocument();
$wa = $document->getWebAssetManager();
$wa->getRegistry()->addExtensionRegistryFile('mod_hello');
$wa->useScript('mod_hello.add-suffix');
// Pass the suffix to add down to js
$document->addScriptOptions('mod_hello.vars', ['suffix' => '!']);
$h = $params->get('header', 'h4');
$greeting = "<{$h} class='mod_hello'>{$hello}</{$h}>";
Text::script('MOD_HELLO_AJAX_OK');
Text::script('JLIB_JS_AJAX_ERROR_OTHER');
?>
<?php echo $greeting; ?>
<div>
<p><?php echo Text::_('MOD_HELLO_NUSERS'); ?><span class="mod_hello_nusers"></span></p>
<button class="mod_hello_updateusers"><?php echo Text::_('MOD_HELLO_UPDATE_NUSERS'); ?></button>
</div>
模块模式
模块通常遵循一个简单的模式
- 获取您要显示的数据(将任何复杂的逻辑放入帮助程序文件中),以及
- 在 HTML 的一部分中显示数据
如果要开发的模块遵循此模式,则可以执行以下操作
- 编写一个类似于 mod_hello 的 Dispatcher 类
- 自定义 getLayoutData 以设置数据数组以满足您的需求。请记住,此数组的元素将提取到 PHP 变量中(这些变量在 tmpl 文件中可用)
- 将任何复杂的逻辑放入帮助程序文件中的函数中
- 使用设置的数据,在 tmpl 文件中输出 HTML
如果您有更复杂的需求,则可能需要覆盖 Dispatcher.php 文件中的更多功能,但您可以使用 AbstractModuleDispatcher 作为基类。
更新后的清单文件
<?xml version="1.0" encoding="UTF-8"?>
<extension type="module" client="site" method="upgrade">
<name>MOD_HELLO_NAME</name>
<version>1.0.10</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>
</extension>