diff --git a/routes/api.php b/routes/api.php index fa01dfe90..2a9908094 100644 --- a/routes/api.php +++ b/routes/api.php @@ -3,6 +3,7 @@ use Binaryk\LaravelRestify\Http\Controllers\GlobalSearchController; use Binaryk\LaravelRestify\Http\Controllers\RepositoryAttachController; use Binaryk\LaravelRestify\Http\Controllers\RepositoryDestroyController; +use Binaryk\LaravelRestify\Http\Controllers\RepositoryDetachController; use Binaryk\LaravelRestify\Http\Controllers\RepositoryFilterController; use Binaryk\LaravelRestify\Http\Controllers\RepositoryIndexController; use Binaryk\LaravelRestify\Http\Controllers\RepositoryShowController; @@ -26,3 +27,4 @@ // Attach related repository id Route::post('/{repository}/{repositoryId}/attach/{relatedRepository}', '\\'.RepositoryAttachController::class); +Route::post('/{repository}/{repositoryId}/detach/{relatedRepository}', '\\'.RepositoryDetachController::class); diff --git a/src/Http/Controllers/RepositoryDetachController.php b/src/Http/Controllers/RepositoryDetachController.php new file mode 100644 index 000000000..1adeb4a1d --- /dev/null +++ b/src/Http/Controllers/RepositoryDetachController.php @@ -0,0 +1,64 @@ +findModelOrFail(); + $repository = $request->repository()->allowToUpdate($request); + + return $repository->detach( + $request, $request->repositoryId, + collect(Arr::wrap($request->input($request->relatedRepository))) + ->map(fn ($relatedRepositoryId) => $this->initializePivot( + $request, $model->{$request->viaRelationship ?? $request->relatedRepository}(), $relatedRepositoryId + )) + ); + } + + /** + * Initialize a fresh pivot model for the relationship. + * + * @param RestifyRequest $request + * @param $relationship + * @return mixed + * @throws \Binaryk\LaravelRestify\Exceptions\Eloquent\EntityNotFoundException + * @throws \Binaryk\LaravelRestify\Exceptions\UnauthorizedException + */ + protected function initializePivot(RestifyRequest $request, $relationship, $relatedKey) + { + $parentKey = $request->repositoryId; + + $parentKeyName = $relationship->getParentKeyName(); + $relatedKeyName = $relationship->getRelatedKeyName(); + + if ($parentKeyName !== $request->model()->getKeyName()) { + $parentKey = $request->findModelOrFail()->{$parentKeyName}; + } + + if ($relatedKeyName !== ($request->newRelatedRepository()::newModel())->getKeyName()) { + $relatedKey = $request->findRelatedModelOrFail()->{$relatedKeyName}; + } + + ($pivot = $relationship->newPivot())->forceFill([ + $relationship->getForeignPivotKeyName() => $parentKey, + $relationship->getRelatedPivotKeyName() => $relatedKey, + ]); + + if ($relationship->withTimestamps) { + $pivot->forceFill([ + $relationship->createdAt() => new DateTime, + $relationship->updatedAt() => new DateTime, + ]); + } + + return $pivot; + } +} diff --git a/src/Http/Requests/RepositoryDetachRequest.php b/src/Http/Requests/RepositoryDetachRequest.php new file mode 100644 index 000000000..15987806d --- /dev/null +++ b/src/Http/Requests/RepositoryDetachRequest.php @@ -0,0 +1,7 @@ +created(); } + public function detach(RestifyRequest $request, $repositoryId, Collection $pivots) + { + $deleted = DB::transaction(function () use ($request, $pivots) { + return $pivots->map(fn ($pivot) => $pivot->delete()); + }); + + return $this->response() + ->data($deleted) + ->deleted(); + } + public function destroy(RestifyRequest $request, $repositoryId) { $status = DB::transaction(function () { diff --git a/tests/Controllers/RepositoryAttachControllerTest.php b/tests/Controllers/RepositoryAttachControllerTest.php new file mode 100644 index 000000000..24e2ade68 --- /dev/null +++ b/tests/Controllers/RepositoryAttachControllerTest.php @@ -0,0 +1,66 @@ +mockUsers(2)->first(); + $company = factory(Company::class)->create(); + + $response = $this->postJson('restify-api/companies/'.$company->id.'/attach/users', [ + 'users' => $user->id, + 'is_admin' => true, + ]) + ->assertStatus(201); + + $response->assertJsonFragment([ + 'company_id' => '1', + 'user_id' => $user->id, + 'is_admin' => true, + ]); + } + + public function test_attach_multiple_users_to_a_company() + { + $user = $this->mockUsers(2)->first(); + $company = factory(Company::class)->create(); + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(0, $usersFromCompany->json('data')); + + $response = $this->postJson('restify-api/companies/'.$company->id.'/attach/users', [ + 'users' => [1, 2], + 'is_admin' => true, + ]) + ->assertStatus(201); + + $response->assertJsonFragment([ + 'company_id' => '1', + 'user_id' => $user->id, + 'is_admin' => true, + ]); + + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(2, $usersFromCompany->json('data')); + } + + public function test_after_attach_a_user_to_company_number_of_users_increased() + { + $user = $this->mockUsers()->first(); + $company = factory(Company::class)->create(); + + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(0, $usersFromCompany->json('data')); + + $this->postJson('restify-api/companies/'.$company->id.'/attach/users', [ + 'users' => $user->id, + ]); + + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(1, $usersFromCompany->json('data')); + } +} diff --git a/tests/Controllers/RepositoryDetachControllerTest.php b/tests/Controllers/RepositoryDetachControllerTest.php new file mode 100644 index 000000000..8d049a70c --- /dev/null +++ b/tests/Controllers/RepositoryDetachControllerTest.php @@ -0,0 +1,42 @@ +mockUsers(2)->first(); + $company = factory(Company::class)->create(); + $company->users()->attach($user->id); + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(1, $usersFromCompany->json('data')); + $this->postJson('restify-api/companies/'.$company->id.'/detach/users', [ + 'users' => $user->id, + ]) + ->assertStatus(204); + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(0, $usersFromCompany->json('data')); + } + + public function test_detach_multiple_users_from_a_company() + { + $users = $this->mockUsers(3); + $company = factory(Company::class)->create(); + $company->users()->attach($users->pluck('id')); + + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(3, $usersFromCompany->json('data')); + + $this->postJson('restify-api/companies/'.$company->id.'/detach/users', [ + 'users' => [1, 2], + ]) + ->assertStatus(204); + + $usersFromCompany = $this->getJson('/restify-api/users?viaRepository=companies&viaRepositoryId=1&viaRelationship=users'); + $this->assertCount(1, $usersFromCompany->json('data')); + } +}