Skip to content
Merged

V1.3 #11

Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
fix: json-api-resource & descriptor support any array or object.
  • Loading branch information
Ark4ne committed Feb 4, 2023
commit c2279236f097bc8e008c80ffd3b65e3317ca93eb
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
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 {}],
[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
Loading