Skip to content

Commit

Permalink
PHP 8.4 Support + Laravel Pint (#33)
Browse files Browse the repository at this point in the history
* build: support php8.4

* build: add laravel pint

* chore: pint files
iBotPeaches authored Jan 2, 2025
1 parent a5a367d commit 150d5af
Showing 15 changed files with 227 additions and 168 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [8.1, 8.2, 8.3]
php: [8.1, 8.2, 8.3, 8.4]
stability: ["--prefer-lowest", "--prefer-stable"]
name: PHP ${{ matrix.php }} - ${{ matrix.stability }}
steps:
@@ -31,11 +31,13 @@ jobs:
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.stability }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: |
${{ runner.os }}-${{ matrix.php }}-${{ matrix.stability }}-composer-
restore-keys: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.stability }}-composer-

- name: Install dependencies
run: composer update ${{ matrix.stability }} --prefer-dist --no-interaction --no-suggest

- name: Run style check
run: vendor/bin/pint --test

- name: Execute tests
run: vendor/bin/phpunit
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -20,11 +20,12 @@
}
},
"require": {
"php": "^8.1",
"php": "^8.1||^8.2||^8.3||^8.4",
"laravel/framework": "^10.0|^11.0"
},
"require-dev": {
"orchestra/testbench": "^8.0|^9.0",
"phpunit/phpunit": "^10.0|^11.0"
"phpunit/phpunit": "^10.0|^11.0",
"laravel/pint": "^1.19"
}
}
8 changes: 5 additions & 3 deletions src/Formatting/FormatDefinition.php
Original file line number Diff line number Diff line change
@@ -13,16 +13,18 @@
class FormatDefinition
{
protected Collection $formats;

protected bool $isExplicitlyDefault;

protected ReflectionMethod $reflection;

public function __construct(ReflectionMethod $reflection)
{
$this->reflection = $reflection;

$this->formats = (new Collection($this->reflection->getAttributes(Format::class)))
->map(fn(ReflectionAttribute $attribute) => $attribute->newInstance());
$this->isExplicitlyDefault = !empty($this->reflection->getAttributes(IsDefault::class));
->map(fn (ReflectionAttribute $attribute) => $attribute->newInstance());
$this->isExplicitlyDefault = ! empty($this->reflection->getAttributes(IsDefault::class));
}

public function invoke(object $object, $request): mixed
@@ -42,7 +44,7 @@ public function name(): string

public function names(): Collection
{
return $this->formats->map(fn(Format $format) => $format->name() ?? $this->reflection->getName())
return $this->formats->map(fn (Format $format) => $format->name() ?? $this->reflection->getName())
->unique();
}

22 changes: 13 additions & 9 deletions src/Formatting/FormatManager.php
Original file line number Diff line number Diff line change
@@ -16,9 +16,13 @@
class FormatManager
{
protected ?string $current;

protected ?FormatDefinition $default;

protected Collection $formats;

protected ReflectionObject $reflection;

protected object $subject;

public function __construct(object $subject)
@@ -27,13 +31,13 @@ public function __construct(object $subject)
$this->subject = $subject;

$definitions = (new Collection($this->reflection->getMethods()))
->filter(fn(ReflectionMethod $method) => !empty($method->getAttributes(Format::class)))
->filter(fn (ReflectionMethod $method) => ! empty($method->getAttributes(Format::class)))
->mapInto(FormatDefinition::class);

$this->formats = $definitions
->tap(Closure::fromCallable([$this, 'preventFormatNameCollisions']))
->flatMap(fn(FormatDefinition $definition) => $definition->names()
->mapWithKeys(fn(string $name) => [$name => $definition]));
->flatMap(fn (FormatDefinition $definition) => $definition->names()
->mapWithKeys(fn (string $name) => [$name => $definition]));

$this->default = $this->determineDefault($definitions);

@@ -67,7 +71,7 @@ public function hasFormat(string $name): bool

public function lacksFormat(string $name): bool
{
return !$this->hasFormat($name);
return ! $this->hasFormat($name);
}

public function select(string $name): static
@@ -87,7 +91,7 @@ protected function determineDefault(Collection $definitions): ?FormatDefinition
return $definitions->first();
}

$definitions = $definitions->filter(fn(FormatDefinition $definition) => $definition->isExplicitlyDefault());
$definitions = $definitions->filter(fn (FormatDefinition $definition) => $definition->isExplicitlyDefault());
$class = $this->reflection;

do {
@@ -99,17 +103,17 @@ protected function determineDefault(Collection $definitions): ?FormatDefinition
->first();

$class = $class->getParentClass();
} while($class && $default === null);
} while ($class && $default === null);

