PHP – Mapowanie zagnieżdżonych struktur JSON za pomocą JsonMapper

1
326
views

W poprzednich artykułach poruszałem już tematykę związaną z obsługą formatu JSON w języku PHP. Było co nieco na temat serializacji obiektów oraz walidacji schematu.

Do zamknięcia krótkiej serii o JSONie, brakuje jeszcze przedstawienia sposobu „deserializacji” danych zapisanych za pomocą tego popularnego formatu do obiektów PHP.

Kontekst – JSON

W artykule posługiwał będę się następującym zestawem danych:

Jak można się domyślić – jest to bardzo okrojona wersja, zbioru danych, reprezentujących zamówienie. W tym przypadku dwóch książek szanownego Uncle Boba. Wykorzystany został każdy z dostępnych typów w formacie JSON –object, array, string, number, boolean oraz null. Z punktu widzenia samego języka PHP, number zostanie przekształcony na int, a format zapisu daty i czasu może być reprezentowany jako obiekt klasy DateTime.

Zakładam również, że dostarczony JSON spełnia założenia walidacji i wszystkie pola zostały dostarczone. O samej walidacji schematu wspominałem w artykule nt. JSON Schema.

Pierwsza implementacja – ręczna

W pierwszej kolejności chciałbym przestawić przykładową implementację w sposób ręczny, bez użycia „wspomagaczy” w postaci zewnętrznych bibliotek.

Sprowadza się ona do założenia, że dla każdej z klas implementujemy statyczną, metodę fabrykującą create. Mógłbym posłużyć się interfejsem z generycznym nagłówkiem metody, która musi zostać zaimplementowana przez każdą z klas. Jednak dla ułatwienia i jedynie zobrazowania nakładu pracy pominę ten etap.

Implementujemy najpierw klasę Order agregującą wszelkie informacje na temat zamówienia:

Następnie uzupełniamy klasę Who reprezentującą osobę realizującą zamówienie:

Ostatnia klasa Item zawiera informacje na temat produktu wchodzącego w skład zamówienia:

Dobra, uruchommy jeszcze całość aby zweryfikować output:

Wszystko się zgadza. Otrzymaliśmy obiekt klasy Order który posiada następującą formę:

Dla prostej struktury danych (np. klasy Who i Item), która nie posiada zagnieżdżonych elementów, implementacja jest prosta, ilość kodu też nie przeraża. Problemy pojawiają się gdy przekształcić chcemy bardziej skomplikowany obiekt, jakim jest Order, złożony z tablic czy kolejnych pod obiektów. Pomijając weryfikację czy poszczególne klucze istnieją w tablicy asocjacyjnej, widzimy, że nawet w takim przypadku należy wyprodukować sporą ilość kodu – a jest to mimo wszystko bardzo prosty przykład.

Na ratunek przybywa JsonMapper

… nagle otwierają się drzwi, pojawia się blask. Po środku on sam, w pełnej swojej okazałości – Dżejson Mapper. Super bohater.

~ „Opowieści z programistycznej piwnicy” ~

Aby zniwelować ręczną implementację, posłużę się pewną formą abstrakcji. W tym przypadku w formie zewnętrznej biblioteki JsonMapper – mappera formatu JSON na odpowiednie instancje klas w języku PHP. Natywnie język nie wspiera mapowania tego formatu do obiektów więc albo sami zapewnimy pełną realizację mapowania lub będziemy polegać na sprawdzonym, gotowym, zewnętrznym rozwiązaniu.

Instalacja jak przystało na bibliotekę w języku PHP odbywa się za pomocą Composer:

Nasze klasy muszą nieco odchudzić swoją zawartość. Należy pozbyć się z każdej z nich, metody create. Pozostaje nam jedynie definicja pól publicznych wraz z adnotacją nt. typu.

Następnie musimy przekazać wszelkie niezbędne informacje do nowego mappera:

(1) Tworzymy instancję JsonMapper, nie wymaga ona żadnych parametrów dostarczanych do konstruktora.

(2) Konfigurujemy JsonMapper tak aby był w stanie przetworzyć każdy rezultat wywołania json_decode. Domyślnie oczekiwany jest rezultat w postaci tablicy asocjacyjnej.

(3) Ładujemy strukturę JSON z pliku, a następnie deserializujemy ją za pomocą funkcji json_decodeJsonMapper wymaga rezultatu wywołania funkcji json_decode().

(4) Wykonujemy proces mapowania na obiekty odpowiednich klas.

Efektem końcowym jest identycznie zbudowany obiekt Order jak w przypadku mapowania realizowanego w sposób manualny. Różnica jest w kwestii wykorzystania – cały ręczny element implementacji znika, a JsonMapper robi za nas „brudną robotę” 🙂

Podsumowanie

W poprzednich dwóch wpisach opierałem się na następujących podejściach rozwiązywania problemu:

  • z użyciem wbudowanej obsługi JsonSerializable w języku PHP,
  • przy użyciu zewnętrznej biblioteki implementującej standard JSON Schema.

Każde z zaproponowanych rozwiązań, dotyczy pewnego kontekstu. W tym przypadku nie jest inaczej – jak już wspominałem w innym artykule – to dodatkowa zależność w Twoim projekcie. To kolejny kawałek kodu który należy dołożyć z zewnątrz. Z drugiej strony – przetestowanego, działającego i popularnego kodu.

Jednak podsumowując – jeżeli nadmiarowość ręcznej implementacji Cię przerasta, to JsonMapper może być dobrym wyborem. Tak, też było w moim przypadku. Warto przypomnieć, że mapowanie struktury na obiekty (znanych klas, a nie stdClass) sprawia, że autouzupełnianie w IDE – działa! Do tego, łatwość użycia i wspieranie Immutable Object jest dużym plusem.

Dodam jeszcze, że artykuł nie wyczerpuje pełnego zakresu dostępnych opcji biblioteki JsonMapper raczej wskazuje, że jest ona jedną z ciekawszych, które można zastosować. Jeżeli staniesz przed wyzwaniem JSON => PHP Object to polecam Ci serdecznie JsonMapper oraz zapoznanie się z dokumentacją biblioteki w której opisano wszystkie dostępne opcje.