Walidacja danych w Laravelu krok po kroku

by admin 2 Comments
Walidacja danych w Laravelu krok po kroku

W tym wpisie dowiesz się jak działa walidacja danych przy użyciu frameworka Laravel. Każda szanująca się aplikacja, waliduje dane które są wysyłane do serwera od użytkownika.

Inicjalizacja projektu

W poprzednim wpisie Jak stworzyć CRUD w Laravel? stworzyliśmy wszelkie niezbędne metody aby wylistować wszystkie produkty a także wyświetlić szczegółowe dane, dodać, edytować lub usunąć produkt. Tutaj znajduje się kod projektu, a tutaj link do stanu aplikacji z poprzedniego wpisu.

Pierwsza walidacja

Dla przykładu weźmy metodę która będzie zapisywać nam produkt do bazy danych. Mamy różne kolumny w naszej bazie danych nazwa produktu, opis cena oraz czy jest aktywny. W bazie danych kolumny mają rożne typy, co także powinniśmy uwzględnić. Każde z tych pól w bazie danych jest wymagane. Nasza metoda store w kontrolerze ProductController powinna wyglądać mniej więcej w następujący sposób:

public function store(Request $request)
{
    $validatedData = $request->validate([
        'name' => 'required|unique:products,name|min:5|max:255',
        'price' => 'required|numeric',
        'description' => 'required|min:20',
        'active' => 'required|boolean',
    ]);
    $product = new Product([
        'name' => $request->get('name'),
        'price' => $request->get('price'),
        'description'  => $request->get('description'),
        'active'  => $request->get('active')
    ]);
    $product->save();
    return response()->json($product);
}

Skupmy się na samym fragmencie dotyczącym walidacji

$validatedData = $request->validate([
    'name' => 'required|unique:products,name|min:5|max:255',
    'price' => 'required|numeric',
    'description' => 'required|min:20',
    'active' => 'required|boolean',
]);

Z obiektu Illuminate\Http\Request wykonujemy metodę walidate, która sprawdza nam czy dane są poprawne. Jeśli tak kod wykona się dalej, w tej metodzie przkazujemy tablicę, która odpowiada naszym danym, które przesyła do nas użytkownik. W kluczu podajemy nazwę pola, w wartości wymagania jakie muszą zostać spełnione aby walidacja się powiodła. Nawet nie znając dokładnie reguł walidacyjnych możesz się domyślić dokładnie co one mogą oznaczać. Poniżej znajduje się wytłumaczenie wszystkich reguł:

  • required – oznacza że dane pole jest wymagane
  • unique:products – wartość w kolumnie musi być unikalna w tabeli products
  • min – ilość minimalnych znaków
  • max – ilość maksymalnych znaków
  • numeric- liczba całkowita lub typu float
  • boolean – wartość może przyjmować true lub false

Reguł walidacyjnych jest bardzo duża ilość. Zachęcam do zapoznania się z dokumentacją Laravela, gdzie zostały opisane wszystkie dostępne reguły walidacji.

Wyślijmy błędny request i zobaczmy co się stanie:

błędna walidacja w laravelu błąd 200

Niestety dostaliśmy odpowiedź 200 i błędy nie zostały poprawnie obsłużone. W tym celu użyjemy obiektu Validator z Fasady Laravela:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'name' => 'required|unique:products,name|min:5|max:255',
    'price' => 'required|numeric',
    'description' => 'required|min:20',
    'active' => 'required|boolean',
]);
if ($validator->fails()) {
    dd($validator->errors());
}

Reguły walidacji zostawiłem bez zmian. Dodałem warunek że jeśli walidacja jest błędna to niech wyświetli wszystkie błędy z funkcją pomocniczą dd.

wyświetlenie błędów walidacji za pomocą funkcji dd

Jak widać błędy się pojawiły na ekranie, dlatego oznacza że walidacja działa poprawnie.

Reguły walidacyjne możemy zapisywać na wiele sposobów, może podawać parametry jako string oddzielając kreską pionową lub jako elementy w tablicy, obie metody są poprawne.

'active' => 'required|boolean'
'active' => ['required', 'boolean']

Wzorcowe tworzenie walidacji danych

Tworzenie walidacji w taki sposób nie jest najlepszym pomysłem. Jednym z powodem jest zachowanie czystości kodu projektu. Chcemy wyizolować logikę walidacji w inne miejsce, co sprawi że będzie można jej użyć w kilku miejscach. W naszym przypadku reguły walidacji w metodach edycji oraz tworzenia produktu będą takie same, co sprawią że kod nie będzie się powtarzał.

W tym celu stworzymy własne requesty za pomocą komendy:

php artisan make:request ProductRequest

Nasz form request utworzył się w ścieżce app\Http\Requests\ProductRequest.php Wygląda on obecnie tak:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

Metoda authorize zwraca false, ponieważ użytkownik musi być zalogowany. W metodzie rules uzupełniamy reguły walidacji.

/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules()
{
    return [
        'name' => $this->getMethod() == 'PUT' ? ["required", "min:5", "max:255", Rule::unique('products')->ignore($this->product->id)] : 'required|unique:products|min:5|max:255',
        'price' => 'required|numeric',
        'description' => 'required|min:20',
        'active' => 'required|boolean',
    ];
}

