Skip to content

Commit 8cf2997

Browse files
committed
fix(laravel): read property type before serialization
fixes #7316
1 parent d1abfc0 commit 8cf2997

File tree

8 files changed

+140
-4
lines changed

8 files changed

+140
-4
lines changed

src/Laravel/ApiPlatformProvider.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ public function register(): void
262262
return new CachePropertyMetadataFactory(
263263
new SchemaPropertyMetadataFactory(
264264
$app->make(ResourceClassResolverInterface::class),
265-
new PropertyInfoPropertyMetadataFactory(
266-
$app->make(PropertyInfoExtractorInterface::class),
267-
new SerializerPropertyMetadataFactory(
268-
$app->make(SerializerClassMetadataFactory::class),
265+
new SerializerPropertyMetadataFactory(
266+
$app->make(SerializerClassMetadataFactory::class),
267+
new PropertyInfoPropertyMetadataFactory(
268+
$app->make(PropertyInfoExtractorInterface::class),
269269
new AttributePropertyMetadataFactory(
270270
new EloquentAttributePropertyMetadataFactory(
271271
new EloquentPropertyMetadataFactory(
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace ApiPlatform\Laravel\Tests;
4+
5+
use ApiPlatform\Laravel\Test\ApiTestAssertionsTrait;
6+
use Illuminate\Foundation\Testing\RefreshDatabase;
7+
use Orchestra\Testbench\Concerns\WithWorkbench;
8+
use Orchestra\Testbench\TestCase;
9+
use Workbench\App\ApiResource\Home;
10+
use Workbench\App\Models\Order;
11+
use Workbench\Database\Factories\OrderFactory;
12+
13+
class CustomRelationTest extends TestCase
14+
{
15+
use ApiTestAssertionsTrait;
16+
use RefreshDatabase;
17+
use WithWorkbench;
18+
19+
public function testCustomRelation(): void
20+
{
21+
$response = $this->get('/api/home', headers: ['accept' => ['application/ld+json']]);
22+
dd($response->json());
23+
$this->assertArrayHasKey('order', $response->json());
24+
$this->assertEquals([
25+
'id' => $order->id,
26+
'number' => $order->number,
27+
], $response->json()['order']);
28+
}
29+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Workbench\App\ApiResource;
4+
5+
use Workbench\Database\Factories\OrderFactory;
6+
use ApiPlatform\Metadata\ApiProperty;
7+
use ApiPlatform\Metadata\ApiResource;
8+
use ApiPlatform\Metadata\Get;
9+
use ApiPlatform\Metadata\Operation;
10+
use Symfony\Component\Serializer\Annotation\Groups;
11+
use Workbench\App\Models\Order;
12+
13+
#[ApiResource(
14+
operations: [
15+
new Get(
16+
uriTemplate: '/home',
17+
normalizationContext: ['groups' => ['home:read']],
18+
provider: [self::class, 'provide'],
19+
),
20+
],
21+
)]
22+
class Home
23+
{
24+
#[ApiProperty(identifier: true)]
25+
public int $id = 1;
26+
27+
#[Groups(['home:read'])]
28+
public ?Order $order = null;
29+
30+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null {
31+
$order = OrderFactory::new()->create();
32+
$home = new Home();
33+
$home->order = $order;
34+
35+
return $home;
36+
}
37+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Workbench\App\Models;
4+
5+
use ApiPlatform\Metadata\ApiProperty;
6+
use ApiPlatform\Metadata\ApiResource;
7+
use Illuminate\Database\Eloquent\Factories\HasFactory;
8+
use Illuminate\Database\Eloquent\Model;
9+
use Symfony\Component\Serializer\Attribute\Groups;
10+
11+
#[ApiResource()]
12+
#[ApiProperty(property: 'id', serialize: [new Groups(['home:read'])])]
13+
#[ApiProperty(property: 'number', serialize: [new Groups(['home:read'])])]
14+
class Order extends Model
15+
{
16+
use HasFactory;
17+
18+
protected $fillable = [
19+
'number',
20+
];
21+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Workbench\Database\Factories;
4+
5+
use Illuminate\Database\Eloquent\Factories\Factory;
6+
use Workbench\App\Models\Order;
7+
8+
class OrderFactory extends Factory
9+
{
10+
protected $model = Order::class;
11+
12+
public function definition()
13+
{
14+
return [
15+
'number' => $this->faker->randomNumber(),
16+
];
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration {
10+
/**
11+
* Run the migrations.
12+
*/
13+
public function up(): void
14+
{
15+
Schema::create('orders', function (Blueprint $table): void {
16+
$table->id();
17+
$table->integer('number');
18+
$table->timestamps();
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*/
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('orders');
28+
}
29+
};

src/Metadata/Property/Factory/PropertyInfoPropertyMetadataFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Metadata\Property\Factory;
1515

16+
use Workbench\App\ApiResource\Home;
1617
use ApiPlatform\Metadata\ApiProperty;
1718
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
1819
use Doctrine\Common\Collections\ArrayCollection;

src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use ApiPlatform\Metadata\Util\ResourceClassInfoTrait;
2020
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
2121
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface as SerializerClassMetadataFactoryInterface;
22+
use Workbench\App\ApiResource\Home;
2223

2324
/**
2425
* Populates read/write and link status using serialization groups.

0 commit comments

Comments
 (0)