Przykład aplikacji CRUD w Laravel 5

Zbudujemy aplikację we frameworku Laravel 5 – lista zadań do wykonania. Lista zadań użytkownika będzie zabezpieczona logowaniem. Aby zrozumieć poniższy kurs i uruchomić na swoim komputerze aplikację należy być obeznanym z następującymi zagadnieniami:

  • programowanie obiektowe PHP
  • wzorzec MVC
  • HTML i CSS
  • narzędzie zarządzania zależnościami programistycznymi Composer
  • podstawy konsoli Linux i/lub Windows
  • serwery lokalne (np. Vagrant box, Wamp, Apache na Debian, Xampp itp.)

Szczegóły poszczególnych zagadnień, jak na przykład opis systemu szablonowego Laravel, znajdują się w oficjalnej dokumentacji Laravel.

Instalacja

Zaczynamy od instalacji świeżej aplikacji startowej poleceniem Composer:

composer create-project --prefer-dist laravel/laravel sampleCrud

Następnie należy ustawić rekursywnie uprawnienia do zapisu dla folderów: storage oraz bootstrap/cache. Jeśli po wejściu na stronę startową uzyskamy napis „Laravel 5”, oznacza to, że instalacja przebiegła poprawnie.

Budowa bazy danych

Ustawiamy dane dostępu do bazy danych w pliku .env. (zmieniamy DB_DATABASE, DB_USERNAME, DB_PASSWORD na odpowiednie własne wartości).

Migracje

php artisan make:migration create_tasks_table --create=tasks

Opcja „–create=tasks” doda do tabeli pole „id” typu int oraz pola typu timestamp. Po wykonaniu powyższego polecenia stworzony zostanie plik z definicją tabeli „tasks” w folderze database/migrations. Dodajemy do funkcji up() następujące nowe kolumny tabeli tasks:

$table->integer('user_id')->index();
$table->string('name');

Następnie w konsoli wydajemy polecenie php artisan migrate co spowoduje utworzenie nowej tabeli w bazie danych (nie musimy tworzyć tabel ręcznie).

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

Seedery

Pora wypełnić tabele przykładowymi danymi. Do tego celu służą seedery.

php artisan make:seeder UsersTableSeeder

Powyższe polecenie utworzy plik UsersTableSeeder.php w folderze database/seeds. Uzupełniamy funkcję run() o następujący kod:

for($i=1;$i<=2;$i++)
{
 DB::table('users')->insert([
 'name' => str_random(10),
 'email' => 'email'.$i.'@gmail.com',
 'password' => bcrypt('secret'.$i),
 ]);
}

Stworzy to nam dwóch nowych użytkowników. Następnie odkomentowujemy w pliku database/seeds/DatabaseSeeder.php wiersz $this->call(UsersTableSeeder::class);, po czym w konsoli wydajemy polecenie php artisan db:seed, aby zapisać efekt w bazie danych. Jeśli jeszcze raz wywołamy powyższe polecenie, otrzymamy błąd o tym, że adres email już istnieje w bazie. Więc, aby całkowicie zresetować naszą bazę wydajemy w konsoli polecenie php artisan migrate:refresh --seed, co spowoduje skasowanie istniejących tabel, utworzenie ich od nowa i zapełnienie przykładowymi danymi.

Modele

php artisan make:model Task – polecenie konsoli tworzące plik modelu Task w folderze app. Uzupełniamy nasz model protected $fillable = ['name']; co spowoduje, że pole name w tabeli Users będzie zapisywalne poprzez wzorzec active record, którym posługuje się Laravel w celu interakcji z bazą danych. Dodajemy również protected $casts = ['user_id'=>'int']; , co zapewni rzutowanie pola tabeli user_id na typ int, co przyda się podczas autoryzowania użytkownika do podjęcia akcji usuwania zadania (id użytkownika musi być dokładnie równe polu user_id zadania do wykonania).

Pora na uzupełnienie relacji między tabelami bazy danych.

