我已经创建了一个自定义插件在Craft CMS 4,必须解码数据和存储在它的相应条目。然而,在开发过程中,我在我的init函数中触发了这个方法,所以在每个页面加载时,它都会被触发,这是不必要的。所以我想在我的小枝模板中的一个按钮被单击时触发这个方法。我设法通过基本原理迷惑我的方式,但由于某种原因,它不会激发实际的功能。有人知道我做错了什么吗?我的代码:
已编辑Plugin.php
public function init(): void
{
parent::init();
// Render the template for my plugin.
Event::on(
View::class,
View::EVENT_REGISTER_SITE_TEMPLATE_ROOTS,
function(RegisterTemplateRootsEvent $event) {
$event->roots['_jsonify'] = __DIR__ . '/src/templates';
}
);
// Register the event that should be triggered on this url.
Event::on(
UrlManager::class,
UrlManager::EVENT_REGISTER_CP_URL_RULES,
function(RegisterUrlRulesEvent $event) {
$event->rules['_jsonify/import/test'] = '_jsonify/import/test';
}
);
Craft::$app->onInit(function() {
$this->getJsonFile();
$this->decodeJsonFile();
});
}
字符串
PluginController.php
<?php
namespace plugins\jsonify\controllers;
use Craft;
use craft\web\Controller;
use craft\elements\Entry;
use yii\web\Response;
class JsonifySettingsController extends Controller
{
// Test function for test purposes
public function test(): Response
{
dd('test');
return $this->asJson(['message' => true]);
}
private function actionHandleJsonRead(): Response
{
$jsonFile = $this->decodeJsonFile();
$section = Craft::$app->sections->getSectionByHandle('test');
foreach ($jsonFile as $key => $data) {
$existingEntry = Entry::find()
->sectionId($section->id)
->andWhere(['title' => $data['Trial_name']])
->one();
if ($existingEntry) {
Craft::$app->getSession()->setNotice('Entry already exists with the same unique identifier. Skipping.');
continue;
}
$entry = new Entry();
$entry->sectionId = $section->id;
$entry->title = $data['Trial_name'];
$entry->testId = $data['testID'];
$entry->entryName = $data['Name'];
$entry->contractorSampleAnalysis = $data['Contractor_sample_analysis'];
$entry->country = $data['Country'];
$entry->crops = $data['Crops'];
$entry->deltaYield = $data['Delta_yield'];
$entry->lat = $data['lat'];
$entry->location = $data['Location'];
$entry->locationXy = $data['location_XY'];
$entry->lon = $data['lon'];
$entry->mapExport = $data['Map_export'];
$entry->primaryCompany = $data['Primary_company'];
$entry->primaryContact = $data['Primary_contact'];
$entry->sizeHa = $data['Size_ha'];
$entry->specsTrial = $data['Specs_trial'];
$entry->entryStatus = $data['Status'];
$entry->summaryResults = $data['Summary_results'];
$entry->testType = $data['Test_type'];
$entry->variety = $data['Variety'];
$entry->year = $data['Year'];
$entry->entryId = $data['ID'];
$entry->internalSpecsTrial = $data['Internal_specs_trial'];
$entry->prio = $data['Prio'];
$entry->trialName = $data['Trial_name'];
$entry->xy = $data['XY'];
$entry->internalStatusTodo = $data['Internal_status_todo'];
$entry->samplingAnalysis = $data['Sampling_Analysis'];
$entry->statusObservations = $data['Status_Observations'];
$entry->subsidyProject = $data['Subsidy_project'];
$entry->xyRandomiser = $data['XY_randomiser'];
if (Craft::$app->elements->saveElement($entry)) {
Craft::$app->getSession()->setNotice('Entry saved.');
} else {
Craft::$app->getSession()->setError('Couldn’t save the entry: ' . implode(', ', $entry->getErrorSummary(true)));
continue;
}
}
$data = ['message' => 'JSON data read successfully'];
return $this->asJson($data);
}
型
}
编辑的Twig模板
{% extends "_layouts/cp.twig" %}
{% set title = "jsonify"|t('_jsonify') %}
{% set fullPageForm = true %}
{% block content %}
{% set folderId = 1 %}
{% set assets = craft.assets.folderId(folderId).kind('json').all() %}
{% if assets|length %}
<ul class="testing">
{% for asset in assets %}
<li style="width: auto; display: flex; justify-content: space-between; align-items: center">
{% if asset.extension == 'json' %}
{{ asset.filename }}
<form method="post">
{{ csrfInput() }}
{{ actionInput('jsonify/import/test') }}
<button
style="margin-left: 30px; background: #d3d3d3; padding: 3px 12px; border-radius: 4px"
class="json-button"
width="120px"
>
Read JSON
</button>
</form>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>No assets found.</p>
{% endif %}
{% endblock %}
型
按钮内部是触发方法的操作。
此时,模板被加载到设置中。我宁愿有我的插件在一个屏幕,这是从工艺品 Jmeter 板侧栏访问,但我没有线索如何使这发生。.
1条答案
按热度按时间lmvvr0a81#
在我们深入研究之前,您可以尝试第一方Feed Me plugin,它可以从JSON文件导入和同步数据,而无需任何编码。
我想你已经得到了你需要的所有部分,然后一些!😅
1.您不需要配置到控制器的路由-插件会通过动作路由自动暴露其控制器。
**解决方案:**删除
UrlManager::EVENT_REGISTER_SITE_URL_RULES
事件监听器。1.正如您所注意到的,
Craft::$app->onInit()
会在每个请求上触发。**解决方案:**移除此块,允许从您的专用控制器调用插件方法!
1.您的控制器无法自动加载。PHP类必须与它们的文件命名相同。
**解决方案:**将类从
JsonifySettingsController
重命名为ImportController
,将文件重命名为ImportController.php
。该文件必须位于your-plugin-directory/controllers/
目录中,或者位于主插件类旁边的controllers/
目录中。1.只有公共控制器方法可以自动路由。目前你的行动方式是
private
!**解决方案:**方法签名使用
public function actionHandleJsonRead()
。1.您的设置模板包含与内置表单元素冲突的标记。Craft将
getSettingsHtml()
的输出 Package 在<form>
中,该<form>
会自动将值发布到其plugins/save-plugin-settings
操作中。**解决方案:**使用其他模板。将
templates/import.twig
添加到您的插件文件夹中,它将在/admin/jsonify/import
中自动访问!现在不要担心JavaScript和 AJAX 。在基本HTML表单中使用
actionInput()
函数,如下所示:字符串
这将向Craft提交一个正常的HTTP请求,Craft将其路由到您的控制器。
注意:在导入过程中,您已经在后端加载了资源(使用
Asset::find()
)。不需要将其URL作为请求的一部分发送,也不需要从其URL下载资产文件。相反,浏览器将向后端发出请求,后端读取文件并执行导入。1.设置flash消息对JSON请求没有任何影响,多次重复设置相同的flash级别(在本例中为“notice”)将只显示最后一条消息(其他消息被覆盖)。
**解决方案:**通过设置标志跟踪故障,使用
asSuccess()
方法发送响应。action方法的主体可能看起来像这样:型
注意不同的
return
语句。这个方法自动设置flash消息,或者为 AJAX 请求适当地设置它们的格式(如果您想切换回来的话)。我们的消息包括由于重复而未导入的条目数。ImportController::actionIndex()
目前未使用。**解决方案:**删除!
这不能保证是一个完整的解决方案,但希望它有助于清理你有什么,所以它更容易告诉发生了什么!