return $default;
}

protected function preventFormatNameCollisions(Collection $formatMethods): void
{
$formatMethods->flatMap(fn(FormatDefinition $definition) => $definition->names())
$formatMethods->flatMap(fn (FormatDefinition $definition) => $definition->names())
->countBy()
->filter(fn(int $count) => $count > 1)
->whenNotEmpty(fn(Collection $collisions) => throw new FormatNameCollisionException(
->filter(fn (int $count) => $count > 1)
->whenNotEmpty(fn (Collection $collisions) => throw new FormatNameCollisionException(
$this->subject,
$collisions->keys()->first(),
));
7 changes: 4 additions & 3 deletions src/Resource.php
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ abstract class Resource extends JsonResource
use SetsResponseStatus;

protected FormatManager $formatManager;

protected Collection $modifications;

public function __construct($resource)
@@ -48,8 +49,8 @@ public function format(string $name): static

public function modify(callable|array $modification): static
{
$modification = !is_callable($modification)
? fn(array $data) => array_merge($data, $modification)
$modification = ! is_callable($modification)
? fn (array $data) => array_merge($data, $modification)
: $modification;

$this->modifications->push($modification);
@@ -62,6 +63,6 @@ public function toArray($request)
$currentFormat = $this->formatManager->current() ?? throw new NoFormatSelectedException($this);
$data = $currentFormat->invoke($this, $request);

return $this->modifications->reduce(fn($carry, $modification) => $modification($carry, $this), $data);
return $this->modifications->reduce(fn ($carry, $modification) => $modification($carry, $this), $data);
}
}
6 changes: 3 additions & 3 deletions src/ResourceCollection.php
Original file line number Diff line number Diff line change
@@ -20,15 +20,15 @@ public function __construct($resource)
{
parent::__construct($resource);

if (!is_a($this->collects, Resource::class, true)) {
if (! is_a($this->collects, Resource::class, true)) {
throw new CannotEnhanceBaseResourcesException($this->collects);
}
}

public function __call($method, $parameters): mixed
{
if ((new ReflectionClass($this->collects))->hasMethod($method)) {
$this->collection->map(fn(Resource $resource) => $resource->{$method}(...$parameters));
$this->collection->map(fn (Resource $resource) => $resource->{$method}(...$parameters));

return $this;
}
@@ -38,7 +38,7 @@ public function __call($method, $parameters): mixed

public function format(string $name): static
{
$this->collection->each(fn(Resource $resource) => $resource->format($name));
$this->collection->each(fn (Resource $resource) => $resource->format($name));

return $this;
}
5 changes: 1 addition & 4 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
@@ -6,7 +6,4 @@

use Orchestra\Testbench\TestCase as OrchestraTestCase;

class TestCase extends OrchestraTestCase
{

}
class TestCase extends OrchestraTestCase {}
39 changes: 22 additions & 17 deletions tests/Unit/AnonymousResourceCollectionTest.php
Original file line number Diff line number Diff line change
@@ -19,10 +19,10 @@ public function test_anonymous_collection_records_are_formatted_correctly(
AnonymousResourceCollection $collection,
array $expectedData
): void {
# Act
// Act
$actualData = $collection->toArray(request());

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

@@ -31,16 +31,16 @@ public function test_anonymous_collection_can_be_modified_dynamically(
ResourceCollection $resource,
array $expectedData,
): void {
# Act
// Act
$actualData = $resource->toArray(request());

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

public function test_response_status_can_be_set(): void
{
# Arrange
// Arrange
$john = new stdClass;
$john->id = 1;
$john->firstName = 'John';
@@ -53,14 +53,14 @@ public function test_response_status_can_be_set(): void

$collection = ImplicitDefaultResource::collection([$john, $jane]);

# Act
// Act
$response = $collection->setResponseStatus(201)->response();

# Assert
// Assert
$this->assertSame(201, $response->getStatusCode());
}

# region Data Providers
// region Data Providers

public static function formatProvider(): array
{
@@ -176,7 +176,7 @@ public static function modificationProvider(): array
],
'closure modification adding data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(fn(array $data) => array_merge($data, ['middle_initial' => 'A.'])),
->modify(fn (array $data) => array_merge($data, ['middle_initial' => 'A.'])),
'expectedData' => [
[
'first_name' => 'John',
@@ -194,7 +194,7 @@ public static function modificationProvider(): array
],
'closure modification overwriting data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(fn(array $data) => array_merge($data, ['first_name' => 'Jon'])),
->modify(fn (array $data) => array_merge($data, ['first_name' => 'Jon'])),
'expectedData' => [
[
'first_name' => 'Jon',
@@ -210,7 +210,7 @@ public static function modificationProvider(): array
],
'closure modification completely overwriting data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(fn() => ['id' => 1]),
->modify(fn () => ['id' => 1]),
'expectedData' => [
['id' => 1],
['id' => 1],
@@ -238,7 +238,8 @@ public static function modificationProvider(): array
],
'invokable modification adding data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(new class {
->modify(new class
{
public function __invoke(array $data): array
{
return array_merge($data, ['middle_initial' => 'A.']);
@@ -261,7 +262,8 @@ public function __invoke(array $data): array
],
'invokable modification overwriting data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(new class {
->modify(new class
{
public function __invoke(array $data): array
{
return array_merge($data, ['first_name' => 'Jon']);
@@ -282,7 +284,8 @@ public function __invoke(array $data): array
],
'invokable modification completely overwriting data' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(new class {
->modify(new class
{
public function __invoke(array $data): array
{
return ['id' => 1];
@@ -295,7 +298,8 @@ public function __invoke(array $data): array
],
'invokable modification accessing resource' => [
'resource' => ImplicitDefaultResource::collection([$john, $jane])
->modify(new class {
->modify(new class
{
public function __invoke(array $data, ImplicitDefaultResource $resource): array
{
$data['id'] = $resource->resource->id * 2;
@@ -324,7 +328,8 @@ public function __invoke(array $data, ImplicitDefaultResource $resource): array

return $data;
})
->modify(new class {
->modify(new class
{
public function __invoke(array $data, ImplicitDefaultResource $resource): array
{
$data['id'] = $resource->resource->id * 2;
@@ -350,5 +355,5 @@ public function __invoke(array $data, ImplicitDefaultResource $resource): array
];
}

# endregion
// endregion
}
14 changes: 8 additions & 6 deletions tests/Unit/Enhancements/ExceptTest.php
Original file line number Diff line number Diff line change
@@ -18,20 +18,21 @@ public function test_except_enhancement_can_be_applied_to_resources(
Resource $resource,
array $expectedData,
): void {
# Act
// Act
$actualData = $resource->toArray(request());

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

# region Data Providers
// region Data Providers

public static function resourceProvider(): array
{
return [
'applied manually' => [
'resource' => (new class(null) extends Resource {
'resource' => (new class(null) extends Resource
{
#[Format]
public function foo(): array
{
@@ -48,7 +49,8 @@ public function foo(): array
],
],
'applied via trait' => [
'resource' => (new class(null) extends Resource {
'resource' => (new class(null) extends Resource
{
use HasExceptEnhancement;

#[Format]
@@ -69,5 +71,5 @@ public function foo(): array
];
}

# endregion
// endregion
}
Loading

0 comments on commit 150d5af

Please sign in to comment.