Prezentacja, która miała miejsce 2018-03-07 w Poznaniu. Wykonanie: Marek Tenus (HighSolutions). Podstawy tworzenia Form Requestów w miejsce standardowego obiektu Request. Opis zalet i wad takiego rozwiązania.
19. #3 - Klasyczna obsługa żądań
Routes
/api/article GET index
/api/article POST store
20. #3 - Klasyczna obsługa żądań
Routes Middleware
/api/article GET index
/api/article POST store
21. #3 - Klasyczna obsługa żądań
Routes Middleware
/api/article GET index
/api/article POST store
allow or deny
22. #3 - Klasyczna obsługa żądań
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
23. #3 - Klasyczna obsługa żądań
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
get request
handle request
do some stuff
return response
24. #3 - Klasyczna obsługa żądań
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
get request
handle request
do some stuff
return response
25. #3 - Klasyczna obsługa żądań
namespace AppHttpControllersEventController;
use AppHttpControllersController;
use IlluminateHttpRequest;
class EventController extends Controller
{
}
26. #3 - Klasyczna obsługa żądań
namespace AppHttpControllersEventController;
use AppHttpControllersController;
use IlluminateHttpRequest;
class EventController extends Controller
{
}
27. #3 - Klasyczna obsługa żądań
public function __construct() {}
public function index() {} //GET
public function create() {} //GET
public function store() {} //POST
public function edit() {} //GET
public function update() {} //PUT/PATCH
public function destroy() {} //DELETE
28. #3 - Klasyczna obsługa żądań
public function store(Request $request) {
}
29. #3 - Klasyczna obsługa żądań
public function store(Request $request) {
}
Dependency Injection
30. #3 - Klasyczna obsługa żądań
public function store() {
$request = request();
}
31. #3 - Klasyczna obsługa żądań
public function store() {
$request = request();
}
Current instance of Request
32. #3 - Klasyczna obsługa żądań
public function store(Request $request) {
//authorize the request access(?)
//check if the request has valid data
//store the event member
//give some response
}
33. #3 - Klasyczna obsługa żądań
//authorize the request access(?)
abort_if(!$request->ajax(), 403);
//check if request has valid data
$request->validate([
'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'department_id' => 'required|exists:departments,id',
'note' => 'max:512',
]);
//store the event member
EventMember::create($request->all());
//give some response
return [
‘success’ => true,
];
34. #4 - Form Request
● Klasa dziedzicząca z klasy Request
● Posiada wbudowaną logikę walidacji
● Autoryzacja dostępu do wykonania żądania
● Czy pozwala na więcej?!
35. #4 - Form Request
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
get request
handle request
do some stuff
return response
36. #4 - Form Request
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
get request
do some stuff
return response
Form
Request
handle request
- validation
- authorization
37. #4 - Form Request
Routes Middleware Controller
/api/article GET index
/api/article POST store
allow or deny
get request
do some stuff
return response
Form
Request
handle request
- validation
- authorization
38. #4 - Form Request
php artisan make:request StoreEventMemberRequest
39. #4 - Form Request
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return false;
}
public function rules()
{
return [
];
}
}
40. #4 - Form Request
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
];
}
}
41. #4 - Form Request
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return true;
}
}
42. #4 - Form Request
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return $this->ajax();
}
}
true => access
false => 403
43. #4 - Form Request
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return $this->ajax();
}
} protected function failedAuthorization()
{
throw new HttpResponseException($this->forbiddenResponse());
}
true => access
false => 403
44. #4 - Form Request
class StoreEventMemberRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'department_id' => 'required|exists:departments,id',
'note' => 'max:512',
];
}
}
45. #4 - Form Request
public function messages()
{
return [
‘first_name.required’ => ‘Your first name is required’,
‘last_name.required’ => ‘Your last name is required’,
];
}
46. #4 - Form Request
public function attributes()
{
return [
‘first_name’ => ‘Your first name’,
‘last_name’ => ‘Your last name’,
];
}
47. #4 - Form Request
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
}
48. #4 - Form Request
use AppHttpControllersController;
use IlluminateHttpRequest;
use AppHttpRequestsStoreEventMemberRequest;
class EventController extends Controller
{
}
49. #4 - Form Request
public function store(StoreEventMemberRequest $request)
{
//authorize the request access(?)
//check if request has valid data
//store the event member
//give some response
}
50. #4 - Form Request
//authorize the request access(?)
abort_if(!$request->ajax(), 403);
//check if request has valid data
$request->validate([
'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'department_id' => 'required|exists:departments,id',
'note' => 'max:512',
]);
//store the event member
EventMember::create($request->all());
//give some response
return [
‘success’ => true,
];
51. #4 - Form Request
//authorize the request access(?)
abort_if(!$request->ajax(), 403);
//check if request has valid data
$request->validate([
'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'department_id' => 'required|exists:departments,id',
'note' => 'max:512',
]);
//store the event member
EventMember::create($request->all());
//give some response
return [
‘success’ => true,
];
52. #4 - Form Request
public function store(StoreEventMemberRequest $request) {
EventMember::create($request->all());
return [
‘success’ => true,
];
}
55. #4 - Form Request
● Oczyszczanie danych formularza (sanitizing)
● Manipulacja danymi formularza (handling)
● Logowanie zdarzeń (logging)
56. #5 - Zastosowanie Form Request w projekcie
● Oczyszczanie danych formularza (sanitizing)
● Manipulacja danymi formularza (handling)
● Logowanie zdarzeń (logging)
57. #5 - Zastosowanie Form Request w projekcie
public function all()
{
}
58. #5 - Zastosowanie Form Request w projekcie
public function all()
{
$attributes = parent::all();
return collect($attributes)
->map(function($field) {
return $field ?? filter_var($field,
FILTER_SANITIZE_STRING);
})
->all();
}
59. #5 - Zastosowanie Form Request w projekcie
public function all()
{
$attributes = parent::all();
return collect($attributes)
->map(function($field) {
return $field ?? filter_var($field,
FILTER_SANITIZE_STRING);
})
->all();
}
$_POST[‘data’] = [...];
422 (Unprocessable Entity)
60. #5 - Zastosowanie Form Request w projekcie
public function all()
{
$attributes = parent::all();
return collect($attributes)
->map(function($field) {
return $field ?? filter_var($field,
FILTER_SANITIZE_STRING);
})
->all();
}
$_POST[‘data’] = [...];
422 (Unprocessable Entity)
public function response(array $errors)
{
if ($this->ajax() || $this->wantsJson()) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
61. #5 - Zastosowanie Form Request w projekcie
public function all()
{
$attributes = parent::all();
return $this->sanitizeAttributes($attributes);
}
$_POST[‘data’] = [...];
protected function sanitizeAttributes($attributes) {
return collect($attributes)
->map(function($field) {
return $field ?? filter_var($field,
FILTER_SANITIZE_STRING);
})
->all();
}
62. #5 - Zastosowanie Form Request w projekcie
public function all()
{
$attributes = $this->input('data');
$attributes['token'] = $this->input('token');
return $this->sanitizeAttributes($attributes);
}
63. #5 - Zastosowanie Form Request w projekcie
public function all()
{
return $this->sanitizeAttributes($this->handleAttributes());
}
protected function handleAttributes() {
$attributes = $this->input('data');
$attributes['token'] = $this-
>input('token');
return $attributes;
}
64. #5 - Zastosowanie Form Request w projekcie
public function all()
{
return $this->sanitizeAttributes($this->handleAttributes());
}
protected function handleAttributes() {
if(!$this->has(‘data’)) {
return parent::all();
}
$attributes = $this->input('data');
$attributes['token'] = $this->input('token');
return $attributes;
}
wskazuje na kontroller/metoda
weryfikuje sposób przesyłania danych / post, get, etc.
umożliwia walidację przesyłanych zmiennych - wzorce
tworzenie nazw routów -> generowanie urli
Middleware - warstwa aplikacji, która jest odpowiedzialna za filtrowanie żądania HTTP, middleware może również być wykorzystywany przy response
dodanie nagłówków
logowanie zdarzeń
wskazanie middleware w routes
handle request - validation, auth, do some stuff
routes + middleware = mur obronny
ale skupmy się na kontrolerze
REST API schema
Wstrzykiwanie zależności (ang. Dependency Injection, DI) – wzorzec projektowy i wzorzec architektury oprogramowania polegający na usuwaniu bezpośrednich zależności pomiędzy komponentami na rzecz architektury typu plug-in. Polega na przekazywaniu gotowych, utworzonych instancji obiektów udostępniających swoje metody i właściwości obiektom, które z nich korzystają (np. jako parametry konstruktora). Stanowi alternatywę do podejścia, gdzie obiekty tworzą instancję obiektów, z których korzystają np. we własnym konstruktorze.
Posiada wbudowaną logikę walidacji
ustalanie reguł
tworzenie custom rules
tworzenie custom messages on fail
tworzenie custom response on fail
form request - ma właściwości middleware i przejmuje zadanie kontrollera
Determine if the user is authorized to make this request
Determine if the user is authorized to make this request
Determine if the user is authorized to make this request
Adding After Hooks To Form Requests
tu również pokazać, że mogłaby być dodatkowa weryfikacja, czy user może wykonać daną akcję, czy zapytanie jest ajaxowe etc.
tak wygląda kod bez form request
kod po zastosowaniu form request
czy możemy zastosować form request do czegoś jeszcze? pytanie do słuchaczy
czy możemy zastosować form request do czegoś jeszcze? pytanie do słuchaczy
metoda Request all()
FILTER_SANITIZE_STRING = Strip tags, optionally strip or encode special characters
The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.
For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
Clean code: mniej kodu, rozdzielenie metod
SRP (Zasada jednej odpowiedzialności) Klasa powinna mieć tylko jedną odpowiedzialność (nigdy nie powinien istnieć więcej niż jeden powód do modyfikacji klasy).
Clean code: mniej kodu, rozdzielenie metod
SRP (Zasada jednej odpowiedzialności) Klasa powinna mieć tylko jedną odpowiedzialność (nigdy nie powinien istnieć więcej niż jeden powód do modyfikacji klasy).