Przykład aplikacji CRUD w Laravel 4

Framework Laravel jest narzędziem języka PHP zdobywającym coraz wiekszą popularność. Można go zainstalować na kilka sposobów. Jednym z nich jest pobranie szkieletu frameworka z repozytorium github. Następnie przy użyciu narzędzia do zarządzania zależnościami Composer instalujemy składniki Laravela: po pobraniu paczki z repozytorium uruchamiamy konsolę tekstową i przechodzimy w niej do folderu gdzie zainstalowany jest Laravel i wydajemy polecenie ‚php composer.phar install’ (plik composer.phar umieść w katalogu z frameworkiem) lub w Windowsie ‚composer install’. W przeglądarce nawigujemy do folderu ‚public’. Jeśli ukaże nam się strona jak poniżej, oznacza to, że instalacja przebiegła poprawnie. Jeśli nie, ustaw rekursywnie uprawnienia do zapisu dla folderu app/storage.

Zbudujemy przykładową aplikację – lista zadań do wykonania. Aplikacja będzie wyświetlać wszystkie utworzone zadania, będzie możliwość dodawania nowego zadania, podglądu poszczególnych zadań, edycji oraz usuwania istniejących. Ponadto będzie można zmieniać status istniejącego zadania na zrealizowane lub niezrealizowane.

1. Obsługa żądań użytkownika.

2. Utworzenie tabeli w bazie danych.

3. Utworzenie kontrolera sterującego.

4. Przygotowanie głównego szablonu.

5. Widoki aplikacji.

Obsługa żądań użytkownika


Główny sterownik naszej aplikacji znajduje się w pliku app/routes.php. Wpisujemy tutaj wszystkie możliwe zapytania użytkownika. W naszym przypadku plik będzie wyglądał tak:

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('/','SampleController@index'); 
Route::get('create','SampleController@create'); 
Route::post('store','SampleController@store'); 
Route::get('destroy/{id}','SampleController@destroy'); 
Route::get('show/{id}','SampleController@show'); 
Route::get('edit/{id}','SampleController@edit'); 
Route::post('update/{id}','SampleController@update'); 
Route::get('change-status/{id}','SampleController@changeStatus');

Usuń ze starego pliku zawartość i zapisz powyższy kod. Mamy tu osiem statycznych wywołań metod klasy Route (nie tak dosłownie statycznych z punktu widzenia języka PHP, tak naprawdę nie istnieją opisane metody w klasie Route, autor Laravela w ten sposób zaimplementował wzorzec projektowy jakim jest „service locator”, ale to wiedza dla zaawansowanych o czym innym razem). Każda metoda wywołana jest w zależności od akcji użytkownika. Metody nazywają się jak typy żądań użytkownika (w tym przypadku get i post) . Pierwszy parametr każdej z metod określa link, w jaki kliknął użytkownik. Przykładowo ‘/’ oznacza wczytanie strony głównej, ‘create’ oznacza wywołanie linku www.example.pl/create, ‘update/{id}’ oznacza wywołanie linku www.example.pl/update/x, gdzie x to pierwszy parametr metody kontrolera. W tym wypadku metodą jest ‘update’ kontrolera SampleController, co widać w drugim parametrze routingu. Jest on dwuczłonowy. Separatorem jest znak @, pierwszy człon to nazwa klasy kontrolera a drugi jest nazwą metody do wywołania. Znaczenia utworzonych żądań:

  • Create – wczytanie formularza w celu zapisania nowego zadania
  • Store – zapisanie nowego zadania
  • Destroy – usunięcie wybranego zadania
  • Show – wczytanie podstrony ze szczegółami konkretnego zadania
  • Edit – edycja zadania
  • Update – zapisanie zmian w istniejącym zadaniu
  • Change status – zmiana statusu zadania na wykonywane lub niewykonane

W skrócie Route::get('change-status/{id}','SampleController@changeStatus'); oznacza: jeśli użytkownik kliknął w link change-status/id, to wywołana zostanie metoda changeStatus() kontrolera SampleController z przekazanym jej parametrem id.

