Skip to content

Instantly share code, notes, and snippets.

@pxpm
Last active January 20, 2022 17:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pxpm/516f55c303235b799ac4e38f1167094e to your computer and use it in GitHub Desktop.
Save pxpm/516f55c303235b799ac4e38f1167094e to your computer and use it in GitHub Desktop.
Backpack 4.1 BelongsToMany with pivot data
<?php
namespace App\Http\Controllers;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation { store as traitStore; } //IMPORTANT HERE
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation { update as traitUpdate; } //IMPORTANT HERE
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
protected function setupListOperation()
{
CRUD::column('name');
}
protected function setupCreateOperation()
{
CRUD::field('name');
CRUD::field('roles_list')
->type('repeatable')
->label('Roles')
->fields([
[
'name' => 'role_id',
'type' => 'select2',
'model' => 'App\Models\Role',
'attribute' => 'name'
],
[
'name' => 'pivot_field',
'type' => 'text'
]
]);
}
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
}
protected function setupShowOperation()
{
CRUD::column('name');
}
public function store()
{
$roles = collect(json_decode(request('roles_list'), true));
$response = $this->traitStore();
$this->crud->entry->roles()->sync($roles);
return $response;
};
public function update()
{
$roles = collect(json_decode(request('roles_list'), true));
$response = $this->traitUpdate();
$this->crud->entry->roles()->sync($roles);
return $response;
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use \Backpack\CRUD\app\Models\Traits\CrudTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'id' => 'integer',
];
public function roles()
{
return $this->belongsToMany(\App\Models\Role::class)->withPivot('pivot_field'); //IMPORTANT: use withPivot!
}
//acessor to get the roles populated in the repeatable field again
public function getRolesListAttribute() {
return json_encode($this->roles->map(function($role) {
return ['role_id' => $role->id, 'pivot_field' => $role->pivot->pivot_field];
}));
}
}
@tabacitu
Copy link

@pxpm - can you rename these files to add the .php extension? Without it there's no syntax highlighting 🙏

@kiddtang
Copy link

kiddtang commented Dec 3, 2021

The update may generate duplicate records in the pivot table, I encounter this issue.

This is a behavior of the sync method. Then I found the solution

So, for update method, transform the int key into a random string.

$roles = [];
foreach(json_decode(request('roles_list'), true) as $role)
{
    $jobs[Str::random(5)] = $role;
}

Then, the duplication of pivot entries will not happen. Hope it helps.

@realtebo
Copy link

@kiddtang To avoid this behaviour, saving the main model, we remove all related relations and resave them all from scratch based on what we receive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment