Lewati ke konten utama

Relasi Antar Entity di API Platform

Dalam API Platform, relasi antar entitas (OneToMany, ManyToOne, ManyToMany, OneToOne) secara otomatis dikonversi menjadi relasi API, termasuk pengelolaan data dan serialisasi JSON.


Contoh Kasus: Book & Author

Misalnya kita memiliki 2 entitas: Author dan Book. Setiap Book ditulis oleh satu Author (ManyToOne), dan satu Author bisa menulis banyak Book (OneToMany).


1. Entity Author

<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
class Author
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;

#[ORM\Column]
private string $name;

#[ORM\OneToMany(mappedBy: 'author', targetEntity: Book::class)]
private Collection $books;

public function __construct()
{
$this->books = new ArrayCollection();
}

// Getter dan Setter
}

2. Entity Book

<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
class Book
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;

#[ORM\Column]
private string $title;

#[ORM\ManyToOne(targetEntity: Author::class, inversedBy: 'books')]
#[ORM\JoinColumn(nullable: false)]
private ?Author $author = null;

// Getter dan Setter
}

Struktur JSON (Default) Endpoint GET /api/books/1 akan mengembalikan:

{
"@id": "/api/books/1",
"@type": "Book",
"id": 1,
"title": "Judul Buku",
"author": "/api/authors/2"
}

Endpoint GET /api/authors/2 akan mengembalikan:

{
"@id": "/api/authors/2",
"@type": "Author",
"id": 2,
"name": "Penulis",
"books": ["/api/books/1", "/api/books/3"]
}

Serialization Groups (Menampilkan Data Relasi) Secara default, relasi hanya menampilkan IRI (URL). Jika ingin menampilkan detail objek, Anda bisa menggunakan Serialization Groups.

Tambahkan Group

use Symfony\Component\Serializer\Annotation\Groups;

#[ApiResource(normalizationContext: ['groups' => ['book:read']])]
class Book
{
#[Groups(['book:read'])]
#[ORM\Column]
private string $title;

#[Groups(['book:read'])]
#[ORM\ManyToOne(targetEntity: Author::class)]
private ?Author $author = null;
}

Dan di Author:

#[Groups(['book:read'])]
#[ORM\Column]
private string $name;

Dengan konfigurasi ini, endpoint GET /api/books/1 akan mengembalikan:

{
"id": 1,
"title": "Judul Buku",
"author": {
"id": 2,
"name": "Penulis"
}
}

Cascade Persist (Opsional) Jika ingin saat menyimpan Book sekaligus menyimpan Author:

#[ORM\ManyToOne(targetEntity: Author::class, cascade: ['persist'])]
private ?Author $author = null;

Filtering Berdasarkan Relasi Aktifkan filter berdasarkan relasi:

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;

#[ApiFilter(SearchFilter::class, properties: ['author' => 'exact'])]
class Book { ... }

Gunakan query:

GET /api/books?author=/api/authors/2