allowedIncludes instanceof Collection) { throw new AllowedFieldsMustBeCalledBeforeAllowedIncludes(); } $fields = is_array($fields) ? $fields : func_get_args(); $this->allowedFields = collect($fields) ->map(function (string $fieldName) { return $this->prependField($fieldName); }); $this->ensureAllFieldsExist(); $this->addRequestedModelFieldsToQuery(); return $this; } protected function addRequestedModelFieldsToQuery() { $modelTableName = $this->getModel()->getTable(); $fields = $this->request->fields(); $modelFields = $fields->has($modelTableName) ? $fields->get($modelTableName) : $fields->get('_'); if (empty($modelFields)) { return; } $prependedFields = $this->prependFieldsWithTableName($modelFields, $modelTableName); $this->select($prependedFields); } public function getRequestedFieldsForRelatedTable(string $relation): array { $tableOrRelation = config('query-builder.convert_relation_names_to_snake_case_plural', true) ? Str::plural(Str::snake($relation)) : $relation; $fields = $this->request->fields() ->mapWithKeys(fn ($fields, $table) => [$table => $fields]) ->get($tableOrRelation); if (! $fields) { return []; } if (! $this->allowedFields instanceof Collection) { // We have requested fields but no allowed fields (yet?) throw new UnknownIncludedFieldsQuery($fields); } return $fields; } protected function ensureAllFieldsExist() { $modelTable = $this->getModel()->getTable(); $requestedFields = $this->request->fields() ->map(function ($fields, $model) use ($modelTable) { $tableName = $model; return $this->prependFieldsWithTableName($fields, $model === '_' ? $modelTable : $tableName); }) ->flatten() ->unique(); $unknownFields = $requestedFields->diff($this->allowedFields); if ($unknownFields->isNotEmpty()) { throw InvalidFieldQuery::fieldsNotAllowed($unknownFields, $this->allowedFields); } } protected function prependFieldsWithTableName(array $fields, string $tableName): array { return array_map(function ($field) use ($tableName) { return $this->prependField($field, $tableName); }, $fields); } protected function prependField(string $field, ?string $table = null): string { if (! $table) { $table = $this->getModel()->getTable(); } if (Str::contains($field, '.')) { // Already prepended return $field; } return "{$table}.{$field}"; } }