Laravel - das einfachste Tutorial der Welt - Teil 2

Laravel - das einfachste Tutorial der Welt - Teil 2

Im ersten Teil dieses Tutorials https://trancefish.de/blog/Laravel%20-%20das%20einfachste%20Tutorial%20der%20Welt%20-%20Teil%201/29 haben wir Laravel erfolgreich installiert, eine Datenbank und eine entsprechende Tabelle angelegt und tatsächlich auch diese Daten schon aus der Datenbank abgeholt. Im zweiten Teil werden wir Daten direkt über unsere Anwendung erfassen, verändern und auch löschen. Dabei lernen wir mehr über “Eloquent” von Laravel.

Wir haben bereits gelernt, dass Laravel für jede URL eine entsprechende Route in der Web.php benötigt. Was nicht drin steht, gibt es nicht. Logisch wäre also, wenn wir unsere Route ticket/new oder ticket/create nennen. Ich wäre für http://localhost:8000/ticket/create und daher öffnen wir wieder die routes/web.php und schreiben das rein.

Route::get('/termine/create', 'CalendarController@create');

Wir öffnen nun unseren Controller app/Http/Controllers/CalendarController.php und suchen die create()-Methode. Die schreiben wir nun um:

/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
    return view('create');
}

Anschließend erstellen wir das Blade-Template resources/views/create.blade.php, damit Laravel uns keinen Fehler schmeisst.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<form action="" method="post">
@csrf
</form>    
</body>
</html>

Aktuell macht dieses Formular gar nichts, es steht hier nur ein leeres Formular und in diesem Formular ist so eine komische @-Variable. @crsf ist ein Sicherheitsfeature und wird bei Wikipedia umfassend erklärt https://de.wikipedia.org/wiki/Cross-Site-Request-Forgery. Für uns ist interessant, dass Laravel ein Formular ohne CSRF-Token gar nicht verarbeitet.

Templates

Allerdings lassen wir das Formular gerade mal Formular sein und machen einen Ausflug in die Welt der Templates. Denn eine Sache ist schon jetzt klar. Es ist ziemlich dämlich, wenn ich jetzt bei jedem View ein Menü einbauen muss, habe ich irgendwann ein Problem, denn je nach Anzahl der Templates müsste ich ja immer wieder alle Views anpassen. Es muss doch möglich sein, ein Hauptlayout zu generieren?

Damals, als wir alle noch Spaghetticode schrieben, machten wir so was:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<?php include('contents') ?>
</body>
</html>

So ähnlich machen wir das noch immer, aber wir sind ja schlauer geworden. Wir erstellen nun ein ganz neues Template und nennen dieses Template layout.blade.php. Dieses Template enthält alle sich wiederholenden Elemente und lässt quasi den “Content” aussen vor. Da Laravel (5.x) das Bootstrap-CSS-Framework gleich mitliefert, können wir die Seite auch direkt hübsch machen.

Wir öffnen auch nochmal eben die web.php und stellen zumindest vorläufig ein, dass ein Aufruf von http://localhost:8000/ ohne weitere Parameter unsere Layout-Datei darstellt.

Route::get('/', function () {
    return view('layout');
});

Das macht es gerade einfacher, hier das Design zu testen. Ausserdem führen wir nun einmal folgendes aus, damit unser Projekt die node_modules bekommt, die wir für unser Projekt benötigen.

npm install
npm run dev

npm zieht sich unter anderem Bootstrap, jquery und vue. Vieles davon brauchen wir für unser Projekt aktuell gar nicht, schaden kann es aber auch nicht.

In unsere layout.blade.php schreiben wir das hier alles rein.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{{asset('css/app.css')}}">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <a class="navbar-brand" href="#">Terminplaner</a>
        <ul class="navbar-nav">
            <li class="nav-item">
                <a class="nav-link" href="{{url('/termine')}}">Termine</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="{{url('/termine/create')}}">Termin erstellen</a>
            </li>
        </ul>
    </nav>
    <div class="container">
        <h1>Mein Terminplaner</h1>
        <hr>
        Contents

    </div>
    <footer class="page-footer bg-dark text-info">
        <div class="container">
            Mein Terminplaner
        </div>
    </footer>
</body>

</html>

Die Layout-Datei sieht nun ein wenig komplexer aus. Nun ja, wir haben eigentlich nur ein Bootstrap-Menu, einen Footer und den Bereich, wo “Mein Terminplaner” steht und unten drunter “Contents”. Wenn wir diese Seite so jetzt aufrufen, sieht das ganze so aus:

So langsam wird es hübsch

Sections und yields

