Table Of Contents
- Real case
- What need to do?
- Bad solution (wrong way)
- Wrong result
- Better solution (Accessors & Mutators)
- Do not forget about Storing!
- Works!
Have you ever heard anything about BackPack for Laravel?
It's Laravel Admin Panel. Fast & easy to integrate. But then could be some issues... For example:
Real case
You have a two tables (order and person):
Schema::create('orders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('primary_person');
$table->unsignedBigInteger('secondary_person');
});
Schema::create('persons', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name', 255);
$table->string('last_name', 255);
});
Each order has relation to primary and secondary persons by ID:
class Order extends Model
{
use CrudTrait;
protected $table = 'orders';
protected $fillable = [
'primary_person',
'secondary_person',
];
public function primaryPerson()
{
return $this->hasOne(Person::class, 'id', 'primary_person');
}
public function secondaryPerson()
{
return $this->hasOne(Person::class, 'id', 'secondary_person');
}
}
What need to do?
BackPackForLaravel provides possibility to quickly generate CRUD pages. In our case we need to edit order page.
So, let's create text inputs for:
- First name of Primary person
- Last name of Primary person
- First name of Secondary person
- Last name of Secondary person
Bad solution (wrong way)
According to documentation in OrderCrudController.php need to add:
$this->crud->addFields([
[
'label' => 'First Name of Primary person',
'type' => 'text',
'name' => 'first_name',
'entity' => 'primaryPerson',
'model' => 'App\Models\Person',
],
[
'label' => 'Last Name of Primary person',
'type' => 'text',
'name' => 'last_name',
'entity' => 'primaryPerson',
'model' => 'App\Models\Person',
],
[
'label' => 'First Name of Secondary person',
'type' => 'text',
'name' => 'first_name',
'entity' => 'secondaryPerson',
'model' => 'App\Models\Person',
],
[
'label' => 'Last Name of Secondary person',
'type' => 'text',
'name' => 'last_name',
'entity' => 'secondaryPerson',
'model' => 'App\Models\Person',
]
]);
Wrong result
Attribute name in controller it's also name in text input.
It have to be uniq!
So, we get only latest two inputs:
Let's think how to cheat.
Better solution (Accessors & Mutators)
Go to Laravel's documentation and read about accessors and mutators.
We could define new names of same field.
For example,
Primary person fields become:
primary_first_name
primary_last_name
Secondary person fields become:
secondary_first_name
secondary_last_name
Let's create two models. PrimaryPerson:
namespace App\Models;
class PrimaryPerson extends Person
{
public function getPrimaryFirstNameAttribute()
{
return $this->attributes['first_name'];
}
public function setPrimaryFirstNameAttribute($value)
{
$this->attributes['first_name'] = $value;
}
public function getPrimaryLastNameAttribute()
{
return $this->attributes['last_name'];
}
public function setPrimaryLastNameAttribute($value)
{
$this->attributes['last_name'] = $value;
}
}
and SecondaryPerson:
namespace App\Models;
class SecondaryPerson extends Person
{
public function getSecondaryFirstNameAttribute()
{
return $this->attributes['first_name'];
}
public function setSecondaryFirstNameAttribute($value)
{
$this->attributes['first_name'] = $value;
}
public function getSecondaryLastNameAttribute()
{
return $this->attributes['last_name'];
}
public function setSecondaryLastNameAttribute($value)
{
$this->attributes['last_name'] = $value;
}
}
New we can change Fields in OrderCrudController.php
$this->crud->addFields([
[
'label' => 'First Name of Primary person',
'type' => 'text',
'name' => 'primary_first_name',
'entity' => 'primaryPerson',
],
[
'label' => 'Last Name of Primary person',
'type' => 'text',
'name' => 'primary_last_name',
'entity' => 'primaryPerson',
],
[
'label' => 'First Name of Secondary person',
'type' => 'text',
'name' => 'secondary_first_name',
'entity' => 'secondaryPerson',
],
[
'label' => 'Last Name of Secondary person',
'type' => 'text',
'name' => 'secondary_last_name',
'entity' => 'secondaryPerson',
]
]);
Do not forget about Storing!
Fetching works good, but we broke store action. Need to implement custom one.
public function update(UpdateRequest $request)
{
$this->crud->hasAccessOrFail('update');
$this->crud->setOperation('update');
if (is_null($request)) {
$request = \Request::instance();
}
/* Storing main object
$item = $this->crud->update($request->get($this->crud->model->getKeyName()),
$request->only([
'primary_person',
'secondary_person',
])
);
$this->data['entry'] = $this->crud->entry = $item;
*/
$this->updatePrimaryPerson($request);
$this->updateSecondaryPerson($request);
\Alert::success(trans('backpack::crud.update_success'))->flash();
$this->setSaveAction();
return $this->performSaveAction($item->getKey());
}
private function updatePrimaryPerson(UpdateRequest $request)
{
$person = PrimaryPerson::find($this->crud->entry->primary_person);
$person->primary_first_name = $request->get('primary_first_name');
$person->primary_last_name = $request->get('primary_last_name');
$person->save();
}
private function updateSecondaryPerson(UpdateRequest $request)
{
$person = SecondaryPerson::find($this->crud->entry->secondary_person);
$person->secondary_first_name = $request->get('secondary_first_name');
$person->secondary_last_name = $request->get('secondary_last_name');
$person->save();
}
Works!
Good luck folk!
Top comments (1)
I go for this method, which is clean.
backpackforlaravel.com/docs/4.1/cr...