Skip to content

Commit

Permalink
fix laravel tests
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Jun 24, 2024
1 parent 722a340 commit db81e02
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 45 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,13 @@ jobs:
run: |
./vendor/bin/phpstan --version
./vendor/bin/phpstan analyse --no-interaction --no-progress --ansi
- name: Install Laravel
run: |
composer api-platform/laravel update
composer api-platform/laravel run-script build
- name: Run PHPStan analysis (laravel)
working-directory: 'src/Laravel'
run: |
composer update
./vendor/bin/phpstan analyse --no-interaction --no-progress --ansi
phpunit:
Expand Down Expand Up @@ -960,7 +963,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite, fileinfo
coverage: none
ini-values: memory_limit=-1
# Not in pecl
Expand Down Expand Up @@ -1011,7 +1014,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite, fileinfo
coverage: none
ini-values: memory_limit=-1
# Not in pecl
Expand Down
1 change: 0 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ parameters:
- '#Method Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::denormalize\(\) invoked with (2|3|4) parameters, 1 required\.#'
- '#Method Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize\(\) invoked with (2|3|4) parameters, 1 required\.#'

- '#Service "behat\.driver\.service_container" is not registered in the container\.#'
# Expected, due to backward compatibility
-
message: "#Call to function method_exists\\(\\) with ApiPlatform\\\\JsonApi\\\\Serializer\\\\ItemNormalizer and 'setCircularReferenc…' will always evaluate to false\\.#"
Expand Down
24 changes: 19 additions & 5 deletions src/Laravel/Eloquent/Metadata/IdentifiersExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,35 @@ public function getIdentifiersFromItem(object $item, ?Operation $operation = nul
private function getIdentifierValue(object $item, Link $link): mixed
{
if ($item instanceof ($link->getFromClass())) {
return $item->{$link->getIdentifiers()[0]};
return $this->getEloquentProperty($item, $link->getIdentifiers()[0]);
}

if ($item instanceof BelongsTo) {
return $item->getParent()->{$item->getForeignKeyName()};
return $this->getEloquentProperty($item->getParent(), $item->getForeignKeyName());
}

if ($toProperty = $link->getToProperty()) {
$relation = $item->{$toProperty}();
$relation = $this->getEloquentProperty($item, $toProperty);

if ($relation instanceof BelongsTo) {
return $item->{$relation->getForeignKeyName()};
return $this->getEloquentProperty($item, $relation->getForeignKeyName());
}
}

return $item->{$link->getIdentifiers()[0]};
return $this->getEloquentProperty($item, $link->getIdentifiers()[0]);
}

private function getEloquentProperty(object $item, string $property): mixed
{
if (method_exists($item, $property)) {
return $item->{$property}();
}

$getter = 'get'.ucfirst($property);
if (method_exists($item, $getter)) {
return $item->{$getter}();
}

return $item->{$property};
}
}
23 changes: 14 additions & 9 deletions src/Laravel/Tests/JsonApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ public function testGetCollection(): void

public function testGetBook(): void
{
$book = Book::find(1);
$response = $this->get('/api/books/1', ['accept' => ['application/vnd.api+json']]);
$book = Book::first();
$iri = $this->getIriFromResource($book);
$response = $this->get($iri, ['accept' => ['application/vnd.api+json']]);
$response->assertStatus(200);
$response->assertHeader('content-type', 'application/vnd.api+json; charset=utf-8');

$this->assertJsonContains([
'data' => [
'id' => '/api/books/1',
'id' => $iri,
'type' => 'Book',
'attributes' => [
'name' => $book->name, // @phpstan-ignore-line
Expand All @@ -68,7 +69,7 @@ public function testCreateBook(): void
'/api/books',
[
'data' => [
'attributes' => ['name' => 'Don Quichotte'],
'attributes' => ['name' => 'Don Quichotte', 'isbn' => fake()->isbn13()],
'relationships' => ['author' => ['data' => ['id' => $this->getIriFromResource($author), 'type' => 'Author']]],
],
],
Expand All @@ -88,12 +89,13 @@ public function testCreateBook(): void
],
],
], $response->json());
$this->assertMatchesRegularExpression('~^/api/books/\d+$~', $response->json('data')['id']);
$this->assertMatchesRegularExpression('~^/api/books/~', $response->json('data.id'));
}

