Я новичок в CakePHP и имею следующую проблему:
У меня есть таблицы «Изображения», «Ключевые слова» и «Ключевые слова». Каждое изображение может иметь много ключевых слов (много ко многим), и у каждого ключевого слова есть категория (много к одному). Получение списка изображений с
$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?
Этот формат в значительной степени является перевернутым содержимым, что невозможно при использовании только автоматической магии ассоциации ORM. Вы должны были бы выбрать связанные данные отдельно, отфильтровать их и вставить их в результаты изображения … вы могли бы даже создать собственный класс ассоциации, который содержит, выбирает и объединяет результаты вместе, но это своего рода излишество, если вы спросите мне.
Так как вам все равно придется делать дополнительное форматирование (и это просто для сшивания результатов), я бы просто использовал вместо этого некоторое форматирование коллекции 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
на каждом изображении результат, состоящий из содержащихся ключевых слов, сгруппированных по названию связанных категорий, с ключевыми словами, вложенными в массив с title
а также keywords
поля, в которых категория удаляется из ключевых слов, и, наконец, переиндексировать все это как базовый числовой индексированный массив.
Смотрите также
Других решений пока нет …