Niestandardowe reguły walidacji w Laravelu (Rule)

by admin 0 Comments
Niestandardowe reguły walidacji w Laravelu (Rule)

Cześć w tym wpisie chciałbym poruszyć temat jak tworzyć niestandardowe 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 dostępne metody walidacji nie wystarczą i wtedy należy użyć czegoś bardziej zaawansowanego.

Inicjalizacja projektu

W poprzednim wpisie dodaliśmy podstawową walidacje danych. Tutaj znajduje się kod projektu, który możesz go pobrać i uruchomić lokalnie.

Tworzenie niestandardowej walidacji przy użyciu Rules

Nadal rozwijamy naszą aplikację opartą o zarządzanie produktami. Załóżmy że klient chce wprowadzić taką opcję, aby była możliwa usuwania tylko produktów, które są nieaktywne, czyli kolumna active w tabeli products musi być ustawiona na false. W tym celu stworzymy na samym początku requesta.

php artisan make:request ProductDeleteRequest

Jak pewnie wiesz ta komenda utworzy nam request, w którym możemy ująć reguły walidacji.

Kolejnym etapem jest stworzenie Rule, czyli customowego sprawdzenia poprawności danych. W tym celu użyjemy komendy:

php artisan make:rule ProductDeleteRule

Od razu uzupełniłem plik ProductDeleteRule, który będzie sprawdzał czy produkt jest deaktywowany.

<?php

namespace App\Rules;

use App\Product;
use Illuminate\Contracts\Validation\Rule;

class ProductDeleteRule implements Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$productExist = Product::query()->find($value);
return $productExist && $productExist->active ? false : true;
}

/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return "Aby usunąć produkt musi on być nieaktywny.";
}
}

Linijka poniżej sprawdza czy produkt istnieje w bazie danych, takie dodatkowe zabezpieczenie, przed błędami rzucanymi w aplikacji.

$productExist = Product::query()->find($value);

Linijka poniżej sprawdza czy produkt istnieje i jeśli istnieje to czy pole active ma wartość true.

return $productExist && $productExist->active ? false : true;

Metoda passes() w naszym Rule jest typu boolean, więc powinna zwracać true lub false. True oznacza że wszystko działa poprawnie. False zostanie zwrócony komunikat z metody message(), w naszym przypadku “Aby usunąć produkt musi on być nieaktywny.”.

Pozostało uzupełnić jeszcze request:

<?php

namespace App\Http\Requests;

use App\Rules\ProductDeleteRule;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\Rule;

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

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'productId' => ['required', 'exists:products,id', new ProductDeleteRule]
];
}

public function messages()
{
return [
'productId.exists' => "Wybrany produkt nie istnieje"
];
}

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

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

Wysyłamy w body jedno pole które musi być wymagane oraz exists:products,id sprawdza czy istnieje taki rekord w tabeli products o danym idku. Dodatkowo w messages zmieniłem komunikat, o tym aby pojawił się komunikat że wybrany produkt nie istnieje. Aby zdefiniować Rule w naszym requeście należy dodać new ProductDeleteRule.

Poprawmy jeszcze nasz kontroller i metodę która jest odpowiedzialna za usuwanie poszczególnego produktu.

/**
* Remove the specified resource from storage.
*
* @param ProductDeleteRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function destroy(ProductDeleteRequest $request)
{
Product::query()->find($request->productId)->delete();
return response()->json(['message' => 'Product deleted']);
}

Ostatnim krokiem jest zmiana naszego route w pliku api.php, od teraz nie będziemy podawać id produktu w urlu tylko w body.

Route::post('product/remove','ProductController@destroy');

Testowanie

Kilka zmian w naszym endpoincie wprowadziliśmy. Zatem, wykonajmy request który usunie jeden z produktów.

request usuwania obrazka

Jak widać produkt został usunięty. Jeśli ponownie wykonamy to zapytanie zostanie nam zwrócony błąd 422.

request nie można ponownie usunąć obrazka, który jest już usunięty

Podsumowanie

Tworzenie własnych reguł walidacji nie jest trudnym procesem. Rozwiązanie jest to przydatne przy zaawansowanych regułach walidacji, które wymagają np. sprawdzenia jakiegoś pola w bazie danych.

Poniżej znajdziesz przydatne linki:

  • Realizowany projekt: link
  • Wprowadzone zmiany: link
  • Stan projektu po zmianach: link

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>