Budujemy przykładową aplikację w Laravel – część 4, model wypożyczeń

W kolejnym odcinku naszego cyklu poświęconego budowie aplikacji w Laravelu spróbujemy zaimplementować jedną z podstawowych funkcjonalności systemu – wypożyczenia. Zapraszam do lektury!

Prace jak zwykle rozpoczynamy od modyfikacji bazy, musimy stworzyć nową tabelę do przechowywania informacji o wypożyczeniach, tabela będzie zawierać:

  • id wypożyczenia
  • datę początku wypożyczenia
  • datę zwrotu sprzętu
  • dane wypożyczającego
  • id pojazdu wypożyczanego
  • cenę wypożyczenia
  • status opłaty
  • status wypożyczenia

W tym celu stwórzmy więc nową migrację:

I uzupełnijmy ją odpowiednimi polami:

Mając migrację utwórzmy model:

app\models\rent

Analogocznie jak w przypadku innych schematów, do modelu tworzymy repozytorium:

app\repositories\RentRepository.php:

W tym miejscu widzimy, iż nasze repozytorium posiada jedną metodę findDatesByVehicle(idVehicle). W metodzie tej kolejno:

  • dla konkretnego ID pojazdu pobieramy wszystkie rekordy z tabeli wypożyczenia
  • definiujemy początek i koniec sezonu wypożyczeń – od 1 kwietnia do 1 listopada, do obsługi dat używamy przy tym znakomitej klasy Carbon
  • Następnie tworzymy pętle iterującą po wszystkich dniach sezonu, oznacza to, iż przejdziemy po kolei, dzień po dniu każdy dzień od kwietnia do listopada
  • dla każdego z dni sezonu, sprawdzimy czy nie ma już zajętego sprzętu, musimy więc iterować po wypożyczeniach, czyli porównujemy każdy dzień z pobranych wypożyczeń z każdym dniem sezonu, jeśli dni się pokrywają, to będzie oznaczać iż sprzęt jest zajęty
  • wynikiem działania funkcji będzie lista dat od 1 kwietnia do 1 listopada, w przypadku gdy w danym dniu nie będzie wypożyczenia lista będzie zawierała jedynie datę, np:
    $dates[“2017-06-17”]=> “2017-06-17”
  • W przypadku gdy porównanie przyniesie informację, iż w danym dniu już istnieje wypożyczenie, oprócz daty system powinien zwrócić informacje także o samym wypożyczeniu, np:
    $dates[“2017-06-17”]=> “2017-07-16”,
    array(
    “start” => “2017-07-16 00:00:00”,
    “end” => “2017-07-18 23:59:59”,
    “renter” => “Renter 1”,
    “vehicle_id” => “1”,
    “price” => “2000”,
    “payment_status” => “1”,
    “status” => “2”
    )
  • oczywiście pobieramy tylko te rekordy z statusem = 2, co oznacza wypożyczenia zaakceptowane i potwierdzone przez przyszłego administratora systemu

W kolejnym kroku dane z repozytorium musimy umieścić w widoku, modyfikujemy nasz router, tak by obsługiwał pobieranie listy wypożyczeń (jako domyślny ustawiamy pojazd nr 1), dodatkowo od razu tworzymy routing do funkcji tworzącej nowe wypożyczenie.

routes/web.php:

Zgodnie z zapisem w web.php tworzymy kontroler Rent:

Kontroler nie robi nic odkrywczego, z repozytorium pobierana jest lista dat z wypożyczeniami i przekazywana do widoku rents. Oprócz tego przyda nam się również id pojazdu, więc ona również zostaje przekazana do widoku. Metoda create przyda nam się natomiast później.

Sam widok prezentuje się następująco:
layouts/rent.blade.php:

Pierwsza część widoku to klasyczna tabela, w której to za pomocą pętli for umieszczamy pobrane dane w postaci wierszy. Każdy wiersz to przede wszystkim konkretna data, jako, że zajęte daty są tablicami, sprawdzamy czy możemy bezkarnie wypisać datę, czy także musimy dodać wpis informujący, że dany termin jest zajęty. Każdy wiersz dodatkowo kończy checkbox, który służy do zaznaczania terminu nowego wypożyczenia.

Tak stworzony kod powinien być już w pełni funkcjonalny, spróbujmy uruchomić naszą stronę, /rents/1

Lista wyświetlana jest poprawnie. Czas przyjrzeć się funkcjonalności dodawania nowego wypożyczenia, a czynność tą rozpoczniemy od analizy wyżej zaprezentowanego widoku. Mianowicie zawiera on dwa dodatkowe elementy, niewidoczne gołym okiem. Są to:

  • przycisk ‘Zarezerwuj’, który to będzie pojawiał się w momencie gdy ktoś wybierze checkbox z konkretną datą
  • okienko modal z formularzem, którego wysłanie będzie równało się złożeniu rezerwacji. Okno to będzie pojawiało się dopiero w momencie wyboru przycisku ‘Zarezerwuj’. Formularz zawiera aż 3 pola ukryte – jedno z tokenem Laravela, drugie z identyfikatorem pojazdu, który jest wynajmowany i wreszcie trzecie z datami w formie listy. Lista ta jest mało poręczna dla użytkownika, dlatego też ją ukrywamy. Oczywiście adresem docelowym formularza jest nasz routing wybrany z web.php

