Automatic Foreign Key Linking di API Platform
Saat membuat relasi antar entitas di API Platform, seperti relasi ManyToOne
, kita sering membutuhkan agar properti relasi seperti user
atau owner
di-set otomatis berdasarkan user yang sedang login, tanpa harus dikirim dari frontend. Ini disebut automatic foreign key linking.
1. Studi Kasus: Komentar Milik User
Kita ingin agar saat user membuat Comment
, field user
langsung di-set ke user yang sedang login.
Entitas Comment:
#[ApiResource(
operations: [
new Post(security: "is_granted('ROLE_USER')")
]
)]
class Comment
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column(type: "integer")]
private ?int $id = null;
#[ORM\Column(type: "text")]
private ?string $content = null;
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(nullable: false)]
private ?User $user = null;
// ... getter & setter
}
🎯 Tujuan: user harus diisi otomatis berdasarkan Security::getUser(), bukan dari payload frontend.
2. Menggunakan Data Persister
Kita gunakan custom DataPersister untuk mengatur nilai user sebelum entitas disimpan ke database:
use Symfony\Component\Security\Core\Security;
use ApiPlatform\State\ProcessorInterface;
class CommentDataPersister implements ProcessorInterface
{
public function __construct(
private Security $security,
private EntityManagerInterface $em
) {}
public function process(mixed $data, array $context = []): object
{
if ($data instanceof Comment && !$data->getId()) {
$data->setUser($this->security->getUser());
}
$this->em->persist($data);
$this->em->flush();
return $data;
}
}
Pastikan CommentDataPersister
terdaftar sebagai service, dan hanya untuk Comment
.
3. Jangan Tampilkan Field Relasi di Input
Gunakan groups
untuk membatasi serialization/deserialization:
use Symfony\Component\Serializer\Annotation\Groups;
#[Groups(['read'])]
private ?User $user = null;
user
tidak perlu masuk di input, tapi tetap tampil di response.
4. Contoh Request Tanpa FK Manual
POST /api/comments
{
"content": "Komentar dari user login"
}
Response:
{
"@context": "/api/contexts/Comment",
"@id": "/api/comments/12",
"content": "Komentar dari user login",
"user": "/api/users/5"
}
5. Alternatif: Event Listener (Opsional)
Jika ingin set user
di level doctrine (bukan API Platform), bisa pakai Doctrine EventSubscriber
, tapi cara ini tidak kontekstual terhadap user dari request API Platform (kurang direkomendasikan).
6. Validasi Otomatis FK Tidak Null
Karena user
wajib (nullable: false), validasi otomatis akan menolak request jika tidak di-set, maka penting memastikan DataPersister
mengisi field ini sebelum flush()
.
Kesimpulan
✅ Gunakan DataPersister
untuk set FK otomatis (misalnya user
)
✅ Hindari input FK dari client-side untuk keamanan
✅ Gunakan serialization groups
untuk menyembunyikan field saat input
✅ Hindari redudansi dan risiko manipulasi oleh user
🔐 Teknik ini menjaga integritas data dan menghindari eksploitasi foreign key
oleh user tak sah.