How to display two fields with same name in BackPack For Laravel
Tags: laravel, backpackforlaravel
Published: 2020-01-15 16:29:48

## Table Of Contents
* [Real case](#real-case)
* [What need to do?](#what-need-to-do)
* [Bad solution (wrong way)](#bad-solution)
* [Wrong result](#wrong-result)
* [Better solution (Accessors & Mutators)](#better-solution)
* [Do not forget about Storing!](#storing)
* [Works!](#works)

Have you ever heard anything about [BackPack for Laravel](https://backpackforlaravel.com/)?
It's **Laravel Admin Panel**. Fast & easy to integrate. But then could be some issues... For example:

## Real case <a name="real-case"></a>
You have a two tables (order and person):
```php
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:
```php
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? <a name="what-need-to-do"></a>
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) <a name="bad-solution"></a>

According to [documentation](https://backpackforlaravel.com/docs/4.0/crud-fields) in *OrderCrudController.php* need to add:
```php
$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 <a name="wrong-result"></a>
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](https://i.stack.imgur.com/cDLN5.png)

Let's think how to cheat.

## Better solution (Accessors & Mutators) <a name="better-solution"></a>
Go to Laravel's [documentation](https://laravel.com/docs/5.8/eloquent-mutators#accessors-and-mutators) 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:
```php
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:
```php
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*
```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! <a name="storing"></a>
Fetching works good, but we broke store action. Need to implement custom one.
```php
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! <a name="works"></a>
![Four fields in admin panel](https://i.stack.imgur.com/B6Fb8.png)

Good luck folk!