Best practice – Entity a REST

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
greeny
Člen | 405
+
0
-

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
+
0
-

nějaké anotace nad fieldama, podle kterých externí služba zajistí export

takhle to přesně řeší http://jmsyst.com/libs/serializer

iNviNho
Člen | 352
+
0
-

Ak potrebujes konvertovat entitu, alebo premenne objektu do nejakeho pola bez rucneho vypisovania, tak mi parkrat pomohol Hydrator.

Ak som vedla, tak aspon pripomeniem, ze nieco take je :)

greeny
Člen | 405
+
0
-

Hydrator je fajn, už jsem na to taky koukal, tam je jen problém, že to nejde nějak customizovat a muselo by se upravovat to finální pole. Ale díky za názor :)

jiri.pudil
Nette Blogger | 1032
+
+5
-

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';

			// ...
		}
	}
}