跳至主要内容
版本:5.1

Ajax 插件

简介

想象一个处理活动预订的 Joomla 网站。在活动当天,负责摆放椅子的工作人员想知道有多少人会来,因此他们在浏览器中输入一个 URL,该 URL 在 Joomla 网站上运行一个作业并输出参与者人数。

这正是可以使用 Ajax 插件轻松处理的作业类型。尽管名称如此,Ajax 插件并不局限于来自 JavaScript 的 Ajax 请求;您可以使用它来处理来自浏览器的普通 GET 请求。

对于像这样的临时作业,使用 Ajax 插件比使用自定义脚本更好,因为 Joomla 支持该功能,并且通常不需要在 Joomla 版本之间进行重新工作。此外,您可以将所有作业保存在一个 PHP 文件中。

此示例 Ajax 插件提供了一个实用程序,用于列出 Joomla 实例上的扩展程序数量,并按扩展程序类型进行分组。您在浏览器中输入一个 URL

https://example.com/index.php?option=com_ajax&format=raw&plugin=getExtensionTotals

该实用程序将以计数的形式进行响应

component:45
file:3
language:9

编写 Ajax 插件

要编写处理 URL 的插件

https://example.com/index.php?option=com_ajax&format=raw&plugin=getExtensionTotals

您只需编写一个标准插件,该插件侦听事件 onAjaxGetExtensionTotals 并将结果作为字符串返回。仅此而已!以下是伪代码

public function onAjaxGetExtensionTotals(Event $event)
{
// perform the database query
// return the result
}

在您输入以运行功能的 URL 中,您必须指定为查询参数

  • option=com_ajax
  • format=<格式类型>(您可以指定 format=json,然后返回一个 JSON 字符串,但 format= 任何其他内容只会返回字符串)
  • plugin=<作业名称> 将导致触发事件 onAjax<作业名称>(注意大小写)。在我们的示例中,plugin=getExtensionTotals 将导致触发 onAjaxGetExtensionTotals

您显然可以指定其他查询参数,然后可以使用输入捕获这些参数并在函数的逻辑中使用它们。

站点、管理员和已登录用户

如果您查看 Joomla 代码,您会发现站点 com_ajax 和管理员 com_ajax 完全相同。因此,您可以使用以下方法运行代码:

https://example.com/administrator/index.php?option=com_ajax&format=raw&plugin=getExtensionTotals

但是,在前面的情况下,您的代码将运行 SiteApplication,但在这种情况下,AdministratorApplication,这将对诸如使用 Route::_() 构建 SEF 路由(您需要在后端使用 Route::link())和获取站点菜单项(您需要在后端显式加载它们)之类的函数产生影响。

此外,如果用户在登录 Joomla 站点前端或管理员后端后运行作业,则如果会话尚未过期,Joomla 应用程序将把用户视为已登录,并且如果“全局配置/系统/共享会话”选项已设置,则这将在管理员和站点之间交叉。

如果您决定在代码中使用硬编码凭据登录用户,则应确保在退出之前将其注销(如是否登录中所述),并将您调用的函数包装在 try/catch 块中,以便您可以捕获任何异常。否则,登录状态将通过会话 cookie 保持。

Ajax 插件代码

此部分包含 ajax 插件的完整源代码。您可以通过复制下面的代码手动编写插件,也可以从下载 Ajax 插件 GetExtensionTotals下载 zip 文件。如果您是手动编写,则将以下文件包含在文件夹中,例如 plg_ajax_jobs

安装 zip 文件并启用插件。然后输入 URL(将 example.com 替换为您的域名)

https://example.com/index.php?option=com_ajax&format=raw&plugin=getExtensionTotals

这将显示 Joomla 实例上每种不同类型的扩展程序的数量。

不幸的是,无法为 com_ajax URL 创建漂亮的 SEF URL。如果您确实需要易于使用的 URL,则必须在 Web 服务器中配置一些重写规则。

清单文件

插件的标准清单文件

plg_ajax_jobs/jobs.xml
<?xml version="1.0" encoding="utf-8"?>
<extension method="upgrade" type="plugin" group="ajax">
<name>Ajax Jobs</name>
<version>1.0</version>
<description>Example ajax plugin for ad hoc jobs</description>
<author>Me</author>
<creationDate>Today</creationDate>
<namespace path="src">My\Plugin\Ajax\AjaxJobs</namespace>
<files>
<folder plugin="jobs">services</folder>
<folder>src</folder>
</files>
</extension>

服务提供程序文件

一个标准的服务提供程序文件,用于通过依赖注入容器实例化插件

plg_ajax_jobs/services/provider.php
<?php

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use My\Plugin\Ajax\AjaxJobs\Extension\Jobs;

return new class() implements ServiceProviderInterface
{
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {

$config = (array) PluginHelper::getPlugin('ajax', 'jobs');
$subject = $container->get(DispatcherInterface::class);
$app = Factory::getApplication();

$plugin = new Jobs($subject, $config);
$plugin->setApplication($app);

return $plugin;
}
);
}
};

作业文件

您在这里编写临时作业的代码。结果将如Joomla 4 和 5 的更改中所述返回。

plg_ajax_jobs/src/Extension/Jobs.php
<?php
namespace My\Plugin\Ajax\AjaxJobs\Extension;

// no direct access
defined('_JEXEC') or die;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Event\Result\ResultAwareInterface;
use Joomla\Database\DatabaseInterface;

class Jobs extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onAjaxGetExtensionTotals' => 'onAjaxGetExtensionTotals',
];
}

public function onAjaxGetExtensionTotals(Event $event)
{
$db = Factory::getContainer()->get(DatabaseInterface::class);

$query = $db->getQuery(true)
->select('type, count(*) as count')
->from($db->quoteName('#__extensions'))
->group('type');
$db->setQuery($query);

$counts = $db->loadAssocList('type', 'count');
$output = "";
foreach ($counts as $extension => $count) {
$output .= "{$extension}:{$count}<br>";
}

if ($event instanceof ResultAwareInterface) {
$event->addResult($output);
} else {
$result = $event->getArgument('result') ?? [];
$result[] = $output;
$event->setArgument('result', $result);
}
}
}