diff --git a/src/Laravel/ApiPlatformProvider.php b/src/Laravel/ApiPlatformProvider.php index 18c40e6a4e..45c1989ab1 100644 --- a/src/Laravel/ApiPlatformProvider.php +++ b/src/Laravel/ApiPlatformProvider.php @@ -262,10 +262,10 @@ public function register(): void return new CachePropertyMetadataFactory( new SchemaPropertyMetadataFactory( $app->make(ResourceClassResolverInterface::class), - new PropertyInfoPropertyMetadataFactory( - $app->make(PropertyInfoExtractorInterface::class), - new SerializerPropertyMetadataFactory( - $app->make(SerializerClassMetadataFactory::class), + new SerializerPropertyMetadataFactory( + $app->make(SerializerClassMetadataFactory::class), + new PropertyInfoPropertyMetadataFactory( + $app->make(PropertyInfoExtractorInterface::class), new AttributePropertyMetadataFactory( new EloquentAttributePropertyMetadataFactory( new EloquentPropertyMetadataFactory( diff --git a/src/Laravel/Tests/JsonLdTest.php b/src/Laravel/Tests/JsonLdTest.php index 4f9b4d3609..9ee7596965 100644 --- a/src/Laravel/Tests/JsonLdTest.php +++ b/src/Laravel/Tests/JsonLdTest.php @@ -369,4 +369,13 @@ public function testResourceWithOptionModel(): void '@type' => 'Collection', ]); } + + public function testCustomRelation(): void + { + $response = $this->get('/api/home', headers: ['accept' => ['application/ld+json']]); + $home = $response->json(); + $this->assertArrayHasKey('order', $home); + $this->assertArrayHasKey('id', $home['order']); + $this->assertArrayHasKey('number', $home['order']); + } } diff --git a/src/Laravel/workbench/app/ApiResource/Home.php b/src/Laravel/workbench/app/ApiResource/Home.php new file mode 100644 index 0000000000..aab095d693 --- /dev/null +++ b/src/Laravel/workbench/app/ApiResource/Home.php @@ -0,0 +1,49 @@ + + * + * 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\ApiResource; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\Operation; +use Symfony\Component\Serializer\Annotation\Groups; +use Workbench\App\Models\Order; +use Workbench\Database\Factories\OrderFactory; + +#[ApiResource( + operations: [ + new Get( + uriTemplate: '/home', + normalizationContext: ['groups' => ['home:read']], + provider: [self::class, 'provide'], + ), + ], +)] +class Home +{ + #[ApiProperty(identifier: true)] + public int $id = 1; + + #[Groups(['home:read'])] + public ?Order $order = null; + + public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $order = OrderFactory::new()->create(); + $home = new self(); + $home->order = $order; + + return $home; + } +} diff --git a/src/Laravel/workbench/app/Models/Order.php b/src/Laravel/workbench/app/Models/Order.php new file mode 100644 index 0000000000..cc063e6818 --- /dev/null +++ b/src/Laravel/workbench/app/Models/Order.php @@ -0,0 +1,32 @@ + + * + * 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\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; +use Symfony\Component\Serializer\Attribute\Groups; + +#[ApiResource()] +#[ApiProperty(property: 'id', serialize: [new Groups(['home:read'])])] +#[ApiProperty(property: 'number', serialize: [new Groups(['home:read'])])] +class Order extends Model +{ + use HasFactory; + + protected $fillable = [ + 'number', + ]; +} diff --git a/src/Laravel/workbench/database/factories/OrderFactory.php b/src/Laravel/workbench/database/factories/OrderFactory.php new file mode 100644 index 0000000000..6613d1f7b3 --- /dev/null +++ b/src/Laravel/workbench/database/factories/OrderFactory.php @@ -0,0 +1,29 @@ + + * + * 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 Workbench\App\Models\Order; + +class OrderFactory extends Factory +{ + protected $model = Order::class; + + public function definition() + { + return [ + 'number' => $this->faker->randomNumber(), + ]; + } +} diff --git a/src/Laravel/workbench/database/migrations/2025_05_08_000000_create_orders_table.php b/src/Laravel/workbench/database/migrations/2025_05_08_000000_create_orders_table.php new file mode 100644 index 0000000000..be65979336 --- /dev/null +++ b/src/Laravel/workbench/database/migrations/2025_05_08_000000_create_orders_table.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +return new class extends Migration { + /** + * Run the migrations. + */ + public function up(): void + { + Schema::create('orders', function (Blueprint $table): void { + $table->id(); + $table->integer('number'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('orders'); + } +};