diff --git a/src/Fields/BelongsToMany.php b/src/Fields/BelongsToMany.php index 257c8cdd..b8baf45e 100644 --- a/src/Fields/BelongsToMany.php +++ b/src/Fields/BelongsToMany.php @@ -82,6 +82,10 @@ public function fields(Request $request): array $this->getRelation($model->pivotParent)->select($query->getModel()->getQualifiedKeyName()) ); }); + })->hydrate(function (Request $request, Pivot $model, mixed $value): void { + $relation = $this->getRelation($model->pivotParent); + + $model->setAttribute($relation->getRelatedPivotKeyName(), $value); })->display(function (Model $model): ?string { return $this->resolveDisplay($model); }), @@ -249,11 +253,11 @@ public function routes(Router $router): void if ($this->isSubResource()) { $router->get('/', [BelongsToManyController::class, 'index']); $router->get('/create', [BelongsToManyController::class, 'create']); - $router->get("/{{$this->getRouteKeyName()}", [BelongsToManyController::class, 'show']); + $router->get("/{{$this->getRouteKeyName()}}", [BelongsToManyController::class, 'show']); $router->post('/', [BelongsToManyController::class, 'store']); - $router->get("/{{$this->getRouteKeyName()}/edit", [BelongsToManyController::class, 'edit']); - $router->patch("/{{$this->getRouteKeyName()}", [BelongsToManyController::class, 'update']); - $router->delete("/{{$this->getRouteKeyName()}", [BelongsToManyController::class, 'destroy']); + $router->get("/{{$this->getRouteKeyName()}}/edit", [BelongsToManyController::class, 'edit']); + $router->patch("/{{$this->getRouteKeyName()}}", [BelongsToManyController::class, 'update']); + $router->delete("/{{$this->getRouteKeyName()}}", [BelongsToManyController::class, 'destroy']); } } diff --git a/src/Fields/MorphToMany.php b/src/Fields/MorphToMany.php index 454e2d6f..240b112d 100644 --- a/src/Fields/MorphToMany.php +++ b/src/Fields/MorphToMany.php @@ -43,6 +43,13 @@ public function fields(Request $request): array $this->getRelation($model->pivotParent)->select($query->getModel()->getQualifiedKeyName()) ); }); + })->hydrate(function (Request $request, MorphPivot $model): void { + $relation = $this->getRelation($model->pivotParent); + + $model->setAttribute( + $relation->getRelatedPivotKeyName(), + $model->related->getAttribute($relation->getRelatedKeyName()) + ); })->display(function (Model $model): mixed { return $this->resolveDisplay($model); }), diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index e99be184..d4b28117 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -25,6 +25,7 @@ use Illuminate\Database\Eloquent\Relations\Relation as EloquentRelation; use Illuminate\Http\Request; use Illuminate\Routing\Events\RouteMatched; +use Illuminate\Routing\Route; use Illuminate\Routing\Router; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; @@ -605,13 +606,17 @@ public function paginate(Request $request, Model $model): LengthAwarePaginator { $relation = $this->getRelation($model); - return $this->resolveFilters($request) - ->apply($request, $relation->getQuery()) + $this->resolveFilters($request)->apply($request, $relation->getQuery()); + + return $relation ->with($this->with) ->withCount($this->withCount) ->latest() - ->paginate($request->input($this->getPerPageKey(), $request->isTurboFrameRequest() ? 5 : $relation->getRelated()->getPerPage())) - ->withQueryString(); + ->paginate( + $request->input($this->getPerPageKey(), $request->isTurboFrameRequest() + ? 5 + : $relation->getRelated()->getPerPage()) + )->withQueryString(); } /** @@ -838,10 +843,10 @@ public function routes(Router $router): void */ public function registerRouteConstraints(Request $request, Router $router): void { - $router->bind($this->getRouteKeyName(), function (string $id) use ($request): Model { + $router->bind($this->getRouteKeyName(), function (string $id, Route $route) use ($router): Model { return $id === 'create' - ? $this->getRelation($request->route()->parentOfParameter($this->getRouteKeyName()))->make() - : $this->resolveRouteBinding($request, $id); + ? $this->getRelation($route->parentOfParameter($this->getRouteKeyName()))->make() + : $this->resolveRouteBinding($router->getCurrentRequest(), $id); }); } diff --git a/tests/Http/BelongsToManyControllerTest.php b/tests/Http/BelongsToManyControllerTest.php index 5bc3702d..8a9eed41 100644 --- a/tests/Http/BelongsToManyControllerTest.php +++ b/tests/Http/BelongsToManyControllerTest.php @@ -12,6 +12,8 @@ class BelongsToManyControllerTest extends TestCase { protected User $admin; + protected Team $team; + protected BelongsToMany $field; public function setUp(): void @@ -20,6 +22,12 @@ public function setUp(): void $this->admin = User::factory()->create(); + $this->team = Team::factory()->create(); + + $this->admin->teams()->attach([ + $this->team->getKey() => ['role' => 'admin'], + ]); + $this->field = Root::instance() ->resources ->resolve('users') @@ -45,7 +53,7 @@ public function test_a_belongs_to_many_controller_handles_store(): void $this->actingAs($this->admin) ->post('/root/users/'.$this->admin->getKey().'/fields/teams', [ 'related' => $team->getKey(), - 'role' => 'admin', + 'role' => 'member', ]) ->assertRedirect() ->assertSessionHas('alerts.relation-created'); @@ -53,7 +61,36 @@ public function test_a_belongs_to_many_controller_handles_store(): void $this->assertDatabaseHas('team_user', [ 'user_id' => $this->admin->getKey(), 'team_id' => $team->getKey(), - 'role' => 'admin', + 'role' => 'member', ]); } + + public function test_a_belongs_to_many_controller_handles_update(): void + { + $team = $this->admin->teams->first(); + + $this->assertSame('admin', $team->pivot->role); + + $this->actingAs($this->admin) + ->patch('/root/users/'.$this->admin->getKey().'/fields/teams/'.$team->pivot->getKey(), [ + 'related' => $team->getKey(), + 'role' => 'member', + ]) + ->assertRedirect() + ->assertSessionHas('alerts.relation-updated'); + + $this->assertSame('member', $team->pivot->refresh()->role); + } + + public function test_a_belongs_to_many_controller_handles_destroy(): void + { + $team = $this->admin->teams->first(); + + $this->actingAs($this->admin) + ->delete('/root/users/'.$this->admin->getKey().'/fields/teams/'.$team->pivot->getKey()) + ->assertRedirect() + ->assertSessionHas('alerts.relation-deleted'); + + $this->assertDatabaseMissing('team_user', ['id' => $team->pivot->getKey()]); + } } diff --git a/tests/User.php b/tests/User.php index e9a250f2..5dbe3753 100644 --- a/tests/User.php +++ b/tests/User.php @@ -18,6 +18,8 @@ class User extends Model implements MustVerifyEmail protected $guarded = []; + protected $table = 'users'; + protected static function newFactory(): UserFactory { return new class() extends UserFactory @@ -49,6 +51,6 @@ public function documents(): MorphToMany public function teams(): BelongsToMany { return $this->belongsToMany(Team::class) - ->withPivot('role'); + ->withPivot(['id', 'role']); } }