Z racji tego że nasza walidacja odbywa się na dwóch formach przesyłania danych metoda POST, która zapisuje dane oraz PUT, która aktualizuje dane. Musimy rozdzielić to na dwa warunki. Jeżeli zostanie ustawiona metoda zapisu PUT, wtedy należy dodać warunek

Rule::unique('products')->ignore($this->product->id)

Który wyszuka unikalność naszej wartości name, ale zignoruje obecny Id naszego produktu.

Dodatkowo musimy dodać metodę failedValidation, która zwróci nam błędy naszej walidacji.

protected function failedValidation(Validator $validator)
{
$errors = $validator->errors();

throw new HttpResponseException(response()->json([
'errors' => $errors
], JsonResponse::HTTP_UNPROCESSABLE_ENTITY));
}

Rzucamy wyjątkiem HttpResponseException aby zwrócić błędy używam JsonResponse::HTTP_UNPROCESSABLE_ENTITY, co pod tą wartością kryje się status HTTP 422, choć staram się korzystać z gotowych zmiennych, aby nie stosować w swoim projekcie “magic numbers”, co pozwala mi zachować czystość kodu w moim projekcie.

wyświetlenie błędów walidacji błąd 422 w jsonie

Jak widać błędy wyświetlają się poprawnie i zwracany jest status 422, wydaje się że moglibyśmy na tym zakończyć, ale lekko dodajmy usprawnień do naszego form requesta.

Atrybuty

Atrybuty pozwalają znam “przezywać” zmienne które są wysyłane do serwera. Najczęściej stosujemy konwencję anglojęzycznego nazewnictwa. Nikt nie tworzy tabeli użytkownicy, z kolumną hasło. Tylko raczej users i kolumna password, w rezultacie użytkownik jeśli zobaczyłby komunikat na ekranie: “Twoje password jest niepoprawne”, raczej nie byłby zadowolony. Dlatego korzystamy z atrybutów w następujący sposób:

public function attributes()
{
return [
'name' => "nazwa produktu",
'price' => "cena",
'description' => "opis produktu",
'active' => "status",
];
}

W rezultacie otrzymamy:

{
  "errors": {
    "name": [
      "The nazwa produktu field is required."
    ],
    "price": [
      "The cena field is required."
    ],
    "description": [
      "The opis produktu field is required."
    ],
    "active": [
      "The status field is required."
    ]
  }
}

Kolejnym krokiem byłoby przetłumaczenie komunikatów, ale tym zajmiemy się kiedy indziej gdy będziemy omawiać możliwość korzystania z wielu wersji językowych w naszej aplikacji.

Własne szablony wiadomości

Jeśli użytkownik popełni błąd podczas wypełniania formularza warto mu pomóc go uzupełnić poprawnie, ze względu na nasze założenia biznesowe mogą być bardziej wymagające np. pole musi spełniać jakieś warunki to wtedy wydarzy się dana akcja. W tym celu twórcy Laravela dodali metodę messages która pozwala zwracać nam customowe wiadomości błędy walidacji.

public function messages()
{
return [
'name.required' => "Pole :attribute jest wymagana oraz musi być unikalny",
'active.boolean' => "Produkt może przyjmować status aktywny lub nieaktywny.",
'price.numeric' => "Podana cena produktu jest niepoprawna."
];
}

Użyłem tutaj :attributes, co pozwala mi się odwołać do nazwy danego pola. W aplikacji do api restowego Insomia dostanę taki rezultat:

użycie atrybutów w walidacji

W rezultacie mamy całkiem nieźle działający formularz walidacji danych. Spróbujmy poprawnie uzupełnić dane i sprawdźmy czy dane zapisały się w bazie danych.

poprawna walidacja oraz zapisanie produktu.

Jak widać dostaliśmy status kodu 200, a nie 422 co oznacza że produkt został dodany do bazy danych, choć jak wcześniej wspomniałem dodajmy także walidację do metody aktualizujące dane. Logika działania walidacji będzie taka sama.

/**
* Update the specified resource in storage.
*
* @param ProductRequest $request
* @param Product $product
* @return \Illuminate\Http\JsonResponse
*/
public function update(ProductRequest $request, Product $product)
{
$product->name = $request->get('name');
$product->price = $request->get('price');
$product->description = $request->get('description');
$product->active = $request->get('active');
$product->save();
return response()->json($product);
}

Podsumowanie

Jak widzisz walidacja danych nie jest skomplikowanym procesem. Pamiętaj aby każde dane które otrzymujesz z zewnątrz powinny być zwalidowane. Poniżej znajdują się przydatne linki:

  • Realizowany projekt: link
  • Wprowadzone zmiany: link, podczas promocji postu jedna osoba znalazła błąd w kodzie, chodzi tutaj o wyszukiwanie unikalności nazwy produktu, tutaj są naniesione zmiany dodatkowe.
  • Stan projektu po zmianach: link

Comments ( 2 )

  1. Niestandardowe reguły walidacji w Laravelu (Rule) - Laravel Developer
    […] reguły walidacji, czyli Rule w Laravelu, często zwane jako customowe. Jak pewnie czytałeś ostatni wpis o walidacji, to zapewne wiesz jak działa walidacja w laravelu. Czasami zdarza się tak że […]
  2. 6 sposobów na zapis danych w Laravelu. - Laravel Developer
    […] przykładzie użyłem metody z requesta validated. Więcej o requestach możesz przeczytać w tym wpisie. Jaka jest prosta różnica pomiędzy nimi? Metoda validated() zwraca tablicę danych, która […]

Leave a reply

Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>