Skip to content
Merged

V1.3 #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG-1.3.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Release note
============

# v1.3.6
### Fixes
- JsonApiResource & Descriptors support any array or object

# v1.3.5
### Fixes
- Descriptors\Values accepts mixed resource
Expand Down
7 changes: 5 additions & 2 deletions src/Descriptors/Describer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Closure;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\MissingValue;
use Illuminate\Support\Arr;

/**
* @template T
Expand Down Expand Up @@ -100,12 +101,14 @@ protected function check(Request $request, mixed $model, string $attribute): boo

private function retrieveValue(mixed $model, string $attribute): mixed
{
$value = static fn($attr) => Arr::accessible($model) ? $model[$attr] : $model->$attr;

$retriever = $this->retriever();
if ($retriever === null) {
return $model->$attribute;
return $value($attribute);
}
if (is_string($retriever)) {
return $model->$retriever;
return $value($retriever);
}
return $retriever();
}
Expand Down
3 changes: 0 additions & 3 deletions src/Descriptors/Descriptors.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

namespace Ark4ne\JsonApi\Descriptors;

/**
* @deprecated
*/
trait Descriptors
{
use Relations;
Expand Down
2 changes: 1 addition & 1 deletion src/Descriptors/Relations.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Closure;

/**
* @template T as \Illuminate\Database\Eloquent\Model
* @template T
*/
trait Relations
{
Expand Down
9 changes: 7 additions & 2 deletions src/Descriptors/Relations/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\MissingValue;
use Illuminate\Support\Arr;

/**
* @template T as \Illuminate\Database\Eloquent\Model
* @template T
* @extends Describer<T>
*/
abstract class Relation extends Describer
Expand Down Expand Up @@ -113,7 +114,11 @@ public function resolveFor(Request $request, mixed $model, string $field): Relat
if ($retriever instanceof Closure) {
$value = static fn() => $retriever($model, $field);
} else {
$value = static fn() => $model->getRelationValue($retriever ?? $field);
$value = static fn() => match (true) {
$model instanceof Model => $model->getRelationValue($retriever ?? $field),
Arr::accessible($model) => $model[$retriever ?? $field],
default => $model->{$retriever ?? $field}
};
}

$relation = $this->value(fn() => $this->check($request, $model, $field) ? $value() : new MissingValue());
Expand Down
2 changes: 1 addition & 1 deletion src/Descriptors/Relations/RelationMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Closure;

/**
* @template T as \Illuminate\Database\Eloquent\Model
* @template T
* @extends Relation<T>
*/
class RelationMany extends Relation
Expand Down
2 changes: 1 addition & 1 deletion src/Descriptors/Relations/RelationOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Closure;

/**
* @template T as \Illuminate\Database\Eloquent\Model
* @template T
* @extends Relation<T>
*/
class RelationOne extends Relation
Expand Down
12 changes: 11 additions & 1 deletion src/Resources/Concerns/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@ trait Attributes
*/
protected function toAttributes(Request $request): iterable
{
return $this->resource->toArray();
if (is_object($this->resource) && method_exists($this->resource, 'toArray')) {
return $this->resource->toArray();
}
if (is_array($this->resource)) {
return $this->resource;
}
if (is_iterable($this->resource)) {
return iterator_to_array($this->resource);
}

return [];
}

/**
Expand Down
14 changes: 8 additions & 6 deletions src/Resources/JsonApiCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public function __construct($resource, ?string $collects = null)
*/
public function toArray(mixed $request, bool $included = true): array
{
if (collect($this->collection)->every(fn($value) => $value instanceof JsonApiResource)) {
$collection = collect($this->collection);
$collection = collect($this->collection);

if ($collection->every(static fn($value) => $value instanceof JsonApiResource)) {
// @phpstan-ignore-next-line
$loads = array_merge(...$collection->map->requestedRelationshipsLoad($request));

// @phpstan-ignore-next-line
$resources = $collection->map->resource;
if (!empty($loads)) {
// @phpstan-ignore-next-line
$resources = $collection->map->resource;

if (!empty($loads) && $resources->every(fn($resource) => $resource instanceof Model)) {
(new Collection($resources))->loadMissing($loads);
if ($resources->every(static fn($resource) => $resource instanceof Model)) {
(new Collection($resources))->loadMissing($loads);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Descriptors/DescriptorsTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Ark4ne\JsonApi\Resources\JsonApiCollection;
use Ark4ne\JsonApi\Resources\JsonApiResource;
use Closure;
use stdClass;
use Test\Support\Reflect;
use Test\TestCase;

Expand All @@ -41,7 +42,7 @@ public function methods()
*/
public function testDescriptorTrait($expected, $method, ...$args)
{
$mock = new class {
$mock = new class extends stdClass {
use Values;
use Relations;
};
Expand Down
50 changes: 32 additions & 18 deletions tests/Unit/Descriptors/RelationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,56 +15,69 @@

class RelationTest extends TestCase
{
public function testIncluded()
public function resourceProvider(): array
{
return [
[[]],
[new class extends stdClass {}],
[new class extends Model {}],
];
}

/**
* @dataProvider resourceProvider
*/
public function testIncluded($model)
{
$stub = new RelationOne(UserResource::class, fn() => null);

$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertFalse(Reflect::get($relation, 'whenIncluded'));

$stub->whenIncluded();
$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertTrue(Reflect::get($relation, 'whenIncluded'));
}

public function testMeta()

/**
* @dataProvider resourceProvider
*/
public function testMeta($model)
{
$stub = new RelationOne(UserResource::class, fn() => null);

$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertEmpty(Reflect::get($relation, 'meta'));

$stub->meta(fn() => ['test']);
$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertInstanceOf(\Closure::class, Reflect::get($relation, 'meta'));
$this->assertEquals(['test'], Reflect::get($relation, 'meta')());
}

public function testLinks()
/**
* @dataProvider resourceProvider
*/
public function testLinks($model)
{
$stub = new RelationOne(UserResource::class, fn() => null);

$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertEmpty(Reflect::get($relation, 'links'));

$stub->links(fn() => ['test']);
$relation = $stub->resolveFor(new Request, new class extends Model {
}, 'null');
$relation = $stub->resolveFor(new Request, $model, 'null');

$this->assertInstanceOf(Relationship::class, $relation);
$this->assertInstanceOf(\Closure::class, Reflect::get($relation, 'links'));
Expand Down Expand Up @@ -120,12 +133,13 @@ public function testWhenPivotLoaded($expectedAttr, $relation, $invokedAttr)
$this->assertTrue($check);
}

public function testRelationMissing()
/**
* @dataProvider resourceProvider
*/
public function testRelationMissing($model)
{
$missing = RelationMissing::fromRelationship(new Relationship(UserResource::class, fn() => null));

$model = new class extends Model {
};
$check = Reflect::invoke($missing, 'check', new Request, $model, 'any');
$value = Reflect::invoke($missing, 'valueFor', new Request, $model, 'any');

Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Descriptors/ResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
use Ark4ne\JsonApi\Descriptors\Values\ValueMixed;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use stdClass;
use Test\Support\Reflect;
use Test\TestCase;

class ResolverTest extends TestCase
{
public function testResolveValue()
{
$stub = new class {
$stub = new class extends stdClass {
use Resolver;

public $resource;
Expand Down
Loading