CakePHP 3:改变结果集的结构

CakePHP 3: Changing structure of result set

我是 CakePHP 新手,遇到以下问题:

我有表格 "Images"、"Keywords" 和 "KeywordCategories"。每个图像都可以有多个关键字(多对多),每个关键字都有一个类别(多对一)。使用

检索图像列表
$images = $this->Images->find()->contain(['Keywords',  'Keywords.KeywordCategories']);

returns 结果结构如下:

[
   {
      "id":1,
      "keywords":[
         {
            "keyword":"Dog",
            "keyword_category":{
               "title":"Animal"
            }
         },
         {
            "keyword":"Cat",
            "keyword_category":{
               "title":"Animal"
            }
         },
         {
            "keyword":"Black",
            "keyword_category":{
               "title":"Color"
            }
         }
      ]
   }
]

很好,但我希望关键字按其关键字类别分组,结构如下:

[
   {
      "id":1,
      "keyword_categories":[
         {
            "title":"Animal",
            "keywords":[
               {
                  "keyword":"Dog"
               },
               {
                  "keyword":"Cat"
               }
            ]
         },
         {
            "title":"Color",
            "keywords":[
               {
                  "keyword":"Black"
               }
            ]
         }
      ]
   }
]

知道如何使用 CakePHP 查询实现吗?

该格式几乎是一个反向包含,仅使用 ORM 关联是不可能的 auto-magic。您将不得不单独获取关联数据,对其进行过滤,然后将其注入图像结果中……您甚至可以创建一个自定义关联 class 来包含、获取并将结果拼接在一起,但这是一种如果你问我太过分了。

因为无论如何你都必须做一些额外的格式化(并且只是为了将结果拼接在一起),我会简单地使用一些 collection 格式化 foo 来代替,类似于

// ...
->find()
->contain(['Keywords', 'Keywords.KeywordCategories'])
->formatResults(function ($results) {
    /* @var $results \Cake\Datasource\ResultSetInterface|\Cake\Collection\CollectionInterface */
    return $results->map(
        function ($image) {
            $image['keyword_categories'] =
                collection($image['keywords'])
                    ->groupBy('keyword_category.title')
                    ->map(function ($keywords, $category) {
                        foreach ($keywords as &$keyword) {
                            unset($keyword['keyword_category']);
                        }
                        return [
                            'title' => $category,
                            'keywords' => $keywords
                        ];
                    })
                    ->toList();
            unset($image['keywords']);
            return $image;
        }
    );
});

* 用于说明目的的未经测试的示例代码

即在每个图像结果上创建一个名为 keyword_categories 的计算字段,由包含的关键字组成,按相关类别标题分组,关键字嵌套在数组中 titlekeywords 从关键字中删除类别的字段,最后 re-index 整个内容作为基本的数字索引数组。

另见