DEV Community

Serhii
Serhii

Posted on

How to display two fields with same name in BackPack For Laravel

Table Of Contents

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);
});
Enter fullscreen mode Exit fullscreen mode

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');
    }
}
Enter fullscreen mode Exit fullscreen mode

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',
    ]
]);
Enter fullscreen mode Exit fullscreen mode

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:
Two fields in form

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
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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',
    ]
]);
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

Works!

Four fields in admin panel

Good luck folk!

Top comments (1)

Collapse
 
polfo profile image
Polfo

I go for this method, which is clean.
backpackforlaravel.com/docs/4.1/cr...