Как трансформировать получаемые данные?
products
--- id
--- name
attributes
--- id
--- name
attribute_values
--- id
--- attribute_id
--- name
attribute_value_product
--- id
--- attribute_value_id
--- product_id
Products
- Продукту может принадлежать много Значений.
Attributes
- Атрибуту может принадлежать много Значений.
Attribute Values
- Значению может принадлежать один Атрибут.
- Значению может принадлежать много Продуктов.
Как я получаю эти данные во View.
foreach ($products as $product) {
foreach ($product->attributeValues as $value) {
$value->attribute->name
$value->name
}
}
Ищу способ трансформировать данные, чтобы во View я мог получить что-то похожее на это.
{
id: 2,
name: "Product 2",
attributes: [
{
name: "weight",
values: [
"1.3kg"
]
},
{
name: "style",
values: [
"something nice"
]
},
{
name: "color",
values: [
"yellow",
"black",
"orange"
]
}
]
}
Имеется возможность вносить любые изменения в проект.
Ответы (3 шт):
Для этого нужно описать связи в моделях, все нужные таблицы в БД у вас уже есть.
Модель Product:
...
public function features() {
return $this->belongsToMany(Feature::class)
->using(FeatureProduct::class);
}
Модель Feature:
...
public function values() {
$this->hasMany(FeatureValue::class);
}
// связь с product, если понадобится
public function products() {
return $this->belongsToMany(Product::class)
->using(FeatureProduct::class);
}
После этого можете обращаться ко всем характеристикам товара $product->features и ко всем значениям характеристики $feature->values, то есть использовать свой цикл, который хотели.
UPD: Теперь понял, тогда как вариант можно ликвидировать таблицу feature_values. Вместо этого добавить поле feature_id в таблицу features. У характеристик feature_id будет null, а у значений характеристик в этом поле будет id характеристики, к которой они относятся. Тогда $product->features выведет все значения характеристик с их именами. Если нужно, то при запросе этих характеристик можно будет разбить их по категориям с помощью keyBy('feature_id').
Можно попробовать создать доп. метод в модели Product для трансформации данных.
class Product extends Model
{
// ...
public function getAttributesData()
{
$attributes = $this->attributeValues->groupBy('attribute.name');
$attributesData = [];
foreach ($attributes as $attributeName => $values) {
$attributesData[] = [
'name' => $attributeName,
'values' => $values->pluck('name')->toArray()
];
}
return $attributesData;
}
}
View:
foreach ($products as $product) {
$productData = [
'id' => $product->id,
'name' => $product->name,
'attributes' => $product->getAttributesData()
];
// использование $productData для отображения во View
}
Можно применить collection helper функции groupBy(), map() и toArray() для трансформации данных:
$products->map(function ($product) {
return [
'id' => $product->id,
'name' => $product->name,
'attributes' => $product->attributeValues->groupBy('attribute.name')->map(function ($values, $name) {
return ['name' => $name, 'values' => $values->pluck('name')->toArray()];
})->values()->toArray()
];
});
Если вы хотите получить действительно гибкие связи необходимо использовать преимущества ООП. Для этого необходимо подняться на более высокий уровень абстракции и описать таблицу иерархических классов, таблицу его свойств и таблицу значений свойств класса. Каждая фактическая сущность будет наследовать id класса, приобретая коллекцию его атрибутов, значений по умолчанию и возможность осознанного поиска по значению атрибута в контексте иерархии. Это дает гибкость EAV и JSON но при этом таковым по факту не является, так как дает возможность описать и индексировать возможные варианты поиска.