JSON 响应格式
Joomla 默认情况下会在请求时使用 Accept: application/json 标头以及特定的 JSON API 标头返回 JSON API 响应。尽管 Joomla 的核心不支持其他内容类型,但 **支持开发人员添加可以响应的其他内容类型的功能**。
目标
- 从 Joomla API 获取 JSON 响应
- 创建必要的 Web 服务插件和组件的 API 部分
- 使用模块参数对将在 API 响应中发送的数据进行建模
非目标
- 如何创建扩展。本教程假设您知道如何在 Joomla 4 中创建扩展。请记住,至少需要一个插件和一个组件。但不用担心,此组件可以非常基础,实际上,它甚至不需要任何模型,只需要管理区的仪表板视图能够正常工作即可。这足以使您的 API 正常工作。
需要基本后端部分的原因是,XML 清单、配置 (config.xml) 和权限 (access.xml) 文件仅存在于组件的后端目录中。XML 清单对于组件能够安装、更新和卸载是必要的。此外,Joomla 始终为组件创建一个后端菜单项,这意味着组件必须有一个后端部分,即使它只是显示一条消息,说明在后端没有与此组件相关的任何操作。
- 使用通用方法开发教程。我们构建了一个自定义的 API 逻辑,并采用了一种特定的方法。尽管如此,在您完成本教程后,您将能够进行更改以满足您的需求。
开始前须知
Joomla API 当前使用的身份验证方法之一是基于令牌的身份验证。(它也有一种用于凭据、用户名和密码的身份验证方法,但您应该始终避免使用这种方法)。
因此,**核心经过精心设计和开发,用于管理功能以及应用程序与自身交互的想法**。因此,身份验证是围绕这一点设计的。
但是,如果您的内容旨在完全公开(例如,应用程序中的博文),您可以在 Web 服务插件中使用公共标志(稍后将详细介绍)。
Web 服务插件
我们的第一行代码将从插件开始。除了指示将处理请求的组件的控制器之外,插件还负责注册 API 的路由(端点)。让我们创建它。
在您的工作区中,创建一个名为:plg_webservices_vapi 的文件夹。在文件夹内,让我们创建一个名为 vapi.php 的 php 文件,内容如下
defined('_JEXEC') || die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\ApiRouter;
use Joomla\Router\Route;
class PlgWebservicesVapi extends CMSPlugin
{
/**
* Registers com_vapi API's routes in the application
*
* @param ApiRouter &$router The API Routing object
*
* @return void
*
*/
public function onBeforeApiRoute(&$router)
{
// Render a list of com_content articles using a specific module
$this->createModuleSiteRoutes($router, 'v1/vapi/modules/:id', 'module.displayModule');
}
/**
* Creates routes map for CRUD
*
* @param ApiRouter &$router The API Routing object
* @param string $baseName The route pattern to use for matching
* @param string $controller The name of the controller that will handle the api request.
* @param array $defaults An array of default values that are used when the URL is matched.
* @param bool $publicGets Allow the public to make GET requests.
*
* @return void
*
*/
private function createModuleSiteRoutes(&$router, $baseName, $controller, $defaults = [], $publicGets = true): void
{
$defaults = [
'component' => 'com_vapi',
'public' => $publicGets,
'format' => [
'application/json'
]
];
$routes = [
new Route(['GET'], $baseName, $controller, ['id' => '(\d+)'], $defaults),
];
$router->addRoutes($routes);
}
}
让我们重点介绍一些您应该了解的关于此插件的信息
-
onBeforeApiRoute 方法:此方法在每个 Web 服务插件中都需要。在这里,您将定义您的路由(端点)。您可以在此方法内定义这些路由,或者像这里一样在自定义的单独方法中定义(此自定义方法将取决于您构建的方式,它不是 Joomla 核心的一部分)。
-
createModuleSiteRoutes 方法:在这里,您可以检查
Joomla\Router\Route
类的构造函数,并了解我们用于实例化类的所有参数。但是,让我们在这里扩展它们的描述。-
["GET"]:此路由支持的 HTTP 方法,所有动词都必须大写。所有有效方法为
["GET", "POST", "PUT", "DELETE", "HEAD", "TRACE", "PATCH"]
-
$baseName:要使用的路由模式或端点。在此示例中,我们在此处获得
v1/vapi/modules/:id
。v1
部分用于对您的 API 进行版本控制。从组件 API 的第一个版本 v1 开始。- 下一部分应该是您的组件名称,不带
com_
前缀。这只是定义路由的约定。 - 只剩下
modules/:id
。这是我们的组件处理的 **功能**,以及一个:id
参数,该参数可能存在或不存在于您的端点中。在我们的例子中,此模式告诉 Joomla 此路由仅在v1/vapi/modules
路由后面跟着某些内容时才会匹配,这些内容将作为名为id
的请求参数提供。如果该内容不存在,则路由不匹配,Joomla 不会使用它。
-
$controller:这是组件 API 控制器以及要执行的任务(此控制器中的一个方法)。请注意,需要用点分隔。
-
['id' => '(\d+)']:如果您的路由模式具有参数,您将提供一个正则表达式模式,该值必须与该模式匹配才能使路由匹配。在这种情况下,id 参数(在模式中定义为
:id
)必须是一个或多个数字组成的整数(包括值 0)。 -
$defaults:最后但并非最不重要。在此变量中,我们定义了
'component' => 'com_vapi'
关联的组件'public' => $publicGets
如果您有一个希望未经身份验证的用户可以访问的路由,则需要为 true,就像我们所做的那样。否则为 false。'format' => ['application/json']
这是定义我们的应用程序将处理 json 格式响应的地方。如果没有此设置,Joomla 将使用默认的 JSON-API。
-
在跳转到组件代码之前,请记住插件需要具有 vapi.xml 清单文件。这将是一个标准的清单,无需添加任何新内容。您可以参考 Web 服务插件组中的任何清单。
组件 API 部分
提醒您,在开始此部分之前,您需要拥有具有基本功能的组件。
在 Joomla 4 中,您的组件还有另一个可选部分:api
部分。就像组件的前端(站点)和后端(管理员)一样,它有自己的控制器、视图和模型来呈现 JSON 结果集,而不是 HTML 页面。
您的组件 XML 清单需要在 <extension>
根节点下有一个 <api>
部分,定义组件的 api 部分中包含的文件和文件夹。通常,它看起来像这样
XML 清单 - API 部分
<api>
<files folder="api/">
<folder>src</folder>
</files>
</api>
在您的组件根安装文件夹中,现在创建一个名为 api
的新文件夹。此文件夹将有一个子文件夹 src
,我们将在此处添加所有 API 文件夹和文件。让我们从控制器开始。现在创建 Controller
文件夹,其中包含文件 ModuleController.php 以及以下代码
控制器 - 类声明
<?php
namespace Carlitorweb\Component\Vapi\Api\Controller;
defined('_JEXEC') || die;
use Joomla\CMS\MVC\Factory\ApiMVCFactory;
use Joomla\CMS\Application\ApiApplication;
use Joomla\Input\Input;
use Joomla\CMS\Language\Text;
use Joomla\Component\Content\Administrator\Extension\ContentComponent;
use Joomla\CMS\Component\ComponentHelper;
class ModuleController extends \Joomla\CMS\MVC\Controller\BaseController
{
/**
* @var string $default_view Will be used as default for $viewName
*/
protected $default_view = 'modules';
/**
* @var \Joomla\Registry\Registry $moduleParams The module params to set filters in the model
*/
protected $moduleParams;
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings
*
* @param ApiMVCFactory $factory The factory.
* @param ApiApplication $app The Application for the dispatcher
* @param Input $input Input
*
* @throws \Exception
*/
public function __construct($config = array(), ApiMVCFactory $factory = null, ?ApiApplication $app = null, ?Input $input = null)
{
if (\array_key_exists('moduleParams', $config)) {
$this->moduleParams = new \Joomla\Registry\Registry($config['moduleParams']);
}
parent::__construct($config, $factory, $app, $input);
}
# your methods code from here...
}
注意控制器的命名空间。您可以将其更改为您自己的组件已有的自定义命名空间。您应该更改 Vapi(这是我在此组件中使用的名称)和前缀 Carlitorweb,其余的根据约定最好保持原样(但您可以更改所有内容以满足您的需求)。
此外,来自 Joomla 核心的 JSON-API 扩展了来自 Joomla\CMS\MVC\Controller\ApiController
的控制器。在我们的案例中,需要获取 JSON 响应,为此,需要扩展自 \Joomla\CMS\MVC\Controller\BaseController
。
我们还声明了两个属性,一个用于告诉 Joomla 我们期望使用的视图文件,另一个用于设置模块参数,以便对将在 API 响应中发送的数据进行建模。
现在让我们看看将参与该类的各个方法
控制器 - 方法声明
/**
* Set the models and execute the view
*
* @throws \Exception
*/
public function displayModule(): void
{
# your code here...
}
/**
* Boot the model and set the states
*
* @param \Joomla\Registry\Registry $params The module params
*
*/
protected function getMainModelForView($params): \Joomla\Component\Content\Site\Model\ArticlesModel
{
# your code here...
}
/**
* Set the module params
*
* @param \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel
*
*/
protected function setModuleParams($moduleModel): \Joomla\Registry\Registry
{
# your code here...
}
displayModule()
是我们在 Web 服务插件中定义为要执行的任务的方法。这是控制器将使用的第一个方法。如果您想测试所有内容是否按预期进行,请在此方法的开头添加以下内容
var_dump(__METHOD__);die;
然后使用您最喜欢的 API 客户端(如 Postman 或 vscode 的 Thunder Client 或 curl……)向路由 [yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]
发出请求。您将看到此响应
string(73)"Carlitorweb\Component\Vapi\Api\Controller\ModuleController::displayModule"
getMainModelForView()
此方法的目的是启动并准备视图将使用的主模型。我写主是因为 Joomla 允许视图与多个模型交互。
setModuleParams()
在这里,我们将获取将在 getMainModelForView()
中使用的模块参数。如果您注意到了,该方法使用了一个参数 \Carlitorweb\Component\Vapi\Api\Model\ModuleModel
。这是 API 将具有的自定义模型,我们需要创建它。在这里,我们将根据请求 URL 中作为参数传递的 ID 获取模块。**此时,您需要知道此 ID 需要与 Joomla 管理区中已创建的前端模块匹配。**
由于参数非常必要,因此让我们立即创建我们的模型。
模型 - 类定义
在我们创建 Controller
文件夹的同一根目录中,让我们现在创建 Model
文件夹,其中包含文件 ModuleModel.php 和以下代码
<?php
defined('_JEXEC') || die;
use Joomla\CMS\Factory;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\Database\ParameterType;
use Joomla\CMS\Language\Text;
class ModuleModel extends \Joomla\CMS\MVC\Model\BaseDatabaseModel
{
/**
* Get the module
*
* @return \stdClass|null The Module object
*
* @throws \InvalidArgumentException If was not set the module ID
* @throws \RuntimeException If the module could not be found
*
*/
public function getModule(): ?object
{
/** @var \Joomla\CMS\Application\CMSApplicationInterface $app */
$app = Factory::getApplication();
$mid = $this->state->get('moduleID', 0);
if ($mid === 0) {
throw new \InvalidArgumentException(
sprintf(
'A module ID is necessary in %s',
__METHOD__
)
);
}
/** @var \Joomla\Database\DatabaseInterface $db */
$db = $this->getDatabase();
$query = $this->getModuleQuery($db, $mid);
// Set the query
$db->setQuery($query);
// Build a cache ID for the resulting data object
$cacheId = 'com_vapi.moduleId' . $mid;
try {
/** @var \Joomla\CMS\Cache\Controller\CallbackController $cache */
$cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class)
->createCacheController('callback', ['defaultgroup' => 'com_modules']);
$module = $cache->get(array($db, 'loadObject'), array(), md5($cacheId), false);
} catch (\RuntimeException $e) {
$app->getLogger()->warning(
Text::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()),
array('category' => 'jerror')
);
return new \stdClass();
}
return $module;
}
/**
* Get the module query
*
* @param int $mid The ID of the module
* @param \Joomla\Database\DatabaseInterface $db
*
*/
protected function getModuleQuery($db, $mid): \Joomla\Database\QueryInterface
{
$query = $db->getQuery(true);
$query->select('*')
->from($db->quoteName('#__modules'))
->where(
$db->quoteName('id') . ' = :moduleId'
)
->bind(':moduleId', $mid, ParameterType::INTEGER);
return $query;
}
}
非常简单的模型。我们获取要在 $this->state->get('moduleID', 0)
行中搜索的模块 ID。我们需要在控制器中提供此 ID(我们很快就会这样做)。然后,使用 $this->getModuleQuery()
方法构建我们将随后执行的数据库查询。最后,我们使用 try/catch 块获取模块对象并将其缓存。
模型准备就绪后,让我们回到控制器,从那里我们可以测试模型是否按预期运行。
控制器 - 方法定义
现在我们可以获取特定模块了,让我们完成 setModuleParams()
方法
/**
* Set the module params
*
* @param \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel
*
*/
protected function setModuleParams($moduleModel): \Joomla\Registry\Registry
{
// Get the module params
$module = $moduleModel->getModule();
if (is_null($module)) {
throw new \UnexpectedValueException(
sprintf(
'$module need be of type object, %s was returned in %s()',
gettype($module), __FUNCTION__
)
);
}
return $this->moduleParams = new \Joomla\Registry\Registry($module->params);
}
让我们看看控制器属性 $moduleParams 是否获取到了预期的结果。为此,让我们编辑主方法 displayModule()
/**
* Set the models and execute the view
*
* @throws \Exception
*/
public function displayModule(): void
{
$moduleID = $this->input->get('id', 0, 'int');
$moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]);
/** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */
$moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]);
// Set the params who will be used by the model
if(empty($this->moduleParams)) {
$this->setModuleParams($moduleModel);
}
var_dump($this->moduleParams);die;
}
-
$this->input->get('id', 0, 'int')
:URL 中:id
参数的值(我们在 webservices 插件中定义的那个)。 -
'state' => $moduleState
:请注意,我们在加载模型时传递了 ID。我们之前已经看到在模型内部使用了这个 ID 的位置。
再次使用您喜欢的 API 客户端,向路由 [yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]
发出请求。您将看到类似以下内容
object(Joomla\Registry\Registry)#938 (3) {
["data":protected]=>
object(stdClass)#1090 (44) {
["mode"]=>
string(6) "normal"
["show_on_article_page"]=>
int(1)
["count"]=>
int(0)
["show_front"]=>
string(4) "only"
["category_filtering_type"]=>
int(1)
["catid"]=>
array(5) {
[0]=>
int(2)
[1]=>
int(8)
[2]=>
int(9)
[3]=>
int(10)
.....
现在参数在我们手中了,让我们使用它。编辑方法 getMainModelForView()
/**
* Boot the model and set the states
*
* @param \Joomla\Registry\Registry $params The module Articles - Category params
*
*/
protected function getMainModelForView($params): \Joomla\Component\Content\Site\Model\ArticlesModel
{
$mvcContentFactory = $this->app->bootComponent('com_content')->getMVCFactory();
// Get an instance of the generic articles model
/** @var \Joomla\Component\Content\Site\Model\ArticlesModel $articlesModel */
$articlesModel = $mvcContentFactory->createModel('Articles', 'Site', ['ignore_request' => true]);
if (!$articlesModel) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$appParams = ComponentHelper::getComponent('com_content')->getParams();
$articlesModel->setState('params', $appParams);
$articlesModel->setState('filter.published', ContentComponent::CONDITION_PUBLISHED);
/*
* Set the filters based on the module params
*/
$articlesModel->setState('list.start', 0);
$articlesModel->setState('list.limit', (int) $params->get('count', 0));
$catids = $params->get('catid');
$articlesModel->setState('filter.category_id', $catids);
// Ordering
$ordering = $params->get('article_ordering', 'a.ordering');
$articlesModel->setState('list.ordering', $ordering);
$articlesModel->setState('list.direction', $params->get('article_ordering_direction', 'ASC'));
$articlesModel->setState('filter.featured', $params->get('show_front', 'show'));
$excluded_articles = $params->get('excluded_articles', '');
if ($excluded_articles) {
$excluded_articles = explode("\r\n", $excluded_articles);
$articlesModel->setState('filter.article_id', $excluded_articles);
// Exclude
$articlesModel->setState('filter.article_id.include', false);
}
return $articlesModel;
}
我们用来建模数据参数来自 Articles - Category 模块。这就是我们使用 :id
参数请求的 ID。(还要注意,并非所有参数都被使用了)
此方法没有太多需要解释的,您应该熟悉此代码。ArticlesModel 被加载,并根据模块参数定义了一组模型状态来获取数据。
让我们再次编辑主方法 displayModule()
来测试我们是否获取到了 ArticlesModel 对象
/**
* Set the models and execute the view
*
* @throws \Exception
*/
public function displayModule(): void
{
$moduleID = $this->input->get('id', 0, 'int');
$moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]);
/** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */
$moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]);
// Set the params who will be used by the model
if(empty($this->moduleParams)) {
$this->setModuleParams($moduleModel);
}
$mainModel = $this->getMainModelForView($this->moduleParams);
var_dump($mainModel::class);die;
}
再次使用您喜欢的 API 客户端,向路由 [yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]
发出请求。您将获得
string(49) "Joomla\Component\Content\Site\Model\ArticlesModel"
一切正常后,我们就可以设置视图并获取预期的 JSON 响应了。让我们最后一次编辑主方法 displayModule()
/**
* Set the models and execute the view
*
* @throws \Exception
*/
public function displayModule(): void
{
$moduleID = $this->input->get('id', 0, 'int');
$moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]);
/** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */
$moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]);
// Set the params who will be used by the model
if(empty($this->moduleParams)) {
$this->setModuleParams($moduleModel);
}
$mainModel = $this->getMainModelForView($this->moduleParams);
/** @var \Joomla\CMS\Document\JsonDocument $document */
$document = $this->app->getDocument();
$viewType = $document->getType();
$viewName = $this->input->get('view', $this->default_view);
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var \Carlitorweb\Component\Vapi\Api\View\Modules\JsonView $view */
$view = $this->getView(
$viewName,
$viewType,
'',
['moduleParams' => $this->moduleParams, 'base_path' => $this->basePath, 'layout' => $viewLayout]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
// Push the model into the view (as default)
$view->setModel($mainModel, true);
// Push as secondary model the Module model
$view->setModel($moduleModel);
$view->document = $this->app->getDocument();
$view->display();
}
-
$this->getView()
:Joomla 将在 View 文件夹内查找 Modules 文件夹(在$viewName
变量中定义的名称),该文件夹需要位于组件 API 部分的根目录(我们已经在其中拥有 Controller 和 Model 文件夹)。 -
'moduleParams' => $this->moduleParams
:请注意,模块参数已发送到视图。 -
$view->setModel()
:在这里,我们在视图对象中设置了我们在 API 中使用的两个模型。默认模型包含我们想要输出的数据,而$moduleModel
是我们的自定义模型(最后一个是可选的)。 -
$view->display()
:执行并显示输出。
让我们创建最后一个文件,即视图。
视图 - 类和方法定义
<?php
namespace Carlitorweb\Component\Vapi\Api\View\Modules;
defined('_JEXEC') || die;
use \Joomla\CMS\MVC\View\JsonView as BaseJsonView;
use \Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\HTML\HTMLHelper;
use \Carlitorweb\Component\Vapi\Api\Model\ModuleModel;
class JsonView extends BaseJsonView
{
/**
* @var array $fieldsToRenderList Array of allowed fields to render
*/
protected $fieldsToRenderList = [
'id',
'title',
'alias',
'displayDate',
'metadesc',
'metakey',
'params',
'displayHits',
'displayCategoryTitle',
'displayAuthorName',
];
/**
* @var array $display Extra params to prepare the articles
*/
protected $display = array();
/**
* Constructor.
*
* @param array $config A named configuration array for object construction.
*
*/
public function __construct($config = [])
{
if (\array_key_exists('moduleParams', $config)) {
$params = $config['moduleParams'];
// Display options
$this->display['show_date'] = $params->get('show_date', 0);
$this->display['show_date_field'] = $params->get('show_date_field', 'created');
$this->display['show_date_format'] = $params->get('show_date_format', 'Y-m-d H:i:s');
$this->display['show_category'] = $params->get('show_category', 0);
$this->display['show_author'] = $params->get('show_author', 0);
$this->display['show_hits'] = $params->get('show_hits', 0);
}
parent::__construct($config);
}
/**
* Set the data who will be load
*/
protected function setOutput(array $items = null): void
{
/** @var \Joomla\CMS\MVC\Model\ListModel $mainModel */
$mainModel = $this->getModel();
/** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */
$moduleModel = $this->getModel('module');
if ($items === null) {
$items = [];
foreach ($mainModel->getItems() as $item) {
$_item = $this->prepareItem($item, $moduleModel);
$items[] = $this->getAllowedPropertiesToRender($_item);
}
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
$this->_output = $items;
}
/**
* @param \stdClass $item The article to prepare
*/
protected function getAllowedPropertiesToRender($item): \stdClass
{
$allowedFields = new \stdClass;
foreach($item as $key => $value) {
if (in_array($key, $this->fieldsToRenderList, true)) {
$allowedFields->$key = $value;
}
}
return $allowedFields;
}
/**
* Prepare item before render.
*
* @param object $item The model item
* @param ModuleModel $moduleModel
*
* @return object
*
*/
protected function prepareItem($item, $moduleModel)
{
$item->slug = $item->alias . ':' . $item->id;
if ($this->display['show_date']) {
$show_date_field = $this->display['show_date_field'];
$item->displayDate = HTMLHelper::_('date', $item->$show_date_field, $this->display['show_date_format']);
}
$item->displayCategoryTitle = $this->display['show_category'] ? $item->category_title : '';
$item->displayHits = $this->display['show_hits'] ? $item->hits : '';
$item->displayAuthorName = $this->display['show_author'] ? $item->author : '';
return $item;
}
/**
* Execute and display a template script.
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
*/
public function display($tpl = null)
{
// remove any string that could create an invalid JSON
// such as PHP Notice, Warning, logs...
ob_clean();
// this will clean up any previously added headers, to start clean
header_remove();
$this->setOutput();
parent::display($tpl);
echo $this->document->render();
}
}
-
JsonView
:这一点很重要。名称需要与此相同,因为 Joomla 将查找此类名。此外,Joomla 核心 JSON-API 从Joomla\CMS\MVC\View\JsonApiView
扩展视图,由于本教程的目标是获取 JSON 响应,因此需要来自\Joomla\CMS\MVC\View\JsonView
。 -
setOutput()
:使用$this->getModel()
方法,我们可以访问我们在控制器中设置的模型,一个默认模型,另一个模型需要名称作为 \Joomla\CMS\MVC\View\AbstractView::_models 数组中的键引用。 -
getAllowedPropertiesToRender()
:如果您有一个公共路由,则**必须**考虑您将在 JsonView 对象中包含哪些字段。并非所有字段都适合公开显示;这可能导致称为信息泄露的安全漏洞。例如,您的论坛组件可能会将 IP 地址与用户 ID 和论坛帖子的创建日期和时间一起保存。**不要**将 IP 地址和用户 ID 提供给公众。此组合被视为个人身份信息,可能会导致罚款!根据站点的上下文,仅用户 ID 可能是特权信息(请记住,用户名不是特权信息,但内部用户 ID 是)。
-
$this->document->render()
:输出文档
再次使用您喜欢的 API 客户端,向路由 [yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]
发出请求。您将获得
[
{
"id": 11,
"title": "Typography",
"alias": "typography",
"metakey": "",
"metadesc": "",
"params": {...},
"displayDate": "2022-11-20 20:49:17",
"displayCategoryTitle": "Typography",
"displayHits": 0,
"displayAuthorName": "Carlos Rodriguez"
}
]
不错!我们的通用 JSON 响应将永远存在;)