php 提交 AJAX 请求时不会触发自定义插件方法

u0sqgete  于 2023-08-02  发布在  PHP
关注(0)|答案(1)|浏览(97)

我已经创建了一个自定义插件在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 板侧栏访问,但我没有线索如何使这发生。.

lmvvr0a8

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()函数,如下所示:

<form method="post">
    {{ csrfInput() }}
    {{ actionInput('jsonify/import/handle-json-read') }}

    <button>Import JSON Data</button>
</form>

字符串
这将向Craft提交一个正常的HTTP请求,Craft将其路由到您的控制器。
注意:在导入过程中,您已经在后端加载了资源(使用Asset::find())。不需要将其URL作为请求的一部分发送,也不需要从其URL下载资产文件。相反,浏览器将向后端发出请求,后端读取文件并执行导入。
1.设置flash消息对JSON请求没有任何影响,多次重复设置相同的flash级别(在本例中为“notice”)将只显示最后一条消息(其他消息被覆盖)。

**解决方案:**通过设置标志跟踪故障,使用asSuccess()方法发送响应。action方法的主体可能看起来像这样:

$failures = 0;

foreach ($jsonFile as $key => $data) {
   // ... look up existing entry

   if ($existingEntry) {
       $failures++;

       continue;
   }

   // ... do import
}

// ...

return $this->asSuccess(Craft::t('jsonify', 'Import complete, skipping {num} duplicate record(s).', ['num' => $failures]));


注意不同的return语句。这个方法自动设置flash消息,或者为 AJAX 请求适当地设置它们的格式(如果您想切换回来的话)。我们的消息包括由于重复而未导入的条目数。

  1. ImportController::actionIndex()目前未使用。

**解决方案:**删除!

这不能保证是一个完整的解决方案,但希望它有助于清理你有什么,所以它更容易告诉发生了什么!

相关问题