<?phpdeclare(strict_types=1);/*** This file is part of CodeIgniter 4 framework.** (c) CodeIgniter Foundation <admin@codeigniter.com>** For the full copyright and license information, please view* the LICENSE file that was distributed with this source code.*/namespace CodeIgniter\API;use CodeIgniter\HTTP\IncomingRequest;use InvalidArgumentException;/*** Base class for transforming resources into arrays.* Fulfills common functionality of the TransformerInterface,* and provides helper methods for conditional inclusion/exclusion of values.** Supports the following query variables from the request:* - fields: Comma-separated list of fields to include in the response* (e.g., ?fields=id,name,email)* If not provided, all fields from toArray() are included.* - include: Comma-separated list of related resources to include* (e.g., ?include=posts,comments)* This looks for methods named `include{Resource}()` on the transformer,* and calls them to get the related data, which are added as a new key to the output.** Example:** class UserTransformer extends BaseTransformer* {* public function toArray(mixed $resource): array* {* return [* 'id' => $resource['id'],* 'name' => $resource['name'],* 'email' => $resource['email'],* 'created_at' => $resource['created_at'],* 'updated_at' => $resource['updated_at'],* ];* }** protected function includePosts(): array* {* $posts = model('PostModel')->where('user_id', $this->resource['id'])->findAll();* return (new PostTransformer())->transformMany($posts);* }* }*/abstract class BaseTransformer implements TransformerInterface{/*** Nesting depth of the transformation currently in progress (0 = root).*/private static int $depth = 0;/*** @var list<string>|null*/private ?array $fields = null;/*** @var list<string>|null*/private ?array $includes = null;protected mixed $resource = null;public function __construct(private ?IncomingRequest $request = null,) {// An explicitly provided request is always honored - its scope is// intentional. Only the implicit global fallback is suppressed for// nested transformers, which is the actual leak vector.$explicitRequest = $request instanceof IncomingRequest;$this->request = $request ?? request();if ($explicitRequest || self::$depth === 0) {$fields = $this->request->getGet('fields');$this->fields = is_string($fields)? array_map(trim(...), explode(',', $fields)): $fields;$includes = $this->request->getGet('include');$this->includes = is_string($includes)? array_map(trim(...), explode(',', $includes)): $includes;}}/*** Converts the resource to an array representation.* This is overridden by child classes to define the* API-safe resource representation.** @param mixed $resource The resource being transformed*/abstract public function toArray(mixed $resource): array;/*** Transforms the given resource into an array using* the $this->toArray().*/public function transform(array|object|null $resource = null): array{// Store the resource so include methods can access it$this->resource = $resource;if ($resource === null) {$data = $this->toArray(null);} elseif (is_object($resource) && method_exists($resource, 'toArray')) {$data = $this->toArray($resource->toArray());} else {$data = $this->toArray((array) $resource);}$data = $this->limitFields($data);return $this->insertIncludes($data);}/*** Transforms a collection of resources using $this->transform() on each item.** If the request's 'fields' query variable is set, only those fields will be included* in the transformed output.*/public function transformMany(array $resources): array{return array_map($this->transform(...), $resources);}/*** Define which fields can be requested via the 'fields' query parameter.* Override in child classes to restrict available fields.* Return null to allow all fields from toArray().** @return list<string>|null*/protected function getAllowedFields(): ?array{return null;}/*** Define which related resources can be included via the 'include' query parameter.* Override in child classes to restrict available includes.* Return null to allow all includes that have corresponding methods.* Return an empty array to disable all includes.** @return list<string>|null*/protected function getAllowedIncludes(): ?array{return null;}/*** Limits the given data array to only the fields specified** @param array<string, mixed> $data** @return array<string, mixed>** @throws InvalidArgumentException*/private function limitFields(array $data): array{if ($this->fields === null || $this->fields === []) {return $data;}$allowedFields = $this->getAllowedFields();// If whitelist is defined, validate against itif ($allowedFields !== null) {$invalidFields = array_diff($this->fields, $allowedFields);if ($invalidFields !== []) {throw ApiException::forInvalidFields(implode(', ', $invalidFields));}}return array_intersect_key($data, array_flip($this->fields));}/*** Checks the request for 'include' query variable, and if present,* calls the corresponding include{Resource} methods to add related data.** @param array<string, mixed> $data** @return array<string, mixed>*/private function insertIncludes(array $data): array{if ($this->includes === null) {return $data;}$allowedIncludes = $this->getAllowedIncludes();if ($allowedIncludes === []) {return $data; // No includes allowed}// If whitelist is defined, filter the requested includesif ($allowedIncludes !== null) {$invalidIncludes = array_diff($this->includes, $allowedIncludes);if ($invalidIncludes !== []) {throw ApiException::forInvalidIncludes(implode(', ', $invalidIncludes));}}self::$depth++;try {foreach ($this->includes as $include) {$method = 'include' . ucfirst($include);if (method_exists($this, $method)) {$data[$include] = $this->{$method}();} else {throw ApiException::forMissingInclude($include);}}} finally {self::$depth--;}return $data;}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。