diff --git a/src/Concerns/Caching.php b/src/Concerns/Caching.php index 8d2cf0f..91d2045 100644 --- a/src/Concerns/Caching.php +++ b/src/Concerns/Caching.php @@ -8,25 +8,12 @@ use TiMacDonald\JsonApi\JsonApiResource; use TiMacDonald\JsonApi\JsonApiResourceCollection; +/** + * @internal + * @todo can we get rid of this? + */ trait Caching { - /** - * @internal - */ - private string|null $idCache = null; - - /** - * @internal - */ - private string|null $typeCache = null; - - /** - * @internal - * - * @var Collection|null - */ - private Collection|null $requestedRelationshipsCache = null; - /** * @internal * @infection-ignore-all @@ -35,51 +22,14 @@ trait Caching */ public function flush() { - $this->idCache = null; - - $this->typeCache = null; - - if ($this->requestedRelationshipsCache !== null) { - $this->requestedRelationshipsCache->each(fn (JsonApiResource|JsonApiResourceCollection $relation) => $relation->flush()); - } + // TODO can we just let this garbage collect? + $this->requestedRelationshipsCache?->each(fn (JsonApiResource|JsonApiResourceCollection $relation) => $relation->flush()); $this->requestedRelationshipsCache = null; - } - /** - * @internal - * @infection-ignore-all - * - * @param (callable(): string) $callback - * @return string - */ - private function rememberId(callable $callback) - { - return $this->idCache ??= $callback(); - } - - /** - * @internal - * @infection-ignore-all - * - * @param (callable(): string) $callback - * @return string - */ - private function rememberType(callable $callback) - { - return $this->typeCache ??= $callback(); - } + $this->idCache = null; - /** - * @internal - * @infection-ignore-all - * - * @param (callable(): Collection) $callback - * @return Collection - */ - private function rememberRequestRelationships(callable $callback) - { - return $this->requestedRelationshipsCache ??= $callback(); + $this->typeCache = null; } /** @@ -89,6 +39,7 @@ private function rememberRequestRelationships(callable $callback) */ public function requestedRelationshipsCache() { + // TODO can we remove this if we ditch caching? Only here for tests. return $this->requestedRelationshipsCache; } } diff --git a/src/Concerns/Identification.php b/src/Concerns/Identification.php index 76ba061..1637aa2 100644 --- a/src/Concerns/Identification.php +++ b/src/Concerns/Identification.php @@ -12,6 +12,10 @@ trait Identification { + private string|null $idCache = null; + + private string|null $typeCache = null; + /** * @internal * @@ -105,7 +109,7 @@ public function toUniqueResourceIdentifier(Request $request) */ private function resolveId(Request $request) { - return $this->rememberId(fn (): string => $this->toId($request)); + return $this->idCache ??= $this->toId($request); } /** @@ -115,7 +119,7 @@ private function resolveId(Request $request) */ private function resolveType(Request $request) { - return $this->rememberType(fn (): string => $this->toType($request)); + return $this->typeCache ??= $this->toType($request); } /** diff --git a/src/Concerns/Relationships.php b/src/Concerns/Relationships.php index 3c1b184..6fe442d 100644 --- a/src/Concerns/Relationships.php +++ b/src/Concerns/Relationships.php @@ -23,6 +23,11 @@ trait Relationships { + /** + * @var Collection|null + */ + private Collection|null $requestedRelationshipsCache = null; + /** * @internal * @@ -103,10 +108,10 @@ private function requestedRelationshipsAsIdentifiers(Request $request) */ private function requestedRelationships(Request $request) { - return $this->rememberRequestRelationships(fn (): Collection => $this->resolveRelationships($request) + return $this->requestedRelationshipsCache ??= $this->resolveRelationships($request) ->only($this->requestedIncludes($request)) ->map(fn (callable $value, string $prefix): null|JsonApiResource|JsonApiResourceCollection => $this->resolveInclude($value(), $prefix)) - ->reject(fn (JsonApiResource|JsonApiResourceCollection|null $resource): bool => $resource === null)); + ->reject(fn (JsonApiResource|JsonApiResourceCollection|null $resource): bool => $resource === null); } /** diff --git a/src/JsonApiResource.php b/src/JsonApiResource.php index 19030df..7df013e 100644 --- a/src/JsonApiResource.php +++ b/src/JsonApiResource.php @@ -10,6 +10,7 @@ use Illuminate\Http\Resources\PotentiallyMissing; use Illuminate\Support\Collection; use stdClass; + use function property_exists; abstract class JsonApiResource extends JsonResource @@ -115,7 +116,7 @@ public function toArray(Request $request) } /** - * @return array{included?: Collection, jsonapi: JsonApiServerImplementation} + * @return array{included?: array, jsonapi: JsonApiServerImplementation} */ public function with(Request $request) { @@ -129,6 +130,8 @@ public function with(Request $request) } /** + * TODO this may be removed once all supported versions have `newCollection`. + * * @return JsonApiResourceCollection */ public static function collection(mixed $resource) @@ -155,7 +158,7 @@ public static function newCollection(mixed $resource) */ public function toResponse($request) { - // TODO: the flush call here is triggering repeated Includes::flush() cals, because of collection.s - return tap(parent::toResponse($request)->header('Content-type', 'application/vnd.api+json'), fn () => $this->flush()); + // TODO: should this header be configurable? Should it be a middleware? Should we not set it if one exists? + return tap(parent::toResponse($request)->header('Content-type', 'application/vnd.api+json'), $this->flush(...)); } } diff --git a/src/JsonApiResourceCollection.php b/src/JsonApiResourceCollection.php index eac3cdc..ac51b6e 100644 --- a/src/JsonApiResourceCollection.php +++ b/src/JsonApiResourceCollection.php @@ -42,7 +42,7 @@ private function resolveResourceIdentifiers(Request $request) } /** - * @return array{included?: Collection, jsonapi: JsonApiServerImplementation} + * @return array{included?: array, jsonapi: JsonApiServerImplementation} */ public function with(Request $request) { @@ -63,7 +63,8 @@ public function with(Request $request) */ public function toResponse($request) { - return tap(parent::toResponse($request)->header('Content-type', 'application/vnd.api+json'), fn () => $this->flush()); + // TODO: should this header be configurable? Should it be a middleware? Should we not set it if one exists? + return tap(parent::toResponse($request)->header('Content-type', 'application/vnd.api+json'), $this->flush(...)); } /** @@ -98,9 +99,9 @@ function (array $link): array { */ public function withIncludePrefix(string $prefix) { - return tap($this, function (JsonApiResourceCollection $resource) use ($prefix): void { - $resource->collection->each(fn (JsonApiResource $resource): JsonApiResource => $resource->withIncludePrefix($prefix)); - }); + $this->collection->each(fn (JsonApiResource $resource): JsonApiResource => $resource->withIncludePrefix($prefix)); + + return $this; } /** diff --git a/src/Support/Fields.php b/src/Support/Fields.php index 08787ff..3dc3ce9 100644 --- a/src/Support/Fields.php +++ b/src/Support/Fields.php @@ -25,7 +25,7 @@ final class Fields */ private WeakMap $cache; - private function __construct(WeakMap $cache = new WeakMap) + private function __construct(WeakMap $cache = new WeakMap()) { $this->cache = $cache; } @@ -78,12 +78,4 @@ private function rememberResourceType(Request $request, string $resourceType, ca return $this->cache[$request][$resourceType] ??= $callback(); } - - /** - * @return void - */ - public function flush() - { - $this->cache = new WeakMap(); - } } diff --git a/src/Support/Includes.php b/src/Support/Includes.php index f38df5a..23347af 100644 --- a/src/Support/Includes.php +++ b/src/Support/Includes.php @@ -9,6 +9,7 @@ use Illuminate\Support\Str; use Symfony\Component\HttpKernel\Exception\HttpException; use WeakMap; + use function explode; use function is_array; @@ -24,7 +25,7 @@ final class Includes */ private WeakMap $cache; - private function __construct(WeakMap $cache = new WeakMap) + private function __construct(WeakMap $cache = new WeakMap()) { $this->cache = $cache; } @@ -80,12 +81,4 @@ private function rememberIncludes(Request $request, string $prefix, callable $ca return $this->cache[$request][$prefix] ??= $callback(); } - - /** - * @return void - */ - public function flush() - { - $this->cache = new WeakMap(); - } } diff --git a/tests/Feature/JsonApiTest.php b/tests/Feature/JsonApiTest.php index 48a9a3c..bc1d61b 100644 --- a/tests/Feature/JsonApiTest.php +++ b/tests/Feature/JsonApiTest.php @@ -11,10 +11,10 @@ use Tests\TestCase; use TiMacDonald\JsonApi\JsonApiResource; use TiMacDonald\JsonApi\JsonApiResourceCollection; -use TiMacDonald\JsonApi\ServerImplementation; use TiMacDonald\JsonApi\Link; use TiMacDonald\JsonApi\RelationshipObject; use TiMacDonald\JsonApi\ResourceIdentifier; +use TiMacDonald\JsonApi\ServerImplementation; class JsonApiTest extends TestCase {