Best practice – Entity a REST
- greeny
- Člen | 405
Zdravím, narazil jsem na menší problém a chtěl bych vědět, jak ho řešíte vy.
Mám Doctrine entity (private fields, getters + setters) a JSON REST API. Potřebuju nějakým způsobem konvertovat entity do objektů, které se pak pošlou payloadem. Je ale potřeba dát pozor na tohle:
- výsledný objekt nemusí nutně nést všechny properties z entity
- výsledný objekt může nést i properties které nejsou definované v entitě
- výsledný objekt může některé pole mít v jiné podobě než entita (typicky konstanty se např. převedou na string)
- v některých případech je nutné zpracovat i relace daného objektu (pozor na rekurzi u bi-directional vazeb)
Napadlo mě již několik řešení:
- entity určené k exportu do JSONu budou implementovat nějakej IJsonSerializable interface s metodou např toJson(), která konvertuje danou entitu na JSON (včetně vazeb) (nebo taky na pole)
- nějakou externí službu, která přes reflexi vytáhne parametry a gettery a vyrobí JSON (něco na tento způsob: https://gist.github.com/…-h57/3714787, jen lepší coding style a pár fixů)
- pro každou entitu externí službu, která bez reflexe vytáhne parametry co jsou potřeba a vrátí je
- nějaké anotace nad fieldama, podle kterých externí služba zajistí export
Jak tohle řešíte vy?
- voda
- Člen | 561
nějaké anotace nad fieldama, podle kterých externí služba zajistí export
takhle to přesně řeší http://jmsyst.com/libs/serializer
- jiri.pudil
- Nette Blogger | 1032
PHP má interface JsonSerializable, ale nepřijde mi vhodné, aby entita
věděla o tom, že se používá v nějakém REST API a jak je v něm
reprezentovaná. Šel bych spíš opačnou cestou – napsat si
FooResponse
třídu, která ví, v jakém formátu má být
výstup a co v něm má být. Takovému response objektu pak předáš, co
potřebuje, a v nějaké třeba toArray
metodě si ten výstup
sestavíš. Můžeš tam pak celkem pěkně pracovat i např. s těmi
konstantami nebo asociacemi.
class FooResponse
{
private $foo;
public function __construct(FooEntity $foo)
{
$this->foo = $foo;
}
public function toArray()
{
return [
'id' => $this->foo->getId(),
'bar' => $this->getBarAsString($this->foo->getBar()),
'baz' => array_map(function (BazEntity $baz) {
return (new BazResponse($baz))->toArray();
}, $this->foo->getBazCollection()->toArray()),
];
}
private function getBarAsString($value)
{
switch ($value) {
case FooEntity::BAR_1:
return 'bar1';
// ...
}
}
}