Do tej pory definiowaliśmy ścieżki naszej aplikacji używając funkcji anonimowych. Zamiast tego moglibyśmy użyć kontrolerów, czyli klas w których obsługujemy kilka ścieżek. Najczęściej w jednym kontrolerze grupujemy ścieżki, które są ze sobą powiązane. Na przykład te odpowiedzialne za dodawanie, wyświetlanie, edytowanie i usuwanie jakiegoś zasobu, na przykład wpisów na blogu.
Zacznijmy od stworzenia kontrolera. Możemy do tego użyć komendy php artisan make:controller PostController
, która stworzy nowy plik w katalogu app/Http/Controllers
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
//
}
Dodajmy w kontrolerze metodę show()
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function show($id)
{
return 'Post: ' . $id;
}
}
Następnie zdefiniujmy ścieżkę:
// routes/web.php
Route::get('posts/{id}', 'PostController@show');
Po wejściu na adres /posts/1
zostanie wykonany i zwrócony kod w metodzie show()
naszego kontrolera. Parametry ze ścieżki zostaną przekazane jako parametry do metody w kontrolerze.
Warto zwrócić uwagę na to, że domyślnie Laravel szuka kontrolerów w przestrzeni nazw (ang. "namspace") App\Http\Controllers
. Dlatego przy definiowniu ścieżki możemy podać jako drugi parametr samą nazwę klasy kontrolera.
Obsługa formularzy
Stworzyliśmy kontroler i zdefiniowaliśmy pierwszą scieżkę, w której go używamy. Zajmijmy się teraz obsługą formularzy. Zdefiniujmy dwie nowe ścieżki:
// routes/web.php
Route::get('posts/create', 'PostController@create');
Route::post('posts', 'PostController@store');
Pierwsza ścieżka będzie odpowiedzialna za wyświetlenie formularza. Dodajmy zatem w naszym kontrolerze metodę create()
, której jedynym zadaniem będzie zwrócenie widoku, w którym zawiera się nasz formularz:
// app/Http/Controllers/PostController.php
public function create()
{
return view('posts.create');
}
Następnie stwórzmy widok:
// resources/views/posts/create.blade.php
<form action="/posts" method="POST">
@csrf
<input type="text" name="title">
<input type="submit" value="Zapisz">
</form>
Dodaliśmy formularz z jednym polem tekstowym o nazwie title
, który zostanie wysłany metodą POST na adres /posts
. Warto zwrócić uwagę na użycie dyrektywy @csrf
. Laravel ułatwie nam ochronę przed atakami CSRF (ang. "cross-site request forgery"). Czym jest atak CSRF? W dużym uproszczeniu: wyobraźmy sobie, że ktoś zmusi przeglądarkę użytkownika (na przykład poprzez wstrzyknięcie iframe) do wysłania złośliwego żądania HTTP w jego imieniu. Ktoś mógłby w ten sposób na przykład zmienić hasło zalogowanego na naszej stronie użytkownika. Dyrektywa Blade @csrf
dodaje do naszego formularza ukryte pole z wygenerowanym tokenem. Ten sam token jest utrzymywany w sesji. Przed przyjęciem żądania POST framework porównuje te tokeny. Jeśli w przesłanym formularzu brakuje tokenu lub nie zgadza się on z tokenem z sesji, żądanie zostaje zatrzymane.
Dodajmy teraz do naszego kontrolera metodę store()
:
// app/Http/Controllers/PostController.php
use App\Post;
use Illuminate\Http\Request;
public function store(Request $request)
{
Post::create([
'title' => $request->input('title'),
]);
return redirect('posts');
}
Metoda ta będzie odpowiadać na żądanie POST pod adres /posts
. Idea jest prosta, dodajemy w bazie danych nowy wpis używając metody Post::create()
a następnie przekierowujemy z powrotem na adres /posts
.
Dodaliśmy w metodzie store()
parametr $request
typu Illuminate\Http\Request
. Natomiast przy definiowaniu ścieżki nie podajemy instancji tej klasy. Nie musimy tego robić, dlatego że używamy tutaj mechanizmu wstrzykiwania zależności, która oferuje kontener Laravela. To brzmi skomplikowanie, ale w uproszczeniu oznacza to tyle, że framework wie jak stworzyć instancję klasy Illuminate\Http\Request
i robi to za nas.
Klasa Illuminate\Http\Request
zawiera informacje o parametrach żądania, GET, POST, sesji, ciasteczkach itp. Pod zmienną $request
mamy dostęp do instancji tej klasy i możemy się odwołac na przykład do metody $request->input('title')
, która zwraca wartość parametru formularza o nazwie title
. Inne przydatne metody klasy Request
dające dostęp do parametrów formularzy to all()
, która zwróci wszystkie parametry czy only()
, która zwraca tylko wybrane. Na przykład $request->only(['title', 'body'])
zwróci tablicę z tylko dwoma parametrami, title
oraz body
.
Kontrolery zasobów
Większość operacji w aplikacjach webowych opiera się na dodawaniu, wyświetlaniu, edytowaniu lub usuwaniu jakiegoś zasobu. W naszym kontrolerze mamy już zdefiniowane metody odpowiadające za dodawanie wpisów: create()
i store()
. Mamy metodę która wyświetla pojedynczy wpis: show()
. Przydałaby nam się też metoda służąca do wyświetlenia listy wszystkich wpisów, nazwijmy ją index()
. Żeby wykonać operację edycji wpisu, potrzebujemy dwóch kolejnych metod, jednej służącej do wyświetlania formularza edycji - edit()
oraz jednej służacej do aktualizowania wpisu - update()
. Ostatnią operacją jest usuwanie wpisu, do czego wystarczy jedna metoda - destroy()
.
Kontroler posiadający takie siedem metod nazywany jest kontrolerem zasobów (ang. "resource controller"). Te siedem metod pozwala wykonać pełny zestaw operacji CRUD (create, read, update, delete) na zasobie. W Laravelu możemy sobie łatwo wygenerować kontroler z wyżej wymienionymi metodami. Wystarczy do komendy php artisan make:controller
dodać flagę --resource
:
php artisan make:controller PostController --resource
Następnie dla każdej z metod powinniśmy zdefiniować ścieżkę:
Route::get('posts', 'PostsController@index');
Route::get('posts/create', 'PostsController@create');
Route::post('posts', 'PostsController@store');
Route::get('posts/{post}', 'PostsController@show');
Route::get('posts/{post}/edit', 'PostsController@edit');
Route::put('posts/{post}', 'PostsController@update'); // lub Route::patch('/posts/{post}', 'PostsController@update');
Route::delete('posts/{post}', 'PostsController@destroy');
Na szczęście, jeśli trzymamy się konwencji nazewnictwa metod w kontrolerze, możemy wszystkie powyższe linijki zastąpić jedną:
Route::resource('posts', 'PostController');
W tej części tutoriala dowiedzieliśmy się jak używać kontrolerów oraz jak obsługiwać formularze. Zahaczyliśmy też o temat kontrolerów zasobów. W następnej części nauczymy się walidować formularze.