在渲染之前重新安排对象上的 CakePHP JSON 响应

Re-arrange a CakePHP JSON response on object prior to render

我正在开发基于 API 的 CakePHP REST/CRUD。它在 /config/routes.php 中使用 $routes->setExtensions(['json']); 将它的响应变成 json 个对象。

我正在处理几个具有复杂模式的对象,我需要在提交给 CakeORM 之前对其进行预处理,以便为最终用户简化 API 集成。

例如,以下是 json 需要使用 $this->ImportSettings->patchEntity($importSetting, $requestData[2]) 修补到 ORM 的 blob:

    {
        "id": 2,
        "generic_setting": "Hello World",
        "import_source_google_setting": null,
        "import_source_csv_ordered_setting": null,
        "import_source_csv_headed_setting": {
            "id": 1,
            "import_settings_id": 2,
            "delimiterId": 1 
        },
        "import_destination_user_setting": null,
        "import_destination_asset_setting": {
            "id": 2,
            "import_settings_id": 2,
            "defaultValueId": 1 
        }
    }

导入设置中可以定义多个来源之一和多个指定设置之一。为了简化 API 用户的操作,我允许他们提交以下内容:

    {
        "id": 2,
        "generic_setting": "Hello World",
        "import_source_setting": {
            "id": 1,
            "import_settings_id": 2,
            "delimiterId": 1 
        },
        "import_destination_setting": {
            "id": 2,
            "import_settings_id": 2,
            "defaultValueId": 1 
        }
    }

我已经在 beforeMarshal 上为 ImportSesttings 编写了一个事件侦听器代码,它能够判断索引“import_source_setting”是否属于 table 中的“[=35” =]”、“import_source_csv_ordered_setting”或“import_source_google_setting”,同样,资产和用户设置进入“import_destination_setting”。

这很适合在请求进入 ORM 之前处理请求中的重新组织数据。但是,我现在想在显示数据之前对数据执行相同的操作,因此 API 用户不需要查看其他源和目标设置。

我已经通过在系统另一部分的类似用例中使用中间件来实现这一点。然而,中间件似乎是附加到路由上的,我的使用似乎更像是应该与模型生命周期相关联的东西,因此只要返回导入设置并正确修改输出,它就会运行,即使嵌套时也是如此。

考虑到我正在寻找的内容,我应该将重新组织 json 对 table 的 ORM 查询结果的响应的逻辑放在 Cake 的哪一部分?你能告诉我这方面的文档吗?

我在另一个论坛上使用 CakePHP's calculated fields 找到了这个问题的答案。看起来 formatResults() 函数可以附加到带有回调的查询,以便在查询 运行 后重新组织结果。我继续将它附加到 beforeFind() 事件中的查询,这似乎有效。

参见下面的示例:

<?php

class ImportSettingsListener implements Cake\Event\EventListenerInterface
{
    public function implementedEvents(): array
    {
        return [
            'Model.beforeFind' => 'generateQuery',
        ];
    }

    public function generateQuery(Event $event, Query $query, ArrayObject $options, bool $primary): void
    {
        $query->formatResults(function (CollectionInterface $results) {
            return $results->map(function ($setting) {
                // Re-format $setting here
                return $setting;
            });
        });
    }
}