W modelu User dodajemy:

public function tasks() // użytkownik może mieć wiele zadań do zrobienia
{
return $this->hasMany(Task::class);
}

A w modelu Task dodajemy:

public function user() // każde zadanie należy do jednego użytkownika
 {
 return $this->belongsTo(User::class);
 }

Następnie tworzymy repozytorium odpowiedzialne za wykonywanie operacji na bazie danych. Utwórz folder app/Repositories, a w nim plik TaskRepository.php

namespace App\Repositories;

use App\User;
use App\Task;

class TaskRepository
{
    /**
     * Get all of the tasks for a given user.
     *
     * @param  User  $user
     * @return Collection
     */
    public function forUser(User $user)
    {
        return Task::where('user_id', $user->id)
                    ->orderBy('created_at', 'asc')
                    ->get();
    }
}

Wzorzec repozytorium jest szczególnie przydatny w dużych aplikacjach. Uzyskujemy separację kodu różnego przeznaczenia. Aplikacja jest łatwiejsza w modyfikacji.

Widoki

php artisan make:auth – polecenie Composer generuje za nas wiele widoków użytecznych m.in. podczas logowania oraz rejestracji użytkowników. Od tego momentu możemy zalogować się do aplikacji na konto jednego z dwóch utworzonych użytkowników, utworzonych wcześniej przez seeder. Oprócz tego, to polecenie konsoli dodaje nowy kontroler HomeController, dodaje do pliku routes.php obsługę routingu do logowania (linki login i register oraz linki do odzyskiwania hasła). Ponieważ po zalogowaniu będziemy chcieli zostać przekierowani do listy zadań użytkownika, musimy zmienić nieco wygenerowane pliki. W pliku app/Http/Controllers/Auth/AuthController.php zmieniamy właściwość $redirectTo na tasks. Podobnie zrobimy w pliku app/Http/Middleware/RedirectIfAuthenticated.php.

Sami musimy zdefiniować kolejne widoki aplikacji. Utworzymy folder tasks w app/resources/views. Utwórz tam plik index.blade.php i zapisz:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="col-sm-offset-2 col-sm-8">
            <div class="panel panel-default">
                <div class="panel-heading">
                    New Task
                </div>

                <div class="panel-body">
                    <!-- Display Validation Errors -->
                    @include('common.errors')

                    <!-- New Task Form -->
                    <form action="./task" method="POST" class="form-horizontal">
                        {{ csrf_field() }}

                        <!-- Task Name -->
                        <div class="form-group">
                            <label for="task-name" class="col-sm-3 control-label">Task</label>

                            <div class="col-sm-6">
                                <input type="text" name="name" id="task-name" class="form-control" value="{{ old('task') }}">
                            </div>
                        </div>

                        <!-- Add Task Button -->
                        <div class="form-group">
                            <div class="col-sm-offset-3 col-sm-6">
                                <button type="submit" class="btn btn-default">
                                    <i class="fa fa-btn fa-plus"></i>Add Task
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>

            <!-- Current Tasks -->
            @if (count($tasks) > 0)
                <div class="panel panel-default">
                    <div class="panel-heading">
                        Current Tasks
                    </div>

                    <div class="panel-body">
                        <table class="table table-striped task-table">
                            <thead>
                                <th>Task</th>
                                <th>&nbsp;</th>
                            </thead>
                            <tbody>
                                @foreach ($tasks as $task)
                                    <tr>
                                        <td class="table-text"><div>{{ $task->name }}</div></td>

                                        <!-- Task Delete Button -->
                                        <td>
                                            <form action="./task/{{ $task->id }}" method="POST">
                                                {{ csrf_field() }}
                                                {{ method_field('DELETE') }}

                                                <button type="submit" id="delete-task-{{ $task->id }}" class="btn btn-danger">
                                                    <i class="fa fa-btn fa-trash"></i>Delete
                                                </button>
                                            </form>
                                        </td>
                                    </tr>
                                @endforeach
                            </tbody>
                        </table>
                    </div>
                </div>
            @endif
        </div>
    </div>