public function testUpdateBook(): void
{
$iri = '/api/books/1';
$book = Book::first();
$iri = $this->getIriFromResource($book);
$response = $this->putJson(
$iri,
[
Expand All @@ -117,7 +119,8 @@ public function testUpdateBook(): void

public function testPatchBook(): void
{
$iri = '/api/books/1';
$book = Book::first();
$iri = $this->getIriFromResource($book);
$response = $this->patchJson(
$iri,
[
Expand All @@ -141,8 +144,10 @@ public function testPatchBook(): void

public function testDeleteBook(): void
{
$response = $this->delete('/api/books/1');
$book = Book::first();
$iri = $this->getIriFromResource($book);
$response = $this->delete($iri, ['accept' => 'application/vnd.api+json']);
$response->assertStatus(204);
$this->assertNull(Book::find(1));
$this->assertNull(Book::find($book->id));
}
}
16 changes: 16 additions & 0 deletions src/Laravel/Tests/JsonLdTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,20 @@ public function testCreateNotValidPost(): void
$this->assertCount(1, $violations);
$this->assertEquals($violations[0], ['propertyPath' => 'title', 'message' => 'The title field is required.']);
}

public function testSluggable(): void
{
$response = $this->get('/api/sluggables', ['accept' => 'application/ld+json']);
$response->assertStatus(200);
$response->assertHeader('content-type', 'application/ld+json; charset=utf-8');
$response->assertJsonFragment([
'@context' => '/api/contexts/Sluggable',
'@id' => '/api/sluggables',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 10,
]);
$iri = $response->json('hydra:member.0.@id');
$response = $this->get($iri, ['accept' => 'application/ld+json']);
$response->assertStatus(200);
}
}
2 changes: 1 addition & 1 deletion src/Laravel/Tests/JsonProblemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function testNotFound(): void
$response->assertHeader('content-type', 'application/problem+json; charset=utf-8');
$response->assertJsonFragment([
'@context' => '/api/contexts/Error',
'@id' => '/api/hydra_errors/404',
'@id' => '/api/errors/404.jsonld',
'@type' => 'hydra:Error',
'type' => '/errors/404',
'title' => 'An error occurred',
Expand Down
2 changes: 1 addition & 1 deletion src/Laravel/phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ parameters:
- Controller
- Eloquent
- Exception
- Metadata
- Routing
- State
- Test
- Tests
# ignoreErrors:
# - '#PHPDoc tag @var#'
Expand Down
23 changes: 0 additions & 23 deletions src/Laravel/workbench/app/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,20 @@

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post as PostOperation;
use ApiPlatform\Metadata\Put;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

#[ApiResource(
uriVariables: [
'slug',
],
operations: [
new Get(), new Put(), new Patch(), new Delete(),
],
rules: [
'title' => 'required',
]
)]
#[ApiResource(
operations: [
new GetCollection(), new PostOperation(),
]
)]
#[ApiProperty(property: 'title', types: ['https://schema.org/name'])]
class Post extends Model
{
use HasFactory;

public function getSlug(): string
{
return Str::slug($this->title);
}

/**
* Get the comments for the blog post.
*/
Expand Down
37 changes: 37 additions & 0 deletions src/Laravel/workbench/app/Models/Sluggable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Workbench\App\Models;

use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

#[Get(
uriVariables: [
'slug',
],
)]
#[GetCollection]
class Sluggable extends Model
{
use HasFactory;
protected $hidden = ['id', 'created_at', 'updated_at'];

public function getSlug(): string
{
return Str::slug($this->title);
}
}
2 changes: 0 additions & 2 deletions src/Laravel/workbench/database/factories/PostFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
namespace Workbench\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use Workbench\App\Models\Post;

/**
Expand Down Expand Up @@ -42,7 +41,6 @@ public function definition(): array

return [
'title' => $title,
'slug' => Str::slug($title),
];
}
}
48 changes: 48 additions & 0 deletions src/Laravel/workbench/database/factories/SluggableFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Workbench\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use Workbench\App\Models\Sluggable;

/**
* @template TModel of \Workbench\App\Models\Author
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel>
*/
class SluggableFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<TModel>
*/
protected $model = Sluggable::class;

/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
$title = fake()->unique()->sentence(10);

return [
'title' => $title,
'slug' => Str::slug($title),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ public function up(): void
});

Schema::create('posts', function (Blueprint $table): void {
$table->id();
$table->string('title');
$table->timestamps();
});

Schema::create('sluggables', function (Blueprint $table): void {
$table->id();
$table->string('title');
$table->string('slug')->unique();
Expand Down
2 changes: 2 additions & 0 deletions src/Laravel/workbench/database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Workbench\Database\Factories\BookFactory;
use Workbench\Database\Factories\CommentFactory;
use Workbench\Database\Factories\PostFactory;
use Workbench\Database\Factories\SluggableFactory;

class DatabaseSeeder extends Seeder
{
Expand All @@ -28,5 +29,6 @@ public function run(): void
{
BookFactory::new()->has(AuthorFactory::new())->count(10)->create();
PostFactory::new()->has(CommentFactory::new()->count(10))->count(10)->create();
SluggableFactory::new()->count(10)->create();
}
}

0 comments on commit db81e02

Please sign in to comment.