Skip to content

Commit

Permalink
update: resource supports formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
Jasonej committed Nov 7, 2021
1 parent 28a0f32 commit dd74d8e
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/Exceptions/NoDefinedFormatsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Sourcetoad\EnhancedResources\Exceptions;

use Exception;

class NoDefinedFormatsException extends Exception
{
protected const MESSAGE_FORMAT = '\'%s\' has no defined formats.';

public function __construct(object $object)
{
$message = vsprintf(static::MESSAGE_FORMAT, [
$object::class,
]);

parent::__construct($message);
}
}
21 changes: 21 additions & 0 deletions src/Exceptions/NoFormatSelectedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Sourcetoad\EnhancedResources\Exceptions;

use Exception;

class NoFormatSelectedException extends Exception
{
protected const MESSAGE_FORMAT = '\'%s\' does not have a default format, and no format was specified.';

public function __construct(object $object)
{
$message = vsprintf(static::MESSAGE_FORMAT, [
$object::class,
]);

parent::__construct($message);
}
}
5 changes: 5 additions & 0 deletions src/Formatting/FormatDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public function __construct(ReflectionMethod $reflection)
$this->isExplicitlyDefault = !empty($this->reflection->getAttributes(IsDefault::class));
}

public function invoke(object $object, $request): mixed
{
return $this->reflection->invoke($object, $request);
}

public function isExplicitlyDefault(): bool
{
return $this->isExplicitlyDefault;
Expand Down
40 changes: 40 additions & 0 deletions src/Resource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Sourcetoad\EnhancedResources;

use Illuminate\Http\Resources\Json\JsonResource;
use Sourcetoad\EnhancedResources\Exceptions\NoDefinedFormatsException;
use Sourcetoad\EnhancedResources\Exceptions\NoFormatSelectedException;
use Sourcetoad\EnhancedResources\Formatting\FormatManager;

abstract class Resource extends JsonResource
{
protected FormatManager $formatManager;

public function __construct($resource)
{
parent::__construct($resource);

$this->formatManager = new FormatManager($this);

if ($this->formatManager->formats()->isEmpty()) {
throw new NoDefinedFormatsException($this);
}
}

public function format(string $name): static
{
$this->formatManager->select($name);

return $this;
}

public function toArray($request)
{
$currentFormat = $this->formatManager->current() ?? throw new NoFormatSelectedException($this);

return $currentFormat->invoke($this, $request);
}
}
139 changes: 139 additions & 0 deletions tests/Unit/ResourceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

declare(strict_types=1);

namespace Sourcetoad\EnhancedResources\Tests\Unit;

use Sourcetoad\EnhancedResources\Exceptions\NoDefinedFormatsException;
use Sourcetoad\EnhancedResources\Exceptions\NoFormatSelectedException;
use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;
use Sourcetoad\EnhancedResources\Tests\TestCase;

class ResourceTest extends TestCase
{
/** @dataProvider formatProvider */
public function test_resource_is_formatted_correctly(Resource $resource, array $expectedData): void
{
# Act
$actualData = $resource->toArray(request());

# Assert
$this->assertSame($expectedData, $actualData);
}

public function test_exception_is_thrown_if_no_formats_are_defined(): void
{
# Expect
$this->expectException(NoDefinedFormatsException::class);

# Act
new class(null) extends Resource {};
}

public function test_exception_is_thrown_if_no_format_is_selected(): void
{
# Expect
$this->expectException(NoFormatSelectedException::class);

# Act
(new class(null) extends Resource {
#[Format]
public function bar() {}

#[Format]
public function foo() {}
})->toArray(request());
}

# region Data Providers

public function formatProvider(): array
{
return [
'implicit default is used' => [
'resource' => (new class(null) extends Resource {
#[Format]
public function foo(): array
{
return [
'first_name' => 'John',
'id' => 1,
'last_name' => 'Doe',
];
}
}),
'expectedData' => [
'first_name' => 'John',
'id' => 1,
'last_name' => 'Doe',
],
],
'explicit default is used' => [
'resource' => (new class(null) extends Resource {
#[Format]
public function bar(): array
{
return [
'first_name' => 'John',
'id' => 1,
'last_name' => 'Doe',
];
}

#[IsDefault, Format]
public function foo(): array
{
return [
'id' => 1,
'name' => [
'first' => 'John',
'last' => 'Doe',
],
];
}
}),
'expectedData' => [
'id' => 1,
'name' => [
'first' => 'John',
'last' => 'Doe',
],
],
],
'explicitly selected format is used' => [
'resource' => (new class(null) extends Resource {
#[Format]
public function bar(): array
{
return [
'first_name' => 'John',
'id' => 1,
'last_name' => 'Doe',
];
}

#[IsDefault, Format]
public function foo(): array
{
return [
'id' => 1,
'name' => [
'first' => 'John',
'last' => 'Doe',
],
];
}
})->format('bar'),
'expectedData' => [
'first_name' => 'John',
'id' => 1,
'last_name' => 'Doe',
],
],
];
}

# endregion
}

0 comments on commit dd74d8e

Please sign in to comment.