appIds)) { return; } $records = array_map(fn (int $appId) => [ 'role_id' => $data->roleId, 'app_id' => $appId, 'duration' => $data->duration, ], $data->appIds); AppRole::query()->upsert( $records, ['role_id', 'app_id'], ['duration'] ); } /** * Remove an app-role assignment. * * @throws InvalidArgumentException when id is invalid. * @throws Throwable when an error occurs during the deletion. */ public function detach(int $id): void { if ($id <= 0) { throw new InvalidArgumentException('Invalid id'); } DB::transaction(function () use ($id): void { AppRole::query()->findOrFail($id)->delete(); }); } /** * Get all apps assigned to a given role. * * @return DataCollection */ #[NoDiscard] public function getAppsForRole(int $roleId): DataCollection { $assignments = AppRole::query() ->with('app:id,name') ->where('role_id', $roleId) ->orderBy('id') ->get(['id', 'app_id', 'role_id', 'duration']); return RoleAppData::collect( $assignments->map(fn (AppRole $row): array => [ 'id' => $row->id, 'appId' => $row->app_id, 'appName' => $row->app->name, 'duration' => $row->duration, ])->all(), DataCollection::class, ); } /** * Search available apps for the select dropdown. */ #[NoDiscard] public function searchAppsForSelect(string $search = ''): Collection { return ConnectedApp::query() ->select(['id', 'name']) ->when($search, function ($query, $search): void { $query->where('name', 'like', '%'.$search.'%'); }) ->limit(50) // Limit the results so the dropdown doesn't lag ->orderBy('name') ->get(['id', 'name']); } /** * Get all connected app IDs for the "Select All" feature. * * @return array */ #[NoDiscard] public function getAllAppIds(): array { // Replace 'ConnectedApp' with your actual model name return ConnectedApp::pluck('id')->toArray(); } }