In dem Bereich der Seite, wo “Contents” steht, sollen unsere dynamischen Daten dargestellt werden. Also nehmen wir genau diesen Bereich und ersetzen das Wort contents durch eine Blade-Funktion:

<div class="container">
    <h1>Mein Terminplaner</h1>
    <hr>
    @yield('contents')
</div>

Jetzt öffnen wir unsere calendar.blade.php und entfernen alles ausserhalb von <body> und </body> und die <h1>Kalenderübersicht</h1> nehmen wir auch noch weg, sodass das Template nur noch so aussieht.

<div>
    <h2>Anstehende Termine für Heute</h2>
    <ul>
    @foreach ($termine as $termin)
        <li>{{$termin->termindatum}} - {{$termin->terminbeschreibung}}</li>
    @endforeach

    </ul>
</div>

Wir passen unser Template noch weiter an und sagen, dass dieses Template eine Erweiterung vom layout ist.

@extends('layout')

<div>
    <h2>Anstehende Termine für Heute</h2>
    <ul>
    @foreach ($termine as $termin)
        <li>{{$termin->termindatum}} - {{$termin->terminbeschreibung}}</li>
    @endforeach

    </ul>
</div>

Wir sagen Laravel nun, dass es doch bitte den Bereich zwischen <div> und </div> auch nutzen soll. Dieser Block soll dahin, wo wir im Layout den Content yielden

@extends('layout')

@section('content')
<div>
    <h2>Anstehende Termine für Heute</h2>
    <ul>
    @foreach ($termine as $termin)
        <li>{{$termin->termindatum}} - {{$termin->terminbeschreibung}}</li>
    @endforeach

    </ul>
</div>

@endsection

Wenn wir JETZT http://localhost:8000/termine aufrufen, lädt Laravel unsere neue calendar.blade.php, lädt parallel auch noch die layout.blade.php und fügt beides zusammen. Das Ergebnis kann sich sehen lassen:

Ein gestyltes Ding

Zurück zum Formular

Da wir jetzt ja ein hübsches Grundlayout haben, öffen wir nun noch einmal die create.blade.php und bauen diese um:

@extends('layout')

@section('content')
<form action="{{url('termine/create')}}" method="post">
    @csrf
    <div class="form-group">
        <label for="Kalenderdatum">Kalenderdatum</label>
        <input type="date" class="form-control" id="Kalenderdatum" name="Kalenderdatum">
    </div>
    <div class="form-group">
        <label for="Terminbeschreibung">Terminbeschreibung</label>
        <input type="text" class="form-control" id="Terminbeschreibung" name="Terminbeschreibung">
    </div>

    <button type="submit" class="btn btn-primary">Speichern</button>
</form>

@endsection

So. Wir haben ein total einfaches Formular. Wenn wir dieses Formular nun auslösen, gibt’s einen Fehler: the POST method is not supported for this route. Das bedeutet nur, dass die Route namens termine/create zwar existiert, aber eben leider noch nicht in web.php hinterlegt ist, sodass POST verarbeitet werden kann. Das machen wir also, indem wir die web.php nun erweitern.

Route::post('/termine/create', 'CalendarController@store');

Store-Methode (einfach. Ohne Prüfung)

Die einfachste Methode wäre nun, den Termin ungeprüft zu speichern. Wie das geht, schreibe ich hier jetzt hin, damit du das mal gesehen hast. Wir öffnen nun also den CalendarController und überarbeiten die store()-Methode

public function store(Request $request)
{
    $termine = new \App\Termine;
    $termine->terminbeschreibung = $request->Terminbeschreibung;
    $termine->termindatum = $request->Kalenderdatum;
    $termine->save();
    return \redirect('termine')->with('status','Gespeichert');
}

Was passiert hier genau? Wir erstellen eine Instanz der Klasse . Das ist ja unsere Terminliste. Wir schreiben dann in die Spalte “terminbeschreibung” den Wert aus dem Request $terminbeschreibung rein und natürlich übernehmen wir auch das Datum in $termindatum. Anschließend wird der Termin über die `$termine->save()`-Methode gepsichert und Laravel macht eine Umleitung auf die Termine-Seite. Mit einem Status.

Wenn Du alles Ordnungsgemäss ausgefüllt hast, sollte deine Terminliste nun ein wenig länger geworden sein. In Teil 3 des Tutorials werden wir uns mit Validieren befassen und was das mit dem Status da eigentlich soll.

Tags: laravel mysql tutorial coding

Kategorie: Laravel
Autor: Marcel Schindler
Datum: 14.06.2019

Blog weiter lesen