diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 672056d..c68ff75 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -17,6 +17,11 @@ jobs: strategy: matrix: php_version: ['8.1', '8.2', '8.3'] + laravel_version: ['^9.0', '^10.0', '^11.0'] + exclude: + - php_version: '8.1' + laravel_version: '^11.0' + steps: - uses: actions/checkout@v3 @@ -33,10 +38,10 @@ jobs: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | - ${{ runner.os }}-php-${{ matrix.php_version }} + ${{ runner.os }}-php-${{ matrix.php_version }}-laravel-${{ matrix.laravel_version }} - name: Install dependencies - run: composer install --prefer-dist --no-progress + run: composer require laravel/framework ${{ matrix.laravel_version }} --prefer-dist --no-progress - name: PHPStan run: vendor/bin/phpstan analyze diff --git a/CHANGELOG-1.4.md b/CHANGELOG-1.4.md index c1d826a..bcc63a2 100644 --- a/CHANGELOG-1.4.md +++ b/CHANGELOG-1.4.md @@ -1,5 +1,10 @@ Release note ============ +# v1.4.4 +### Change +- `applyWhen` condition can be a closure +- CI: test all supported laravel version + # v1.4.3 ### Added - Add support for Laravel 11 diff --git a/composer.json b/composer.json index 04ceb2f..dcae5f2 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ "illuminate/support": "^9.0|^10.0|^11.0" }, "require-dev": { - "phpunit/phpunit": "^9.5|^10.0", - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.0|^10.0", + "orchestra/testbench": "^7.5|^8.0|^9.0|^10.0", "phpstan/phpstan": "^1.9.18" }, "license": "MIT", diff --git a/phpstan.neon b/phpstan.neon index 81d4598..856fa7c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,6 +7,8 @@ parameters: - tests/app/routes.php level: 6 + reportUnmatchedIgnoredErrors: false + ignoreErrors: - identifier: missingType.generics diff --git a/src/Descriptors/Relations/RelationMissing.php b/src/Descriptors/Relations/RelationMissing.php index 067d2da..babd780 100644 --- a/src/Descriptors/Relations/RelationMissing.php +++ b/src/Descriptors/Relations/RelationMissing.php @@ -6,6 +6,9 @@ use Closure; use Illuminate\Http\Resources\MissingValue; +/** + * @internal + */ final class RelationMissing extends Relation { private function __construct(string $related, Closure|string|null $relation) diff --git a/src/Descriptors/Relations/RelationRaw.php b/src/Descriptors/Relations/RelationRaw.php new file mode 100644 index 0000000..a0666fa --- /dev/null +++ b/src/Descriptors/Relations/RelationRaw.php @@ -0,0 +1,27 @@ +relation)(); + } + + public static function fromRelationship(Relationship $relationship): self + { + return new self($relationship->getResource(), fn() => $relationship); + } +} diff --git a/src/Descriptors/Values/ValueRaw.php b/src/Descriptors/Values/ValueRaw.php new file mode 100644 index 0000000..db0aa72 --- /dev/null +++ b/src/Descriptors/Values/ValueRaw.php @@ -0,0 +1,25 @@ + + */ +class ValueRaw extends Value +{ + public function __construct( + null|string|Closure $attribute, + protected mixed $raw + ) { + parent::__construct($attribute); + } + + public function value(mixed $of): mixed + { + return $this->raw; + } +} diff --git a/src/Resources/Concerns/ConditionallyLoadsAttributes.php b/src/Resources/Concerns/ConditionallyLoadsAttributes.php index 5c90286..a6cd0d7 100644 --- a/src/Resources/Concerns/ConditionallyLoadsAttributes.php +++ b/src/Resources/Concerns/ConditionallyLoadsAttributes.php @@ -2,13 +2,15 @@ namespace Ark4ne\JsonApi\Resources\Concerns; -use Ark4ne\JsonApi\Descriptors\Relations\Relation; -use Ark4ne\JsonApi\Descriptors\Relations\RelationMissing; +use Ark4ne\JsonApi\Descriptors\Describer; +use Ark4ne\JsonApi\Descriptors\Relations\RelationRaw; +use Ark4ne\JsonApi\Descriptors\Values\ValueRaw; use Ark4ne\JsonApi\Resources\Relationship; use Ark4ne\JsonApi\Support\Fields; use Ark4ne\JsonApi\Support\Includes; use Ark4ne\JsonApi\Support\Supported; use Ark4ne\JsonApi\Support\Values; +use Closure; use Illuminate\Http\Request; use Illuminate\Http\Resources\MergeValue; use Illuminate\Http\Resources\MissingValue; @@ -48,27 +50,23 @@ protected function whenIncluded(Request $request, string $type, mixed $value) } /** - * @param bool $condition + * @param bool|Closure():boolean $condition * @param iterable $data * * @return \Illuminate\Http\Resources\MergeValue */ - protected function applyWhen(bool $condition, iterable $data): MergeValue + protected function applyWhen(bool|Closure $condition, iterable $data): MergeValue { - if ($condition) { - return new MergeValue($data); - } - - return new MergeValue(collect($data)->map(function ($raw) { - if ($raw instanceof Relationship) { - return RelationMissing::fromRelationship($raw); - } - - if ($raw instanceof Relation) { - return $raw->when(false); + return new MergeValue(collect($data)->map(function ($raw, $key) use ($condition) { + if ($raw instanceof Describer) { + $value = $raw; + } elseif ($raw instanceof Relationship) { + $value = RelationRaw::fromRelationship($raw); + } else { + $value = new ValueRaw($key, $raw); } - return new MissingValue(); + return $value->when(fn () => value($condition)); })); } @@ -111,7 +109,7 @@ public function whenHas($attribute, $value = null, $default = null) */ public function unless($condition, $value, $default = null) { - if (Supported::$whenHas) { + if (Supported::$unless) { // @phpstan-ignore-next-line return parent::unless($condition, $value, $default); } diff --git a/tests/Unit/Resources/Concerns/ConditionallyLoadsAttributesTest.php b/tests/Unit/Resources/Concerns/ConditionallyLoadsAttributesTest.php index 63996b6..d9b4dcb 100644 --- a/tests/Unit/Resources/Concerns/ConditionallyLoadsAttributesTest.php +++ b/tests/Unit/Resources/Concerns/ConditionallyLoadsAttributesTest.php @@ -2,12 +2,12 @@ namespace Test\Unit\Resources\Concerns; -use Ark4ne\JsonApi\Descriptors\Relations\RelationMissing; use Ark4ne\JsonApi\Descriptors\Relations\RelationOne; +use Ark4ne\JsonApi\Descriptors\Relations\RelationRaw; use Ark4ne\JsonApi\Descriptors\Values\ValueMixed; +use Ark4ne\JsonApi\Descriptors\Values\ValueRaw; use Ark4ne\JsonApi\Resources\Concerns\ConditionallyLoadsAttributes; use Ark4ne\JsonApi\Resources\Relationship; -use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\MergeValue; @@ -75,16 +75,16 @@ public function testApplyWhen() 'missing.2' => 123, ]); $this->assertEquals(new MergeValue([ - 'missing.1' => new MissingValue, - 'missing.2' => new MissingValue, + 'missing.1' => (new ValueRaw('missing.1', 'abc'))->when(fn () => false), + 'missing.2' => (new ValueRaw('missing.2', 123))->when(fn () => false), ]), $actual); $actual = Reflect::invoke($stub, 'applyWhen', true, [ 'present.1' => 'abc', 'present.2' => 123, ]); $this->assertEquals(new MergeValue([ - 'present.1' => 'abc', - 'present.2' => 123, + 'present.1' => (new ValueRaw('present.1', 'abc'))->when(fn () => true), + 'present.2' => (new ValueRaw('present.2', 123))->when(fn () => true), ]), $actual); $actual = Reflect::invoke($stub, 'applyWhen', true, [ 'present.1' => (new ValueMixed(fn() => 'abc')), @@ -94,11 +94,11 @@ public function testApplyWhen() 'present.5' => (new Relationship(UserResource::class, fn() => null)), ]); $this->assertEquals(new MergeValue([ - 'present.1' => (new ValueMixed(fn() => 'abc')), - 'present.2' => (new ValueMixed(fn() => 123)), - 'present.3' => (new RelationOne('present', fn() => 'abc')), - 'present.4' => (new RelationOne('present', fn() => 123)), - 'present.5' => (new Relationship(UserResource::class, fn() => null)), + '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')), @@ -108,11 +108,11 @@ public function testApplyWhen() 'missing.5' => (new Relationship(UserResource::class, fn() => null)), ]); $this->assertEquals(new MergeValue([ - 'missing.1' => new MissingValue, - 'missing.2' => new MissingValue, - 'missing.3' => (new RelationOne('present', fn() => 'abc'))->when(false), - 'missing.4' => (new RelationOne('present', fn() => 123))->when(false), - 'missing.5' => RelationMissing::fromRelationship((new Relationship(UserResource::class, fn() => null))), + '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); }