MissingValue.php000064400000000415150031475360007667 0ustar00collects = $collects; parent::__construct($resource); } } Json/PaginatedResourceResponse.php000064400000005005150031475360013315 0ustar00json( $this->wrap( $this->resource->resolve($request), array_merge_recursive( $this->paginationInformation($request), $this->resource->with($request), $this->resource->additional ) ), $this->calculateStatus(), [], $this->resource->jsonOptions() ), function ($response) use ($request) { $response->original = $this->resource->resource->map(function ($item) { return is_array($item) ? Arr::get($item, 'resource') : $item->resource; }); $this->resource->withResponse($request, $response); }); } /** * Add the pagination information to the response. * * @param \Illuminate\Http\Request $request * @return array */ protected function paginationInformation($request) { $paginated = $this->resource->resource->toArray(); $default = [ 'links' => $this->paginationLinks($paginated), 'meta' => $this->meta($paginated), ]; if (method_exists($this->resource, 'paginationInformation')) { return $this->resource->paginationInformation($request, $paginated, $default); } return $default; } /** * Get the pagination links for the response. * * @param array $paginated * @return array */ protected function paginationLinks($paginated) { return [ 'first' => $paginated['first_page_url'] ?? null, 'last' => $paginated['last_page_url'] ?? null, 'prev' => $paginated['prev_page_url'] ?? null, 'next' => $paginated['next_page_url'] ?? null, ]; } /** * Gather the meta data for the response. * * @param array $paginated * @return array */ protected function meta($paginated) { return Arr::except($paginated, [ 'data', 'first_page_url', 'last_page_url', 'prev_page_url', 'next_page_url', ]); } } Json/ResourceCollection.php000064400000006362150031475360012004 0ustar00resource = $this->collectResource($resource); } /** * Indicate that all current query parameters should be appended to pagination links. * * @return $this */ public function preserveQuery() { $this->preserveAllQueryParameters = true; return $this; } /** * Specify the query string parameters that should be present on pagination links. * * @param array $query * @return $this */ public function withQuery(array $query) { $this->preserveAllQueryParameters = false; $this->queryParameters = $query; return $this; } /** * Return the count of items in the resource collection. * * @return int */ public function count(): int { return $this->collection->count(); } /** * Transform the resource into a JSON array. * * @param \Illuminate\Http\Request $request * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable */ public function toArray($request) { return $this->collection->map->toArray($request)->all(); } /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ public function toResponse($request) { if ($this->resource instanceof AbstractPaginator || $this->resource instanceof AbstractCursorPaginator) { return $this->preparePaginatedResponse($request); } return parent::toResponse($request); } /** * Create a paginate-aware HTTP response. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ protected function preparePaginatedResponse($request) { if ($this->preserveAllQueryParameters) { $this->resource->appends($request->query()); } elseif (! is_null($this->queryParameters)) { $this->resource->appends($this->queryParameters); } return (new PaginatedResourceResponse($this))->toResponse($request); } } Json/JsonResource.php000064400000013323150031475360010615 0ustar00resource = $resource; } /** * Create a new resource instance. * * @param mixed ...$parameters * @return static */ public static function make(...$parameters) { return new static(...$parameters); } /** * Create a new anonymous resource collection. * * @param mixed $resource * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection */ public static function collection($resource) { return tap(new AnonymousResourceCollection($resource, static::class), function ($collection) { if (property_exists(static::class, 'preserveKeys')) { $collection->preserveKeys = (new static([]))->preserveKeys === true; } }); } /** * Resolve the resource to an array. * * @param \Illuminate\Http\Request|null $request * @return array */ public function resolve($request = null) { $data = $this->toArray( $request = $request ?: Container::getInstance()->make('request') ); if ($data instanceof Arrayable) { $data = $data->toArray(); } elseif ($data instanceof JsonSerializable) { $data = $data->jsonSerialize(); } return $this->filter((array) $data); } /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable */ public function toArray($request) { if (is_null($this->resource)) { return []; } return is_array($this->resource) ? $this->resource : $this->resource->toArray(); } /** * Convert the model instance to JSON. * * @param int $options * @return string * * @throws \Illuminate\Database\Eloquent\JsonEncodingException */ public function toJson($options = 0) { $json = json_encode($this->jsonSerialize(), $options); if (json_last_error() !== JSON_ERROR_NONE) { throw JsonEncodingException::forResource($this, json_last_error_msg()); } return $json; } /** * Get any additional data that should be returned with the resource array. * * @param \Illuminate\Http\Request $request * @return array */ public function with($request) { return $this->with; } /** * Add additional meta data to the resource response. * * @param array $data * @return $this */ public function additional(array $data) { $this->additional = $data; return $this; } /** * Get the JSON serialization options that should be applied to the resource response. * * @return int */ public function jsonOptions() { return 0; } /** * Customize the response for a request. * * @param \Illuminate\Http\Request $request * @param \Illuminate\Http\JsonResponse $response * @return void */ public function withResponse($request, $response) { // } /** * Set the string that should wrap the outer-most resource array. * * @param string $value * @return void */ public static function wrap($value) { static::$wrap = $value; } /** * Disable wrapping of the outer-most resource array. * * @return void */ public static function withoutWrapping() { static::$wrap = null; } /** * Transform the resource into an HTTP response. * * @param \Illuminate\Http\Request|null $request * @return \Illuminate\Http\JsonResponse */ public function response($request = null) { return $this->toResponse( $request ?: Container::getInstance()->make('request') ); } /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ public function toResponse($request) { return (new ResourceResponse($this))->toResponse($request); } /** * Prepare the resource for JSON serialization. * * @return array */ public function jsonSerialize(): array { return $this->resolve(Container::getInstance()->make('request')); } } Json/ResourceResponse.php000064400000006231150031475360011502 0ustar00resource = $resource; } /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ public function toResponse($request) { return tap(response()->json( $this->wrap( $this->resource->resolve($request), $this->resource->with($request), $this->resource->additional ), $this->calculateStatus(), [], $this->resource->jsonOptions() ), function ($response) use ($request) { $response->original = $this->resource->resource; $this->resource->withResponse($request, $response); }); } /** * Wrap the given data if necessary. * * @param array $data * @param array $with * @param array $additional * @return array */ protected function wrap($data, $with = [], $additional = []) { if ($data instanceof Collection) { $data = $data->all(); } if ($this->haveDefaultWrapperAndDataIsUnwrapped($data)) { $data = [$this->wrapper() => $data]; } elseif ($this->haveAdditionalInformationAndDataIsUnwrapped($data, $with, $additional)) { $data = [($this->wrapper() ?? 'data') => $data]; } return array_merge_recursive($data, $with, $additional); } /** * Determine if we have a default wrapper and the given data is unwrapped. * * @param array $data * @return bool */ protected function haveDefaultWrapperAndDataIsUnwrapped($data) { return $this->wrapper() && ! array_key_exists($this->wrapper(), $data); } /** * Determine if "with" data has been added and our data is unwrapped. * * @param array $data * @param array $with * @param array $additional * @return bool */ protected function haveAdditionalInformationAndDataIsUnwrapped($data, $with, $additional) { return (! empty($with) || ! empty($additional)) && (! $this->wrapper() || ! array_key_exists($this->wrapper(), $data)); } /** * Get the default data wrapper for the resource. * * @return string */ protected function wrapper() { return get_class($this->resource)::$wrap; } /** * Calculate the appropriate status code for the response. * * @return int */ protected function calculateStatus() { return $this->resource->resource instanceof Model && $this->resource->resource->wasRecentlyCreated ? 201 : 200; } } PotentiallyMissing.php000064400000000331150031475360011114 0ustar00collects(); $this->collection = $collects && ! $resource->first() instanceof $collects ? $resource->mapInto($collects) : $resource->toBase(); return ($resource instanceof AbstractPaginator || $resource instanceof AbstractCursorPaginator) ? $resource->setCollection($this->collection) : $this->collection; } /** * Get the resource that this resource collects. * * @return string|null */ protected function collects() { $collects = null; if ($this->collects) { $collects = $this->collects; } elseif (str_ends_with(class_basename($this), 'Collection') && (class_exists($class = Str::replaceLast('Collection', '', get_class($this))) || class_exists($class = Str::replaceLast('Collection', 'Resource', get_class($this))))) { $collects = $class; } if (! $collects || is_a($collects, JsonResource::class, true)) { return $collects; } throw new LogicException('Resource collections must collect instances of '.JsonResource::class.'.'); } /** * Get the JSON serialization options that should be applied to the resource response. * * @return int */ public function jsonOptions() { $collects = $this->collects(); if (! $collects) { return 0; } return (new ReflectionClass($collects)) ->newInstanceWithoutConstructor() ->jsonOptions(); } /** * Get an iterator for the resource collection. * * @return \ArrayIterator */ public function getIterator(): Traversable { return $this->collection->getIterator(); } } DelegatesToResource.php000064400000006447150031475360011204 0ustar00resource->getRouteKey(); } /** * Get the route key for the resource. * * @return string */ public function getRouteKeyName() { return $this->resource->getRouteKeyName(); } /** * Retrieve the model for a bound value. * * @param mixed $value * @param string|null $field * @return void * * @throws \Exception */ public function resolveRouteBinding($value, $field = null) { throw new Exception('Resources may not be implicitly resolved from route bindings.'); } /** * Retrieve the model for a bound value. * * @param string $childType * @param mixed $value * @param string|null $field * @return void * * @throws \Exception */ public function resolveChildRouteBinding($childType, $value, $field = null) { throw new Exception('Resources may not be implicitly resolved from route bindings.'); } /** * Determine if the given attribute exists. * * @param mixed $offset * @return bool */ public function offsetExists($offset): bool { return isset($this->resource[$offset]); } /** * Get the value for a given offset. * * @param mixed $offset * @return mixed */ public function offsetGet($offset): mixed { return $this->resource[$offset]; } /** * Set the value for a given offset. * * @param mixed $offset * @param mixed $value * @return void */ public function offsetSet($offset, $value): void { $this->resource[$offset] = $value; } /** * Unset the value for a given offset. * * @param mixed $offset * @return void */ public function offsetUnset($offset): void { unset($this->resource[$offset]); } /** * Determine if an attribute exists on the resource. * * @param string $key * @return bool */ public function __isset($key) { return isset($this->resource->{$key}); } /** * Unset an attribute on the resource. * * @param string $key * @return void */ public function __unset($key) { unset($this->resource->{$key}); } /** * Dynamically get properties from the underlying resource. * * @param string $key * @return mixed */ public function __get($key) { return $this->resource->{$key}; } /** * Dynamically pass method calls to the underlying resource. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } return $this->forwardCallTo($this->resource, $method, $parameters); } } ConditionallyLoadsAttributes.php000064400000021066150031475360013130 0ustar00 $value) { $index++; if (is_array($value)) { $data[$key] = $this->filter($value); continue; } if (is_numeric($key) && $value instanceof MergeValue) { return $this->mergeData( $data, $index, $this->filter($value->data), array_values($value->data) === $value->data ); } if ($value instanceof self && is_null($value->resource)) { $data[$key] = null; } } return $this->removeMissingValues($data); } /** * Merge the given data in at the given index. * * @param array $data * @param int $index * @param array $merge * @param bool $numericKeys * @return array */ protected function mergeData($data, $index, $merge, $numericKeys) { if ($numericKeys) { return $this->removeMissingValues(array_merge( array_merge(array_slice($data, 0, $index, true), $merge), $this->filter(array_values(array_slice($data, $index + 1, null, true))) )); } return $this->removeMissingValues(array_slice($data, 0, $index, true) + $merge + $this->filter(array_slice($data, $index + 1, null, true))); } /** * Remove the missing values from the filtered data. * * @param array $data * @return array */ protected function removeMissingValues($data) { $numericKeys = true; foreach ($data as $key => $value) { if (($value instanceof PotentiallyMissing && $value->isMissing()) || ($value instanceof self && $value->resource instanceof PotentiallyMissing && $value->isMissing())) { unset($data[$key]); } else { $numericKeys = $numericKeys && is_numeric($key); } } if (property_exists($this, 'preserveKeys') && $this->preserveKeys === true) { return $data; } return $numericKeys ? array_values($data) : $data; } /** * Retrieve a value based on a given condition. * * @param bool $condition * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function when($condition, $value, $default = null) { if ($condition) { return value($value); } return func_num_args() === 3 ? value($default) : new MissingValue; } /** * Merge a value into the array. * * @param mixed $value * @return \Illuminate\Http\Resources\MergeValue|mixed */ protected function merge($value) { return $this->mergeWhen(true, $value); } /** * Merge a value if the given condition is truthy. * * @param bool $condition * @param mixed $value * @return \Illuminate\Http\Resources\MergeValue|mixed */ protected function mergeWhen($condition, $value) { return $condition ? new MergeValue(value($value)) : new MissingValue; } /** * Merge a value unless the given condition is truthy. * * @param bool $condition * @param mixed $value * @return \Illuminate\Http\Resources\MergeValue|mixed */ protected function mergeUnless($condition, $value) { return ! $condition ? new MergeValue(value($value)) : new MissingValue; } /** * Merge the given attributes. * * @param array $attributes * @return \Illuminate\Http\Resources\MergeValue */ protected function attributes($attributes) { return new MergeValue( Arr::only($this->resource->toArray(), $attributes) ); } /** * Retrieve a model attribute if it is null. * * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenNull($value, $default = null) { $arguments = func_num_args() == 1 ? [$value] : [$value, $default]; return $this->when(is_null($value), ...$arguments); } /** * Retrieve a model attribute if it is not null. * * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenNotNull($value, $default = null) { $arguments = func_num_args() == 1 ? [$value] : [$value, $default]; return $this->when(! is_null($value), ...$arguments); } /** * Retrieve an accessor when it has been appended. * * @param string $attribute * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenAppended($attribute, $value = null, $default = null) { if ($this->resource->hasAppended($attribute)) { return func_num_args() >= 2 ? value($value) : $this->resource->$attribute; } return func_num_args() === 3 ? value($default) : new MissingValue; } /** * Retrieve a relationship if it has been loaded. * * @param string $relationship * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenLoaded($relationship, $value = null, $default = null) { if (func_num_args() < 3) { $default = new MissingValue; } if (! $this->resource->relationLoaded($relationship)) { return value($default); } if (func_num_args() === 1) { return $this->resource->{$relationship}; } if ($this->resource->{$relationship} === null) { return; } return value($value); } /** * Retrieve a relationship count if it exists. * * @param string $relationship * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ public function whenCounted($relationship, $value = null, $default = null) { if (func_num_args() < 3) { $default = new MissingValue(); } $attribute = (string) Str::of($relationship)->snake()->finish('_count'); if (! isset($this->resource->getAttributes()[$attribute])) { return value($default); } if (func_num_args() === 1) { return $this->resource->{$attribute}; } if ($this->resource->{$attribute} === null) { return; } return value($value, $this->resource->{$attribute}); } /** * Execute a callback if the given pivot table has been loaded. * * @param string $table * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenPivotLoaded($table, $value, $default = null) { return $this->whenPivotLoadedAs('pivot', ...func_get_args()); } /** * Execute a callback if the given pivot table with a custom accessor has been loaded. * * @param string $accessor * @param string $table * @param mixed $value * @param mixed $default * @return \Illuminate\Http\Resources\MissingValue|mixed */ protected function whenPivotLoadedAs($accessor, $table, $value, $default = null) { if (func_num_args() === 3) { $default = new MissingValue; } return $this->when( $this->resource->$accessor && ($this->resource->$accessor instanceof $table || $this->resource->$accessor->getTable() === $table), ...[$value, $default] ); } /** * Transform the given value if it is present. * * @param mixed $value * @param callable $callback * @param mixed $default * @return mixed */ protected function transform($value, callable $callback, $default = null) { return transform( $value, $callback, func_num_args() === 3 ? $default : new MissingValue ); } } MergeValue.php000064400000001243150031475360007315 0ustar00data = $data->all(); } elseif ($data instanceof JsonSerializable) { $this->data = $data->jsonSerialize(); } else { $this->data = $data; } } }