Zostań Profesjonalistą W Tworzeniu Aplikacji Webowych! Zapisz Się Na Kurs Laravel nauczysz się również tworzyć aplikacje hybrydowe na smartfony

Utworzenie tabeli w bazie danych dla aplikacji


Polecenie sql tworzące tabelę dla przykładowej aplikacji:

CREATE TABLE `to-do` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(50) NOT NULL,
 `content` text NOT NULL,
 `status` enum('Y','N') DEFAULT 'N',
 PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8

Utwórz tabelę i zapisz dane dostępowe do bazy danych MySQL w pliku app/config/database.php.

Utworzenie kontrolera sterującego naszą aplikacją


W tej przykładowej nieskomplikowanej aplikacji obejdzie się bez pliku modelu, wszystko zapiszemy w kontrolerze. Model utworzylibyśmy, gdy chcielibyśmy skorzystać ze sposobu komunikacji z bazą danych, jakim jest ‘eloquent orm’ , który upraszcza nam korzystanie z bazy danych. O tym może w następnym odcinku. Tutaj użyjemy standardowych zapytań SQL.

<?php

class SampleController extends \BaseController {

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index() {
        $tasks = DB::select('select * from `to-do`'); // pobieramy wszystkie zadania z tabeli

        return View::make('home')->with('tasks', $tasks); // tworzymy widok z dostępnymi danymi o wszystkich zadaniach
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create() {
        return View::make('task.create-task');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store() {

        $validator = Validator::make(
                        [
                    'task-name' => Input::get('task-name'),
                    'task-content' => Input::get('task-content')
                        ], [
                    'task-name' => 'required',
                    'task-content' => 'required'
                        ]
        );

        if ($validator->fails()) {
            return Redirect::back()->withInput()->withErrors($validator);
        }


        DB::insert('insert into `to-do` values (null,?,?,default)', [ Input::get('task-name'), Input::get('task-content')]);

        return Redirect::to('/');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id) {
        $task = DB::select('select * from `to-do` where id=? limit 1', [$id]); // polecenie przygotowane sql
        $task = $task[0];
        return View::make('task.show-task')->with('task', $task);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return Response
     */
    public function edit($id) {
        $task = DB::select('select * from `to-do` where id=?', [$id]);
        $task = $task[0];
        return View::make('task.edit-task')->with('task', $task);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     * @return Response
     */
    public function update($id) {
        $validator = Validator::make(
                        [
                    'task-name' => Input::get('task-name'),
                    'task-content' => Input::get('task-content')
                        ], [
                    'task-name' => 'required',
                    'task-content' => 'required'
                        ]
        );

        if ($validator->fails()) {
            return Redirect::back()->withInput()->withErrors($validator);
        }

        DB::update('update `to-do` set name = ?,content = ? where id=?', [Input::get('task-name'), Input::get('task-content'), $id]);

        return Redirect::to('/');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id) {
        DB::delete('delete from `to-do` where id=?', [$id]);
        return Redirect::to('/');
    }

    public function changeStatus($id) {
        $query = "update `to-do` set status = case when status = 'Y' then 'N' else 'Y' end where id=?";
        DB::update($query, [$id]);
        return Redirect::to('/');
    }

//end class
}

Zapisz powyższy kod w app/controllers/SampleController. php. Mamy tu osiem publicznych metod – dokładnie tyle ile zdefiniowanych jest w pliku z routingiem. Każda ma określoną już w punkcie 1 rolę. Spójrz na komentarze w kodzie a tutaj opiszemy metodę update: Tworzymy obiekt walidatora. Metoda tworząca obiekt walidatora przyjmuje dwa argumenty – dwie tablice, pierwsza zawiera nazwy oraz wartości walidowanych pól, druga – reguły walidacji dla podanych nazw. Konstrukcja Input::get('task-name') odpowiada konstrukcji $_POST[‘task-name’]. W drugiej tablicy słowo kluczowe ‘required’ oznacza, że dane pole jest wymagane. Następnie na utworzonym obiekcie walidatora wywołujemy metodę fails(), która sprawdza czy formularz przeszedł narzucone przez nas reguły walidacji. W tym przypadku sprawdza czy pola formularza o nazwach task-name i task-content nie są puste. Jeśli są niewypełnione następuje ponowne wczytanie formularza. W tym celu wywołujemy kilka metod klasy Redirect. Metoda withIput() spowoduje, że nasz formularz zapamięta wartości wpisane wcześniej przez użytkownika. Natomiast metoda withErrors() spowoduje, że w naszym widoku będzie dostępny obiekt $errors, przy pomocy którego wyświetlimy błędy walidacji. Gdy nie będzie błędów walidacji nastąpi aktualizacja tabeli w bazie danych. Wykorzystywany jest w tym celu mechanizm poleceń przygotowanych ( z ang. prepared statements), dzięki czemu nie musimy filtrować zmiennych, automatycznie otrzymujemy zabezpieczenie przed atakiem typu ‘sql injection’ ponieważ zmienne do zapytania SQL są podstawiane w momencie jego wykonywania a nie przed, dzięki czemu nie można zmienić pierwotnej konstrukcji zapytania SQL. Na końcu przekierowywujemy do strony głównej.

Przygotowanie głównego szablonu dla poszczególnych widoków naszej aplikacji


Zaczniemy od głównego pliku szablonu, który będzie punktem wyjścia dla wszystkich widoków. Oto przykładowy szablon:

<!DOCTYPE html>
<html lang="pl">
    <head>
        <meta charset="utf-8">
        <!--[if IE]>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <![endif]-->
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Basic Template</title>
        <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link href='http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic&subset=latin-ext' rel='stylesheet' type='text/css'>
        <style>
            body,html {
                font-family: 'Lora', serif;
                font-size: 20px;
                font-weight: 400;
                line-height: 1.5em;
            }
            .error {
                color: red;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <a href="{{URL::to('/')}}" class="pull-right">home</a>
            @yield('content')
        </div>
        <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
        <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
          <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
          <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
    </body>
</html>

Zwróć uwagę na konstrukcję @yield('content'). Jest to element systemu szablonowego we frameworku Laravel. W to miejsce będzie wstawiona dynamiczna treść naszej aplikacji. Szczegóły w dalszej części. Zwróć uwagę również na linijkę wyżej. Para podwójnych nawiasów klamrowych {{…}} jest podstawowym elementem systemu szablonowego w Laravel. Zastępuje ona konstrukcję <?php echo….;?>. Stwórz folder app/views/layouts i zapisz tam powyższy kod pod nazwą template.blade.php. Obecność słowa kluczowego ‘blade’ w nazwie szablonu informuje Laravel, że używasz jego systemu szablonów. Jeśli nie ma tego słowa kluczowego musisz używać zwykłych znaczników php. Możesz natomiast używać znaczników php obok języka szablonowego Laravel.

Widoki aplikacji


Strona startowa będzie wyświetlać listę zadań. Zapisz ją w pliku app/views/home.blade.php.

@extends('layouts.template')

@section('content')

<h1>Lista zadań <small><button type="button" class="btn btn-primary btn-sm" onclick="location.href = 'create'">Dodaj zadanie</button></small></h1>
<br />
<table class="table table-bordered table-hover">
    <tr>
        <th>Nazwa zadania</th>
        <th>Edycja</th>
        <th>Usuwanie</th>
        <th>Status</th>
    </tr>

    @foreach($tasks as $task)
    <tr>
        <td><a href="{{ URL::to('show') }}/{{ $task->id }}">{{{ $task->name }}} </a></td>
        <td><a href="edit/{{ $task->id }}">edytuj</a></td>
        <td><a href="destroy/{{ $task->id }}" onclick="return confirm('Na pewno?');">usuń</a></td>
        <?php
        if ($task->status == 'Y')
            $status = 'X';
        else
            $status = ' ';
        ?>
        <td><a href="change-status/{{$task->id}}">[ {{$status}} ]</a></td>
    </tr>
    @endforeach

</table>

@stop

@extends('layouts.template') oznacza, że naszym szablonem jest wcześniej utworzony plik template.blade.php. Zauważ zaletę – można tworzyć osobny template dla konkretnej podstrony (np. inna stopka na szczególnej podstronie). Kropka między słowem layaouts i template jest zamiennikiem ukośnika / . Czyli innymi słowy chodzi o plik template.blade.php zlokalizowany w folderze layouts. Pamiętasz zapis @yield('content') w pliku szablonu? W to miejsce będzie wklejone to co w pliku home.blade.php jest zlokalizowane między @section('content') a @stop. Mamy tutaj pętlę foreach, w której operujemy na obiekcie $tasks utworzonym w kontrolerze.

Pora na utworzenie poszczególnych widoków naszej aplikacji. Zaczniemy od widoku wyświetlającego formularz do dodania nowego zadania. Zapisz poniższy kod do pliku app/views/task/create-task.blade.php.

@extends('layouts.template')

@section('content')

<h1>Dodawanie nowego zadania</h1>
<br />

<form role="form" method="post" action="store">

    <div class="row">
        <div class="form-group col-xs-6">
            <label>Nazwa zadania</label> <span class="error">{{ $errors->first('task-name') }}</span>
            <input type="text" name="task-name" class="form-control">
        </div>
    </div>

    <div class="row">
        <div class="form-group col-xs-6">
            <label>Treść zadania</label><span class="error">{{ $errors->first('task-content') }}</span>
            <textarea name="task-content" class="form-control" rows="6"></textarea>
        </div>
    </div>

    <button type="submit" class="btn btn-default">Zapisz zadanie</button>
</form>

@stop

{{ $errors->first('task-name') }} odpowiada za wyświetlenie błędu, jeśli walidacja nie przebiegnie pomyślnie. Celem spolszczenia komunikatów o błędach należy utworzyć folder app/lang/pl, skopiować do niego zawartość folderu app/lang/en, następnie przetłumaczyć znajdujące się w poszczególnych plikach komunikaty błędów. Na koniec w pliku app/config/app.php należy ustawić wartość ‘locale’ na ‘pl’.
Pora na widok wyświetlający dane pojedynczego zadania:

@extends('layouts.template')

@section('content')

<h1>{{{ $task->name }}}</h1>
<p> {{{ $task->content }}}</p>

@stop

Zapisz powyższy kod jako app/views/task/show-task.blade.php.
Zwróć uwagę, że tym razem w konstrukcji {{{ $task->content }}} dodaliśmy trzy nawiasy klamrowe z każdej strony a nie dwa jak zwykle. Oznacza to, że dana wyświetlona w tym miejscu, będzie przefiltrowana na wypadek, gdyby ktoś zapisał do bazy kod javascript, co zabezpieczy nas przed potencjalnym atakiem typu xss.
I na końcu widok do edycji zadania, który jest prawie identyczny jak ten do utworzenia zadania. Jednak tym razem zapiszemy go jako osobny plik:

@extends('layouts.template')

@section('content')

<h1>Edycja zadania</h1>
<br />

<form role="form" method="post" action="{{ URL::to('update/'.$task->id) }} ">

    <div class="row">
        <div class="form-group col-xs-6">
            <label>Nazwa zadania</label><span class="error">{{ $errors->first('task-name') }}</span>
            <input type="text" name="task-name" class="form-control" value="{{{ $task->name }}}">
        </div>
    </div>

    <div class="row">
        <div class="form-group col-xs-6">
            <label>Treść zadania</label><span class="error">{{ $errors->first('task-content') }}</span>
            <textarea name="task-content" class="form-control" rows="6">{{{ $task->content }}}</textarea>
        </div>
    </div>

    <button type="submit" class="btn btn-default">Zapisz zadanie</button>
</form>

@stop

Zapisz powyższy kod jako app/views/task/edit-task.blade.php.
Nasz aplikacja – lista zadań, jest gotowa.

zapisz się na kurs Laravela >>>> lub program partnerski
Share

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *