跳至主要内容
版本:5.1

步骤 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 有几点需要注意

  1. 它在其构造函数中传递了模块 $module、应用程序 $app 和输入 $input 变量,并将这些变量存储在实例变量中。

  2. 它有一个函数 loadLanguage,用于加载模块的 .ini 语言文件。

  3. 它有一个函数 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 个变量可用于模块代码,因此为了向后兼容而保留)。

  1. 它有一个函数 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 文件删除了几行,变为

mod_hello/src/Dispatcher/Dispatcher.php
<?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 变量。

mod_hello/tmpl/default.php
<?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 作为基类。

更新后的清单文件

mod_hello/mod_hello.xml
<?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>