暂存
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Http\Resources\Json;
|
||||
|
||||
class AnonymousResourceCollection extends ResourceCollection
|
||||
{
|
||||
/**
|
||||
* The name of the resource being collected.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $collects;
|
||||
|
||||
/**
|
||||
* Indicates if the collection keys should be preserved.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $preserveKeys = false;
|
||||
|
||||
/**
|
||||
* Create a new anonymous resource collection.
|
||||
*
|
||||
* @param mixed $resource
|
||||
* @param string $collects
|
||||
*/
|
||||
public function __construct($resource, $collects)
|
||||
{
|
||||
$this->collects = $collects;
|
||||
|
||||
parent::__construct($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the collection keys should be preserved.
|
||||
*/
|
||||
public function preserveKeys(bool $value = true): static
|
||||
{
|
||||
$this->preserveKeys = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Http\Resources\Json;
|
||||
|
||||
use ArrayAccess;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Contracts\Routing\UrlRoutable;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Attributes\PreserveKeys;
|
||||
use Illuminate\Http\Resources\ConditionallyLoadsAttributes;
|
||||
use Illuminate\Http\Resources\DelegatesToResource;
|
||||
use JsonException;
|
||||
use JsonSerializable;
|
||||
use ReflectionClass;
|
||||
|
||||
class JsonResource implements ArrayAccess, JsonSerializable, Responsable, UrlRoutable
|
||||
{
|
||||
use ConditionallyLoadsAttributes, DelegatesToResource;
|
||||
|
||||
/**
|
||||
* The resource instance.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $resource;
|
||||
|
||||
/**
|
||||
* The additional data that should be added to the top-level resource array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $with = [];
|
||||
|
||||
/**
|
||||
* The additional metadata that should be added to the resource response.
|
||||
*
|
||||
* Added during response construction by the developer.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $additional = [];
|
||||
|
||||
/**
|
||||
* The "data" wrapper that should be applied.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static $wrap = 'data';
|
||||
|
||||
/**
|
||||
* Whether to force wrapping even if the $wrap key exists in underlying resource data.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static bool $forceWrapping = false;
|
||||
|
||||
/**
|
||||
* Create a new resource instance.
|
||||
*
|
||||
* @param mixed $resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $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(static::newCollection($resource), function ($collection) {
|
||||
if (! array_key_exists(static::class, static::$cachedPreserveKeysAttributes)) {
|
||||
static::$cachedPreserveKeysAttributes[static::class] = (new ReflectionClass(static::class))->getAttributes(PreserveKeys::class) !== [];
|
||||
}
|
||||
|
||||
if (static::$cachedPreserveKeysAttributes[static::class]) {
|
||||
$collection->preserveKeys = true;
|
||||
} elseif (property_exists(static::class, 'preserveKeys')) {
|
||||
$collection->preserveKeys = (new static([]))->preserveKeys === true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource collection instance.
|
||||
*
|
||||
* @param mixed $resource
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
protected static function newCollection($resource)
|
||||
{
|
||||
return new AnonymousResourceCollection($resource, static::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the resource to an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request|null $request
|
||||
* @return array
|
||||
*/
|
||||
public function resolve($request = null)
|
||||
{
|
||||
$data = $this->resolveResourceData(
|
||||
$request ?: $this->resolveRequestFromContainer()
|
||||
);
|
||||
|
||||
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 toAttributes(Request $request)
|
||||
{
|
||||
if (property_exists($this, 'attributes')) {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
return $this->toArray($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the resource data to an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function resolveResourceData(Request $request)
|
||||
{
|
||||
return $this->toAttributes($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray(Request $request)
|
||||
{
|
||||
if (is_null($this->resource)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return is_array($this->resource)
|
||||
? $this->resource
|
||||
: $this->resource->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the resource to JSON.
|
||||
*
|
||||
* @param int $options
|
||||
* @return string
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\JsonEncodingException
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
{
|
||||
try {
|
||||
$json = json_encode($this->jsonSerialize(), $options | JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw JsonEncodingException::forResource($this, $e->getMessage());
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the resource to pretty print formatted JSON.
|
||||
*
|
||||
* @param int $options
|
||||
* @return string
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\JsonEncodingException
|
||||
*/
|
||||
public function toPrettyJson(int $options = 0)
|
||||
{
|
||||
return $this->toJson(JSON_PRETTY_PRINT | $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any additional data that should be returned with the resource array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function with(Request $request)
|
||||
{
|
||||
return $this->with;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional metadata 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 $request, JsonResponse $response)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the HTTP request instance from container.
|
||||
*
|
||||
* @return \Illuminate\Http\Request
|
||||
*/
|
||||
protected function resolveRequestFromContainer()
|
||||
{
|
||||
return Container::getInstance()->make('request');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ?: $this->resolveRequestFromContainer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($this->resolveRequestFromContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the resource's global state.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function flushState()
|
||||
{
|
||||
static::$wrap = 'data';
|
||||
static::$forceWrapping = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Http\Resources\Json;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class PaginatedResourceResponse extends ResourceResponse
|
||||
{
|
||||
/**
|
||||
* 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),
|
||||
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) {
|
||||
if (is_array($item)) {
|
||||
return Arr::get($item, 'resource');
|
||||
} elseif (is_object($item)) {
|
||||
return $item->resource ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
$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') ||
|
||||
$this->resource->hasMacro('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 metadata 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',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Http\Resources\Json;
|
||||
|
||||
use Countable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\CollectsResources;
|
||||
use Illuminate\Pagination\AbstractCursorPaginator;
|
||||
use Illuminate\Pagination\AbstractPaginator;
|
||||
use IteratorAggregate;
|
||||
|
||||
class ResourceCollection extends JsonResource implements Countable, IteratorAggregate
|
||||
{
|
||||
use CollectsResources;
|
||||
|
||||
/**
|
||||
* The resource that this resource collects.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $collects;
|
||||
|
||||
/**
|
||||
* The mapped collection instance.
|
||||
*
|
||||
* @var \Illuminate\Support\Collection|null
|
||||
*/
|
||||
public $collection;
|
||||
|
||||
/**
|
||||
* Indicates if all existing request query parameters should be added to pagination links.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $preserveAllQueryParameters = false;
|
||||
|
||||
/**
|
||||
* The query parameters that should be added to the pagination links.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $queryParameters;
|
||||
|
||||
/**
|
||||
* Create a new resource instance.
|
||||
*
|
||||
* @param mixed $resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
parent::__construct($resource);
|
||||
|
||||
$this->resource = $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
|
||||
*/
|
||||
#[\Override]
|
||||
public function toArray(Request $request)
|
||||
{
|
||||
if ($this->collection->first() instanceof JsonResource) {
|
||||
return $this->collection->map->resolve($request)->all();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Http\Resources\Json;
|
||||
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ResourceResponse implements Responsable
|
||||
{
|
||||
/**
|
||||
* The underlying resource.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $resource;
|
||||
|
||||
/**
|
||||
* Create a new resource response.
|
||||
*
|
||||
* @param mixed $resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $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 \Illuminate\Support\Collection|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)
|
||||
{
|
||||
if ($this->resource instanceof JsonResource && $this->resource::$forceWrapping) {
|
||||
return $this->wrapper() !== null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user