REST w ZF2 – metody PUT i DELETE w formularzach

Uwaga! Ten wpis został napisany ponad rok temu i informacje w nim zawarte mogą być nieaktualne.

Architektura dostępu do danych REST staje się coraz bardziej popularna w Internecie. Coraz częściej trafiam na serwisy działające w ten sposób, coraz więcej frameworków obsługuje ten wzorzec. W Internecie dużo już napisano na temat samego sposobu implementacji, ale w skrócie chodzi w głównym stopniu o sposobie dostępu dodanych przez protokół HTTP wykorzystując 4 typy (metody) zapytań i odpowiednie formatowanie adresów URI. Zazwyczaj standardowe serwisy korzystają z zapytań GET i POST. REST proponuje wykorzystanie też PUT i DELETE (HTTP definiuje jeszcze kilka kolejnych, jeszcze rzadziej wykorzystywanych).

Najcześciej wykorzystywane i obsługiwane przez frameworki zapytania to (podane na przykładzie zasobu users):

  • GET /users – pobranie listy zasobów (tutaj użytkowników)
  • GET /users/5 – pobranie danych konkretnego zasobu o podanym identifykatorze
  • POST /users – utworzenie nowego zasobu
  • PUT /users/5 – aktulizacja (edycja) konkretnego zasobu
  • DELETE /users/5 – usunięcie konkretnego zasobu

Jak widać zapytania te odpowiadają standardowemu modelowi CRUD (create, read/retrieve, update, delete/destroy) – czynnościom wykonywanym na danych w 99% przypadków działania aplikacji.

Cały czas rozwijany Zend Framework 2 jest tworzony z całkiem niezłą obsługą REST. Przygotowany został specjalny typ kontrolera – RestfulController – w którym znajdziemy abstrakcyjne metody getList, get, create, update i delete odpowiadające wyżej wymienionym RESTowym akcjom. Niestety, problem cały czas stanowią przeglądarki, które niebardzo chcą RESTowe zapytania obsługiwać. A dokładniej wysyłać dane z typem zapytania PUT lub DELETE. Wiele innych frameworków obsługuje takie czy inne sztuczki do pominięcia tego ograniczenia, jednak w ZF2 niczego takiego nie udało mi się znaleźć. Być może zostanie to dodane w przyszłości, ale już teraz poradzenie sobie z tym nie wymaga wiele pracy.

Zapytania PUT i DELETE zmieniają dane w bazie (a PUT dodatkowo przesyła dane do serwera), więc bliżej im do POST niż do GET. Wykorzystamy więc standardowy formularz HTMLowy, ale z dodatkowym ukrytym parametrem _method o wartości metodą, którą chcemy „przemycić”:

Następnie musimy przechwycić te dane i wskazać klasie żądania nowy sposób działania. Robimy to na zdarzeniu bootstrap na wysokim priorytecie (żeby kod został wykonany jak najwcześniej). Akcję definiujemy w dowolnym module, gdzie najlepiej będzie to pasowało do konkretnej aplikacji, może to być na przykład standardowy moduł Application. Edytujemy plik Module.php z katalogu głównego modułu i wpisujemy w nim metodę init:

Jeżeli w konkretnym module metoda już istnieje dopisujemy tylko brakujące linie. Spowoduje to uruchomienie na bardzo wczesnym etapie zdarzenia bootstrap metody overrideMethod z bieżącego obiektu (trzeci parametr metody attach definuje callback). Musimy tę metodę stworzyć (w tej samej klasie Module):

Metoda kolejno:

  • pobiera obiekt Request z Eventu (linia 3),
  • sprawdza, czy rządanie jest typu POST (linia 5),
  • testuje zawartość pola _method (linia 6),
  • nadpisuje odpowiednią metodę zapytania (linie 8 i 12),
  • przepisuje dane wejściowe (klasa Request z ZF2 spodziewa się tylko formatu POST, linia 9).

Od tej pory w aplikacji można normalnie używać kontrolerów RestfulControler i ich standardowych akcji łącznie z parametrem $data dla create i update.

Dodaj komentarz