Lewati ke konten utama

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.