feat: add per-type API transformer sparse fieldsets#10285
Conversation
| protected mixed $resource = null; | ||
|
|
||
| public function __construct( | ||
| private ?IncomingRequest $request = null, |
There was a problem hiding this comment.
To allow reusing the same transformer for multiple relations (like posts and comments) with independent fieldsets, we should add an $overrideResourceType parameter to the constructor.
There was a problem hiding this comment.
I’d rather not add this. The idea is, $resourceType is the resource type, not the relation name. If someone needs the same transformer logic for two resource types, they can make small subclasses with different $resourceType values.
| /** | ||
| * Resolves the requested field list for this transformer from the request. | ||
| * | ||
| * Supports both the flat `?fields=a,b` form and the per-type sparse | ||
| * fieldset form `?fields[<type>]=a,b`. The flat form is only honored when | ||
| * $allowFlat is true (i.e. for the root transformer); a type-specific | ||
| * fieldset is matched against this transformer's $resourceType at any | ||
| * nesting level. | ||
| * | ||
| * @return list<string>|null | ||
| */ | ||
| private function resolveFields(bool $allowFlat): ?array | ||
| { | ||
| $fields = $this->request->getGet('fields'); | ||
|
|
||
| // Sparse fieldsets: ?fields[posts]=id,slug -> ['posts' => 'id,slug'] | ||
| if (is_array($fields)) { | ||
| $scoped = ($this->resourceType !== null && is_string($fields[$this->resourceType] ?? null)) | ||
| ? $fields[$this->resourceType] | ||
| : null; | ||
|
|
||
| return $scoped !== null ? $this->splitList($scoped) : null; | ||
| } | ||
|
|
||
| // Flat fieldset: ?fields=id,slug (applies to the root only) | ||
| if ($allowFlat && is_string($fields)) { | ||
| return $this->splitList($fields); | ||
| } | ||
|
|
||
| return null; | ||
| } |
There was a problem hiding this comment.
In resolveFields(), mixing fields[x]=... and fields=... in the URL causes PHP to natively overwrite the array and break the filters,we need to manually parse the QUERY_STRING to prevent this bug.
There was a problem hiding this comment.
I don't think we should manually parse QUERY_STRING for this. If clients need separate fieldsets for root and nested resources, they can use the bracketed form for both, e.g. fields[users]=id,name&fields[posts]=id,slug. This is already covered by tests.
I added an explanation for this behavior to the docs.
Description
This PR adds per-type sparse fieldsets for API transformers via
fields[<type>].Transformers can opt in by defining
$resourceType, allowing nested resources to apply their own field filters without inheriting the rootfieldsparameter.Ref: #10278 (comment)
Checklist: