Skip to content

v1.4.5 #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

strategy:
matrix:
php_version: ['8.1', '8.2', '8.3']
php_version: ['8.1', '8.2', '8.3', '8.4']
laravel_version: ['^9.0', '^10.0', '^11.0']
exclude:
- php_version: '8.1'
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG-1.4.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
Release note
============
# v1.4.4
# v1.4.6
### Change
- Support PHP 8.4
### Fixed
- Fix `applyWhen` behavior

# v1.4.5
### Change
- `applyWhen` condition can be a closure
- CI: test all supported laravel version

# v1.4.4
### Fixes
- typo on ToResponse : change Content-type to Content-Type

# v1.4.3
### Added
- Add support for Laravel 11
Expand Down
26 changes: 26 additions & 0 deletions phpunit.php8.4.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
executionOrder="depends,defects"
failOnRisky="true"
failOnWarning="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<php>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
</php>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
</source>
</phpunit>
55 changes: 55 additions & 0 deletions src/Asserts/AssertJsonApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Ark4ne\JsonApi\Asserts;

use Ark4ne\JsonApi\Descriptors\Values\Value;
use Ark4ne\JsonApi\Resources\JsonApiResource;
use Ark4ne\JsonApi\Support\FakeModel;
use Ark4ne\JsonApi\Support\Values;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\MissingValue;
use ReflectionClass;

class AssertJsonApiResource
{
/**
* @param class-string<JsonApiResource> $class
*/
public function __construct(protected string $class)
{
}

public function assert(): void
{
$this->itCanGenerateSchema();
$this->allAttributesAreLazySet();
}

private function itCanGenerateSchema(): void
{
try {
$this->class::schema();
} catch (\Throwable $throwable) {
throw new FailGenerateSchema($this->class, $throwable);
}
}

private function allAttributesAreLazySet(): void
{
$reflection = new ReflectionClass($this->class);
$instance = $reflection->newInstanceWithoutConstructor();
$instance->resource = new FakeModel;

$method = $reflection->getMethod('toAttributes');
$method->setAccessible(true);
/** @var iterable<array-key, mixed> $attributes */
$attributes = $method->invoke($instance, new Request());
$attributes = Values::mergeValues($attributes);

foreach ($attributes as $key => $attribute) {
if (!($attribute instanceof \Closure || $attribute instanceof MissingValue || $attribute instanceof Value)) {
throw new EagerSetAttribute($this->class, $key);
}
}
}
}
13 changes: 13 additions & 0 deletions src/Asserts/EagerSetAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Ark4ne\JsonApi\Asserts;

use Throwable;

class EagerSetAttribute extends \Exception
{
public function __construct(string $class, string $key, ?Throwable $previous = null)
{
parent::__construct("Attribute [$key] on resource [$class] is eager set.", 0, $previous);
}
}
13 changes: 13 additions & 0 deletions src/Asserts/FailGenerateSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Ark4ne\JsonApi\Asserts;

use Throwable;

