Reputation: 93
I'm trying to figure out how to have to make a custom attribute when I'm setting up fields with relationship.
So I have students who are having a hasMany relationship with promotions. Now my problem is when the attribute that I want is in another model/table. For example I need the belt color, but the belt color is not stored in promotions.. promotion table holds just the belt_id. I need to extract the color of that belt from the belts table. I have all the relationships set up but I don't know how to manipulate the attribute. I hope this makes sense.
$this->crud->addField([
'label' => "Promotions",
'type' => 'select2_multiple',
'name' => 'promotion',
'entity' => 'promotion',
'attribute' => 'name', // <- how can I make a custom query for this?
'pivot' => true,
]);
Thank you!
Upvotes: 0
Views: 1396
Reputation: 93
It looks like I found a solution and fixed a little bug.. at least It looks like to be a bug cuz I can't find the documentation for this feature.. I found it by inspecting the code. Anyway the cool thing is that we can chain relationships with ".", so the column setup will look like this:
$this->crud->addColumn([
'label' => "Rank", // Table column heading
'type' => "select",
'name' => 'promotion_id', // the column that contains the ID of that connected entity;
'entity' => 'promotion.belt', // <- here I'm chaining the model relationships
'attribute' => 'color', // the belt's attribute
'model' => "App\Models\Promotion" // foreign key model
]);
In theory everything should work fine but there is a lil bug in a method located in vendore\backpack\crud\src\CrudPanel.php
:
private function getRelationModelInstances($model, $relationString)
{
$relationArray = explode('.', $relationString);
$firstRelationName = array_first($relationArray);
// this is the line with the bug
//$relation = $model->{$firstRelationName};
// Fix the bug above
if($model instanceof Collection) {
$relation = $model->{$firstRelationName};
} else {
$relation = $model[$firstRelationName];
}
$results = [];
if (! empty($relation)) {
if ($relation instanceof Collection) {
$currentResults = $relation->toArray();
} else {
$currentResults[] = $relation;
}
array_shift($relationArray);
if (! empty($relationArray)) {
foreach ($currentResults as $currentResult) {
$results = array_merge($results, $this->getRelationModelInstances($currentResult, implode('.', $relationArray)));
}
} else {
$results = $currentResults;
}
}
return $results;
}
Basically this recursive function when is calling itself it passes the $model
parameter as an array
not object
.. so when it s trying to get $firstRelationName
from the $model
like this $model->{$firstRelationName}
will result in an error.
Meanwhile I discovered a better solution. To accomplish the same goal, I used accessors
.
In my promotion
model I have:
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function belt()
{
return $this->belongsTo('App\Models\Belt');
}
/*
|--------------------------------------------------------------------------
| ACCESORS
|--------------------------------------------------------------------------
*/
public function getPromotionSummaryAttribute()
{
return $this->belt()->get()[0]->color . ', ' . $this->stripe . ' stripe';
}
And for students
I have:
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function promotion()
{
return $this->hasMany('App\Models\Promotion');
}
/*
|--------------------------------------------------------------------------
| ACCESORS
|--------------------------------------------------------------------------
*/
public function GetLastPromotionAttribute()
{
return $this->promotion()->get()->last()->promotion_summary;
}
And the column setup will be simple like this:
$this->crud->addColumn([
'name' => 'last_promotion',
'type' => 'text',
'label' => 'Rank'
]);
I hope this will help someone out there :)
Upvotes: 2