CakePHP 3: 改变结果集的结构

5

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

我有三个表格,“Images”、“Keywords”和“KeywordCategories”。每张图片可以有多个关键词(多对多),每个关键词都有一个类别(多对一)。通过下面的代码获取图片列表:

$images = $this->Images->find()->contain(['Keywords',  'Keywords.KeywordCategories']);

返回一个类似于这样的结果结构:
[
   {
      "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查询实现此目标吗?

1个回答

9
那种格式基本上是一个反向容器,仅使用ORM的关联自动魔法是不可能实现的。您需要单独获取关联数据、进行过滤并将其注入到图像结果中……您甚至可以创建一个自定义关联类,其中包含获取和拼接结果,但如果您问我,那有点过度投入。

既然您必须进行一些额外的格式化(而且仅用于将结果拼接在一起),我建议使用集合格式化工具,例如

// ...
->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字段的数组中,其中从关键字中删除了类别,并最终将整个内容重新索引为基本数字索引数组。

另请参见:

* 未经测试的示例代码仅供说明目的


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接