class FailGenerateSchema extends \Exception
{
public function __construct(string $class, ?Throwable $previous = null)
{
parent::__construct("Can't generate schema for resource [$class].", 0, $previous);
}
}
6 changes: 3 additions & 3 deletions src/Descriptors/Relations/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function meta(Closure $meta): static
* @param bool|null $whenIncluded
* @return $this
*/
public function whenIncluded(bool $whenIncluded = null): static
public function whenIncluded(null|bool $whenIncluded = null): static
{
if ($whenIncluded === null) {
$this->whenIncluded ??= true;
Expand All @@ -83,7 +83,7 @@ public function whenIncluded(bool $whenIncluded = null): static
*
* @return static
*/
public function whenLoaded(string $relation = null): self
public function whenLoaded(null|string $relation = null): self
{
return $this->when(fn(
Request $request,
Expand All @@ -100,7 +100,7 @@ public function whenLoaded(string $relation = null): self
*
* @return static
*/
public function whenPivotLoaded(string $table, string $accessor = null): self
public function whenPivotLoaded(string $table, null|string $accessor = null): self
{
return $this->when(fn(
Request $request,
Expand Down
25 changes: 0 additions & 25 deletions src/Descriptors/Values/ValueRaw.php

This file was deleted.

6 changes: 3 additions & 3 deletions src/Resources/Concerns/ConditionallyLoadsAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Ark4ne\JsonApi\Descriptors\Describer;
use Ark4ne\JsonApi\Descriptors\Relations\RelationRaw;
use Ark4ne\JsonApi\Descriptors\Values\ValueRaw;
use Ark4ne\JsonApi\Descriptors\Values\ValueMixed;
use Ark4ne\JsonApi\Resources\Relationship;
use Ark4ne\JsonApi\Support\Fields;
use Ark4ne\JsonApi\Support\Includes;
Expand Down Expand Up @@ -57,13 +57,13 @@ protected function whenIncluded(Request $request, string $type, mixed $value)
*/
protected function applyWhen(bool|Closure $condition, iterable $data): MergeValue
{
return new MergeValue(collect($data)->map(function ($raw, $key) use ($condition) {
return new MergeValue(collect($data)->map(function ($raw) use ($condition) {
if ($raw instanceof Describer) {
$value = $raw;
} elseif ($raw instanceof Relationship) {
$value = RelationRaw::fromRelationship($raw);
} else {
$value = new ValueRaw($key, $raw);
$value = new ValueMixed(is_callable($raw) ? $raw : static fn () => $raw);
}

return $value->when(fn () => value($condition));
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/Concerns/Relationships.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private function requestedRelationshipsLoadFromSchema(Request $request, Skeleton
if ($load && Includes::include($request, $name)) {
$include = Includes::through($name, fn() => $this->requestedRelationshipsLoadFromSchema($request, $schema->relationships[$name]));

$apply = static function ($load, string $pre = null) use (&$loads, &$apply) {
$apply = static function ($load, null|string $pre = null) use (&$loads, &$apply) {
foreach ((array)$load as $key => $value) {
if (is_string($value)) {
$loads["$pre.$value"] = [];
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/Concerns/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ trait Schema
*/
private static array $schemas = [];

public static function schema(Request $request = null): Skeleton
public static function schema(null|Request $request = null): Skeleton
{
if (isset(self::$schemas[static::class])) {
return self::$schemas[static::class];
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/Concerns/SchemaCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

trait SchemaCollection
{
public static function schema(Request $request = null): Skeleton
public static function schema(null|Request $request = null): Skeleton
{
return self::new()->collects::schema($request);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/Relationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public function asCollection(): self
* @param bool|null $whenIncluded
* @return $this
*/
public function whenIncluded(bool $whenIncluded = null): static
public function whenIncluded(null|bool $whenIncluded = null): static
{
if ($whenIncluded === null) {
$this->whenIncluded ??= true;
Expand Down
4 changes: 2 additions & 2 deletions src/Support/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private static function flattenDot(array $array, string $prepend, string $saveKe
* @param string|null $saveKey
* @return array<mixed>
*/
public static function undot(array $array, string $saveKey = null): array
public static function undot(array $array, null|string $saveKey = null): array
{
$results = [];

Expand All @@ -129,7 +129,7 @@ public static function undot(array $array, string $saveKey = null): array
* @param string|null $saveKey
* @return mixed
*/
public static function apply(array &$array, string $path, mixed $value, string $saveKey = null): mixed
public static function apply(array &$array, string $path, mixed $value, null|string $saveKey = null): mixed
{
$keys = explode('.', $path);

Expand Down
4 changes: 2 additions & 2 deletions src/Support/Fields.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static function through(string $type, callable $callable): mixed
*
* @return string[]|null
*/
public static function get(Request $request, string $type = null): ?array
public static function get(Request $request, null|string $type = null): ?array
{
$type ??= self::$current;

Expand All @@ -57,7 +57,7 @@ public static function get(Request $request, string $type = null): ?array
*
* @return bool
*/
public static function has(Request $request, string $field, string $type =null): bool {
public static function has(Request $request, string $field, null|string $type =null): bool {
$type ??= self::$current;

if ($type === null) {
Expand Down
9 changes: 8 additions & 1 deletion tests/Feature/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ class SchemaTest extends FeatureTestCase
{
public function testSchema()
{
$user = new Skeleton(UserResource::class, 'user', ['name', 'email', 'only-with-fields']);
$user = new Skeleton(UserResource::class, 'user', [
'name',
'email',
'only-with-fields',
'with-apply-conditional-raw',
'with-apply-conditional-closure',
'with-apply-conditional-value',
]);
$post = new Skeleton(PostResource::class, 'post', ['state', 'title', 'content']);
$comment = new Skeleton(CommentResource::class, 'comment', ['content']);

Expand Down
11 changes: 10 additions & 1 deletion tests/Feature/User/ResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,16 @@ private function getJsonResult(User $user, ?array $attributes = null, ?array $re
'attributes' => array_filter(array_intersect_key([
'name' => $user->name,
'email' => $user->email,
], array_fill_keys($attributes ?? ['name', 'email'], true))),
"with-apply-conditional-closure" => "huge-data-set",
"with-apply-conditional-raw" => "huge-data-set",
"with-apply-conditional-value" => "huge-data-set"
], array_fill_keys($attributes ?? [
'name',
'email',
"with-apply-conditional-closure",
"with-apply-conditional-raw",
"with-apply-conditional-value",
], true))),
'relationships' => [
'main-post' => [],
'posts' => array_filter([
Expand Down
29 changes: 15 additions & 14 deletions tests/Unit/Resources/Concerns/ConditionallyLoadsAttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Ark4ne\JsonApi\Descriptors\Values\ValueMixed;
use Ark4ne\JsonApi\Descriptors\Values\ValueRaw;
use Ark4ne\JsonApi\Resources\Concerns\ConditionallyLoadsAttributes;
use Ark4ne\JsonApi\Resources\JsonApiResource;
use Ark4ne\JsonApi\Resources\Relationship;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
Expand Down Expand Up @@ -75,16 +76,16 @@ public function testApplyWhen()
'missing.2' => 123,
]);
$this->assertEquals(new MergeValue([
'missing.1' => (new ValueRaw('missing.1', 'abc'))->when(fn () => false),
'missing.2' => (new ValueRaw('missing.2', 123))->when(fn () => false),
'missing.1' => (new ValueMixed(fn() => 'abc'))->when(fn() => false),
'missing.2' => (new ValueMixed(fn() => 123))->when(fn() => false),
]), $actual);
$actual = Reflect::invoke($stub, 'applyWhen', true, [
'present.1' => 'abc',
'present.2' => 123,
]);
$this->assertEquals(new MergeValue([
'present.1' => (new ValueRaw('present.1', 'abc'))->when(fn () => true),
'present.2' => (new ValueRaw('present.2', 123))->when(fn () => true),
'present.1' => (new ValueMixed(fn() => 'abc'))->when(fn() => true),
'present.2' => (new ValueMixed(fn() => 123))->when(fn() => true),
]), $actual);
$actual = Reflect::invoke($stub, 'applyWhen', true, [
'present.1' => (new ValueMixed(fn() => 'abc')),
Expand All @@ -94,11 +95,11 @@ public function testApplyWhen()
'present.5' => (new Relationship(UserResource::class, fn() => null)),
]);
$this->assertEquals(new MergeValue([
'present.1' => (new ValueMixed(fn() => 'abc'))->when(fn () => true),
'present.2' => (new ValueMixed(fn() => 123))->when(fn () => true),
'present.3' => (new RelationOne('present', fn() => 'abc'))->when(fn () => true),
'present.4' => (new RelationOne('present', fn() => 123))->when(fn () => true),
'present.5' => RelationRaw::fromRelationship(new Relationship(UserResource::class, fn() => null))->when(fn () => true),
'present.1' => (new ValueMixed(fn() => 'abc'))->when(fn() => true),
'present.2' => (new ValueMixed(fn() => 123))->when(fn() => true),
'present.3' => (new RelationOne('present', fn() => 'abc'))->when(fn() => true),
'present.4' => (new RelationOne('present', fn() => 123))->when(fn() => true),
'present.5' => RelationRaw::fromRelationship(new Relationship(UserResource::class, fn() => null))->when(fn() => true),
]), $actual);
$actual = Reflect::invoke($stub, 'applyWhen', false, [
'missing.1' => (new ValueMixed(fn() => 'abc')),
Expand All @@ -108,11 +109,11 @@ public function testApplyWhen()
'missing.5' => (new Relationship(UserResource::class, fn() => null)),
]);
$this->assertEquals(new MergeValue([
'missing.1' => (new ValueMixed(fn() => 'abc'))->when(fn () => false),
'missing.2' => (new ValueMixed(fn() => 123))->when(fn () => false),
'missing.3' => (new RelationOne('present', fn() => 'abc'))->when(fn () => false),
'missing.4' => (new RelationOne('present', fn() => 123))->when(fn () => false),
'missing.5' => RelationRaw::fromRelationship(new Relationship(UserResource::class, fn() => null))->when(fn () => false),
'missing.1' => (new ValueMixed(fn() => 'abc'))->when(fn() => false),
'missing.2' => (new ValueMixed(fn() => 123))->when(fn() => false),
'missing.3' => (new RelationOne('present', fn() => 'abc'))->when(fn() => false),
'missing.4' => (new RelationOne('present', fn() => 123))->when(fn() => false),
'missing.5' => RelationRaw::fromRelationship(new Relationship(UserResource::class, fn() => null))->when(fn() => false),
]), $actual);
}

Expand Down
Loading
Loading