@endsection

Pliki z nazwą blade.php są plikami systemu szablonowego Laravel 5. Występuje tu wiele przydatnych dyrektyw, spośród których najważniejsze są nawiasy klamrowe {{ }}, w których zapisujemy zmienną lub wynik funkcji do wyświetlenia. Następnie utwórz folder app/resources/views/common, a w nim plik errors.blade.php, w którym zapisz:

@if (count($errors) > 0)
 <!-- Form Error List -->
 <div class="alert alert-danger">
 <strong>Whoops! Something went wrong!</strong>

<br><br>

<ul>
 @foreach ($errors->all() as $error)
 <li>{{ $error }}</li>
 @endforeach
 </ul>
 </div>
 @endif

Będą tutaj wyświetlane komunikaty o błędach w przypadku błędów w formularzach aplikacji.

Kontrolery

Tworzymy kontroler php artisan make:controller TaskController

Uzupełniamy otrzymany kod, aby plik w folderze app/Http/Controllers wyglądał tak:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;

use App\Repositories\TaskRepository;

use App\Task;


class TaskController extends Controller
{
    public function __construct( TaskRepository $tasks )
    {
	$this->tasks = $tasks;
        $this->middleware('auth'); // to spowoduje, że każda akcja kontrolera będzie chroniona przed dostępem osób niezalogowanych do aplikacji
    }


    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|max:255',
        ]);   // w pliku widoku będą dostępne informacje o błędach: $errors->all()

        // Create The Task…
          $request->user()->tasks()->create([
            'name' => $request->name,
        ]);

        return redirect('/tasks');
    }


    public function index(Request $request)
    {
        //$tasks = Task::where('user_id', $request->user()->id)->get();

          return view('tasks.index', [
                'tasks' => $this->tasks->forUser($request->user()),
            ]);
    }


    public function destroy(Request $request, Task $task)
    {

        $this->authorize('destroy', $task); // jeśli id użytkownika jest równe polu user_id zadania do wykonania, zostanie wykonany dalszy kod czyli usunięcie zadania
        $task->delete();

        return redirect('/tasks');
    }
}

Nowe metody kontrolera musimy odnotować w pliku z routingiem:

 Route::get('/tasks', 'TaskController@index');
 Route::post('/task', 'TaskController@store');
 Route::delete('/task/{task}', 'TaskController@destroy');

Autoryzacja

Tworzymy kod odpowiedzialny za autoryzację użytkowników podczas kasowania zadania do wykonania (każdy użytkownik może skasować tylko swoje zadanie).

php artisan make:policy TaskPolicy

Polecenie powyższe utworzy plik app/Http/Policies/TaskPolicy.php. Zmień go aby wyglądał tak:

namespace App\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;

use App\Task;
use App\User;

class TaskPolicy
{
    use HandlesAuthorization;

    /**
     * Create a new policy instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    
    public function destroy(User $user, Task $task)
    {
        return $user->id === $task->user_id;
    }
}

W pliku app/Providers/AuthServiceProvider.php dodajemy do tablicy $policies element ‚App\Task’ => ‚App\Policies\TaskPolicy’

Dodatkowe ustawienia

W aplikacji wykorzystujemy mechanizm odzyskiwania zapomnianego hasła poprzez wysłanie wiadomości email. W tym celu musimy ustawić własne dane konta pocztowego znajdujące się w pliku .env. Do zmiany są wszystkie parametry rozpoczynające się od MAIL_. Konieczna jest również zmiana parametrów klucza tablicy ‚from’ w pliku config/mail.php. Dodatkowo, jeśli chcemy aby sesja zalogowanego użytkownika wygasała po zamknięciu przeglądarki, ustawiamy klucz ‚expire_on_close’ na wartość true w pliku config/session.php.

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 *