W tym miejscu możemy wrócić do naszego kontrolera Rent i przyjrzeć się metodzie create, za parametry przyjmuje ona obiekt repository, a także samo rządanie, które widzimy jest klasy CreateRentRequest. Musimy więc taką klasę stworzyć:

Sama klasa definiuje przede wszystkim funkcję rules, w której podajemy wymagane pola. Co więcej, w klasie CreateRentRequest tworzymy również funkcję filtered. Funkcja ta zamienia listę dat, w których ma nastąpić wypożyczenie, na datę startu i datę końca wypożyczenia. Ponadto sprawdzamy, czy dni podane przez użytkownika tworzą ciąg – w naszym systemie jedna rezerwacja będzie mogła odnosić się do jednego zakresu dat, np: 17-07-2015 – 20-07-2017.

Ostatni element układanki to kod JavaScript. W pliku app.js umieszczamy kod poniżej:

Cóż on robi? Przede wszystkim implementuje wzorzec module w jQuery, a w nim:

  • przy każdym wybraniu checkboxa z datą następuje dodanie wybranej daty do listy, jeśli lista zawiera wybrane dni następuje pokazanie przycisku ‘zarezerwuj’. Analogicznie gdy lista z datami będzie pusta, przycisk znika.
  • daty przetrzymywane są w zmiennej dates
  • inicjalizacja kodu to również wywołanie zmiany checkboxów – przez to przeładowanie strony powoduje wyświetlenie bądź zniknięcie przycisku zależnie od zapisanego stanu dat
  • Lista dat zachowywana jest w ukrytym polu formularza z selektorem “.dates_input”

Uruchamiamy aplikację – wszystko powinno działać. Spróbujmy dodać nową rezerwację – wynik powinien zostać poprawnie zapisany w bazie.

Ostatnia sprawa – testy!

Przeanalizujmy co tak naprawdę chcemy przetestować:

  • pobieranie listy wszystkich wypożyczeń
  • tworzenie nowego wypożyczenia
  • pobieranie dat wolnych i dat z zajętymi wypożyczeniami dla konkretnego pojazdu

Najpierw – klasa factory:

Następnie tworzenie samego testu Rent Repository:

 

Klasa RentRepositoryTest składa się z 3 testów:

  • testGetAll – pobieranie wszystkich wypożyczeń, w niej kolejno tworzymy 3 wypożyczenia (dane statyczne pobieramy za pomocą getCreateData()), następnie pobieramy odpowiedź serwera za pomocą getFilteredResponse(), w której to usuwamy metadane created_at, updated_at i id. Na koniec oczywiście porównujemy dodane dane, a także dane zwrócone przez aplikację. Oczywiście dodane dane muszą zawierać się wynikach pobranych z serwera.
  • testCreate – tworzenie nowego wypożyczenia, podobnie jak w poprzednim przypadku dodajemy jedno z statycznych danych, a następnie sprawdzamy czy serwer zwraca dane, w których znajduje się nasz świeżo stworzony wpis
  • testFindDatesByVehicle – najciekawszy test, który sprawdza, czy zwracane przez system daty faktycznie zawierają informacje czy dany dzień jest już zajęty (i w takiej sytuacji system powinien zwrócić informacje o wypożyczeniu), czy też jest wolny. Na początku, standardowo dodajemy nowe wypożyczenie testowe. Nastepnie za pomocą funkcji getFindDatesByVehicleFilteredResponse pobieramy faktyczną odpowiedź serwera, z odpowiedzi tej usuwamy meta dane created_at, updated_at i id. Usuwamy także informacje o pojeździe, dla ułatwienia testujemy jedynie wypożyczenie i dane osoby wypożyczającej. Faktyczną odpowiedź serwera porównujemy z danymi statycznymi

Druga porcja testów dotyczy kontrolera. Nasz kontroler pokazujący listę wypożyczeń powinien jednorazowo uruchomić funkcję findDatesByVehicle, a takżedo widoku przekazać listę dat (dates), a także id pojazdu (vehicle_id), całość prezentuje się następująco:

I tyle. Wywołanie testów powinno dać pozytywny rezultat:

Mamy już 6 testów i 13 porównań! 🙂 W tym momencie przerwiemy etap tworzenia interfejsu klienta, a skierujemy się do panelu administracyjnego. Ktoś w końcu musi zatwierdzać dodane wypożyczenia. Oczywiście nasz system kliencki można rozbudować – przydałyby się e-maile wysyłane do administratorów, a także klientów którzy złożyli zamówienie (forma potwierdzenia przyjęcia rezerwacji). Kolejny odcinek już niedługo!

Kod źródłowy
Baza

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

This site uses Akismet to reduce spam. Learn how your comment data is processed.