A page
has multiple elements and they are linked using the page_to_elements
table. Each element
has multiple element_fields
and are linked using the element_to_element_fields
. Each element_field
has a type and are linked using the element_to_element_fields
table. The values of each element_field
within the element has a value (eitehr in value_char, value_text or value_num) that is stored in the element_values
table.
Below is how the database structure is:
pages:
id|name
elements:
id|name
element_fields_types (sql_type can be char, text or num):
id|name|sql_type
element_fields (names can be title, intro, content, link, number, etc etc):
id:element_field_type_id|name
element_to_element_fields:
id|element_id|element_field_id
page_to_elements:
id|page_id|element_id
element_values:
id|page_id|element_id|page_to_element_id|element_field_id|value_char|value_text|value_num
What I am looking for is a good hasManyToMany
solution to get all values when I request a page id. I now have multiple loops and array creations to get a structure like this (where the values are from the correct column name based on what was set in the element_fields
):
$page = array(
'elements' => array(
[0] => array(
'element_name_here' => array(
'fields' => array(
[0] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
[1] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
[2] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
)
)
),
[1] => array(
'element_name_here' => array(
'fields' => array(
[0] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
[1] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
[2] => array(
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value',
'field_name_here' => 'Field value'
),
)
)
),
)
);
So I need something like below to produce above array:
$page = Page::find($id);
print_r($page->getValues->toArray());
I have some experience with belongsToMany or hasManyToMany, but never this deep.
Any help would be much appreciated.
Echo the Laravel database name in Blade/PHP This will output the name of the database or return 'none' if there is no connection. If you view it in the browser, it gives you the name of the connected database. Checking whether the application is connected to a Laravel database.
Your schema is quite complex, but I believe you can achieve the structure you want with eager-loading the relations and leveraging collection methods.
<?php
class Page extends Eloquent
{
public function elements()
{
return $this->belongsToMany(Element::class, 'page_to_elements');
}
public function values()
{
return $this->hasMany(Value::class);
}
public function getValues()
{
return $this->values()
// Eager-load the value element, the value field and its type
->with(['element', 'field.type'])->get()
// Group all the values by page element
->groupBy('page_to_element_id')->values()
// Group the values of each page element by the element name
->groupBy(function ($values) {
return $values->first()->element->name;
})
// Iterate each page element
->map(function ($values, $element) {
// Make an array with the element name as key and its fields as value
return [
$element => [
// Group the values by element field
'fields' => $values->groupBy('element_field_id')->values()
// Make an array with the field names and values for each element field
->map(function ($values) {
return $values->pluck('value', 'field.name')->all();
})->all(),
],
];
})->all();
}
}
class Element extends Eloquent
{
public function pages()
{
return $this->belongsToMany(Page::class, 'page_to_elements');
}
public function fields()
{
return $this->belongsToMany(Field::class, 'element_to_element_fields');
}
public function values()
{
return $this->hasMany(Value::class);
}
}
class Field extends Eloquent
{
public function type()
{
return $this->belongsTo(Type::class);
}
public function values()
{
return $this->hasMany(Value::class);
}
}
class Type extends Eloquent
{
public function fields()
{
return $this->hasMany(Field::class);
}
}
class Value extends Eloquent
{
public function page()
{
return $this->belongsTo(Page::class);
}
public function element()
{
return $this->belongsTo(Element::class);
}
public function field()
{
return $this->belongsTo(Field::class);
}
public function getValueAttribute()
{
$type = $this->field->type->sql_type;
return $this->getAttribute('value_'.$type);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With