LaravelTutorial: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Zeile 411: | Zeile 411: | ||
* Wir brauchen einen Handler für diese Route: | * Wir brauchen einen Handler für diese Route: | ||
web.php: | web.php: | ||
< | <syntaxhighlight lang="php"> | ||
Route:: | Route::get('/edit-note/{post}', [NoteController::class, 'showEditScreen']); | ||
</ | </syntaxhighlight> | ||
* Die Variable {post} wird verwendet, die dynamische Note-Id zu verarbeiten. | |||
* NoteController: | * NoteController: | ||
< | <syntaxhighlight lang="php"> | ||
public function | public function showEditScreen(Note $note){ | ||
return view('edit-note', ['note' => $note]); | |||
} | |||
</syntaxhighlight> | |||
* resources/view/edit-note.blade.php: | |||
<syntaxhighlight lang="html"> | |||
... | |||
<body> | |||
<h1>Edit Note</h1> | |||
<form action="/edit-note/{{$note->id}}" method="POST"> | |||
@csrf | |||
@method('PUT') | |||
</ | <input type="text" name="title" value="{{$note->title}}" placeholder="Title"> | ||
<textarea name="body" placeholder="Body">{{$note->body}} | |||
</textarea> | |||
<button>Save Changes</botton> | |||
</form> | |||
</body> | |||
... | |||
</syntaxhighlight> | |||
* Browser F5: Jetzt funktioniert die Anzeige der zu edierenden Notiz. |
Version vom 8. Oktober 2023, 18:13 Uhr
Links
- Inspiriert von https://www.youtube.com/watch?v=cDEVWbz2PpQ (englisch)
- ApplikationMitNginx
Zielsetzung
Es wird eine Webapplikation "Notes" gebaut, die folgende grundlegende Fähigkeiten hat:
- Registrierung mit Name, Email und Passwort. Speichern in einer Datenbank.
- Login mit Name und Passwort, Abgleich mit Datenbank
- Logout
- Erstellen einer Notiz mit Titel und Nachricht
- Anzeige aller Notizen des Benutzers
- Edieren der Notiz
- Löschen der Notiz
Voraussetzungen
- Visual Studio Code ist installiert, ebenso die Erweiterungen PHP, PHP Namespace Resolver, Laravel Blade Snippets
- Composer ist installiert.
Vorgehen
Erstellen des Projekts
PROJ=notes
BASE=/home/ws/php/$PROJ
mkdir -p $BASE
cd $BASE
composer create-project laravel/laravel .
- Damit wird ein Verzeichnis $BASE/notes erstellt, und mittels Composer das Grundgerüst der Applikation erstellt.
- Es steht dann das PHP-Script **artisan** zur Verfügung, mit dem Laravel-Kommandos gegeben werden können.
- Interessant ist auch die Datei .env, in der die Konfiguration der Applikation stattfindet.
Starten des Webservers
Es gibt einen eingebauten Webserver für die Entwicklung:
cd $BASE
./artisan serve
Die Applikation steht dann im Browser unter http://localhost:8000 zur Verfügung.
Modifizieren der Homepage
- Die erstellte Homepage steht in der Datei resources/views/welcome.blade.php
- Diese Datei öffnen und im Quelltext was ändern
- Im Browser F5 drücken, der geänderte Text wird sichtbar
Neue Homepage erstellen
- Neue Datei: resources/views/home.blade.php Wichtig: endet immer mit .blade.php
- Eintippen: ! Es erscheint ein Icon "Schraubenschlüssel" mit Titel !. Dieses anklicken. Damit wird ein HTML-Grundgerüst erstellt.
- Titel korigieren: <title>Notes</title>
- Im Body:
<h1>Test</h1>
- Speichern
- Datei routes/web.php
Route::get('/', function () { return view('welcome'); });
- Hier steht der Aufruf der Datei welcome.blade.php
- Wir ersetzen das durch unsere eigene Datei home.blade.php:
Route::get('/', function () { return view('home'); });
Das Registrier-Formular
- resources/views/home.blade.php
<div style="border: 3px solid black;"> <h2>Register</h2> <form action="/register" method="POST"> @csrf <input name="name" type="text" placeholder="name"> <input name="email" type="text" placeholder="email"> <input name="password" type="password" placeholder="password"> <button>Register</button> </form> </div>
- @csrf: Sicherheit: https://en.wikipedia.org/wiki/Cross-site_request_forgery
- /routes/web.php:
Route::post('/register', function() { return 'We have registered'; });
- Browser aktualisieren (F5)
UserController erstellen
- Die Behandlung des Formulars passiert in einem "Controller"
php artisan make:controller UserController
- Es entsteht die Datei app/Http/Controllers/UserController
- Wir erweitern die Klasse UserController um eine Methode register(), die die Registrierung vornimmt:
class UserController extends Controller { public function register(Request $request) { $incomingFields = $request->validate([ 'name' => ['required', 'min:3', 'max:10', Rule::unique('users', 'name')], 'email' => ['required', 'email', Rule::unique('users', 'email')], 'password' => 'required' ]); return 'Hello from UserController'; } }
- Die Methode bekommt den Parameter $request, der die HTML-Infos der Seite enthält.
- Der Aufruf von $request->validate() stellt Überprüfungen an:
- In dem assoziativen Feld werden die zu überprüfenden Felder mit den Validierungsregeln verknüpft:
- Das Feld "name" darf nicht leer sein ("required"), der Name muss mindestens 3 und darf maximal 10 Zeichen lang sein, der Name darf noch nicht in der DB in der Tabelle 'users' im Feld 'name' vorkommen.
- Damit PHP die Klasse Rules in der Datei UserController.php kennt: Doppelklick auf Rule (Auswählen), dann Alt-Ctr-I (Import Class). In der Liste Illuminate\validation\Rule auswählen.
- In der Datei routes/web.php:
Route::post('/register', [UserController::class, 'register']; });
- Mit der URL /register wird die Methode 'register' in der Klasse UserController aufgerufen.
- Damit PHP die Klasse UserController in der Datei web.php kennt: UserController doppelklicken (Auswählen): Rechte Maustaste: "Import Class" (oder Alt-Ctr-I). Es wird dann der Import erledigt.
- Browser mit F5 aktualisieren:
- Nichts eingeben, auf Button "Register" klicken: nichts passiert
- Alle 3 Felder ausfüllen und dann Button "Register" klicken: Fehlermeldung, dass Benutzer nicht angemeldet ist. Das ist so korrekt, die Validierung ist demnach korrekt durchlaufen.
Datenbank anlegen
- Mit mysql die Datenbank dbnotes mit Benutzer notes und Passwort 'TopSecret' anlegen, z.B. mit
sudo mysql mysql <<EOS CREATE DATABASE dbnotes; GRANT ALL ON dbnotes.* to 'notes'@'localhost' IDENTIFIED BY 'TopSecret'; EOS
- In der Datei .env:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=dbnotes
DB_USERNAME=notes
DB_PASSWORD='TopSecret'
Datenbank initialisieren
- Laravel hat schon einige DB-Elemente vorbereitet. Diese werden so aktiviert:
php artisan migrate
mysql -u notes -pTopSecret dbnotes <<EOS
show tables;
select * from users;
EOS
- Es werden die Tabellen failed_jobs migrations password_reset_tokens personal_access_tokens und users angelegt.
- Die Tabelle users ist leer.
Registrierung fertigstellen
- Änderung in app/Http/UserController.php:
public function register(Request $request) { $incomingFields = $request->validate([ 'name' => ['required', 'min:3', 'max:10', Rule::unique('users', 'name')], 'email' => ['required', 'email', Rule::unique('users', 'email')], 'password' => 'required' ]); $incomingFields['password'] = bcrypt($incomingFields['password']); $user = User::create($incomingFields); auth()->login($user); return redirect('/'); }
- "User::" doppelklicken, Alt-Ctrl-i importiert die Klasse App\Models\User
- Browser: F5, Felder ausfüllen, Button "Register"
mysql -u notes -pTopSecret dbnotes <<EOS
select * from users;
EOS
- Jetzt ist ein Datensatz in der Datenbank, der passende Benutzer
- Fülle das Formular nochmal mit anderen Daten aus, damit 2 Benutzer existieren.
Logout und Login
- In resources/home.blade.php:
<body> @auth <form action="/logout" method="POST"> @csrf <p>You are logged in!</p> <button>logout</button> </form> @else <div style="border: 3px solid black;"> <h2>Register</h2> <form action="/register" method="POST"> @csrf <input name="name" type="text" placeholder="name"> <input name="email" type="text" placeholder="email"> <input name="password" type="password" placeholder="password"> <button>Register</button> </form> </div> <div style="border: 3px solid black;"> <h2>Login</h2> <form action="/login" method="POST"> @csrf <input name="loginname" type="text" placeholder="name"> <input name="loginpassword" type="password" placeholder="password"> <button>Login</button> </form> </div> @endauth </body>
- Änderung in app/Http/UserController.php:
public function logout() { auth()->logout(); return redirect('/'); } public function login(Request $request) { $incomingFields = $request->validate([ 'loginname' => 'required', 'loginpassword' => 'required' ]); $incomingFields['loginpassword'] = bcrypt($incomingFields['loginpassword'] . $incomingFields['loginname']); if ( auth()->attempt([ 'name' => $incomingFields['loginname'], 'password' => $incomingFields['loginpassword'] ]) ) { $request->session()->regenerate(); } return redirect('/'); }
- Änderung in routes/web.php:
Route::post('/register', [UserController::class, 'register']); Route::post('/login', [UserController::class, 'login']); Route::post('/logout', [UserController::class, 'logout']);
- im Browser: F5 Felder für Login ausfüllen, Button "Login" -> "Your are logged in"
Tabelle für Notizen erstellen
php artisan make:migration create_notes_table
- Der Teil zwischen create_ und _table ist der Name der Tabelle, also "notes".
- Es wird eine Datei database/migrations/xxx_create_notes_table.php erzeugt: Diese edieren.
public function up(): void { Schema::create('notes', function (Blueprint $table) { $table->id(); $table->timestamps(); $table->string('title'); $table->longText('body'); $table->foreignId('user_id')->constrained(); }); }
- Es werden folgende Felder angelegt:
- 'id': der Primärschlüssel, erzeugt durch $table->id()
- 'changed_at' und 'updated_at', erzeugt durch $table->timestamps()
- 'title': ein Feld vom Typ VARCHAR(255)
- 'body': ein Feld vom Type LONGTEXT
- 'user_id': Ein Fremdschlüssel auf die Tabelle 'users' Feld 'id'
php artisan migrate
Modell Note erzeugen
- Ein Model ist eine Klasse, die eine DB-Tabelle verwaltet.
- Konvention: die Tabelle ist kleingeschrieben und in Mehrzahl. Die Klasse ist großgeschrieben und in Einzahl.
php artisan make:model Note
- Es entsteht die Datei app/Models/Note.php
class Note extends Model { use HasFactory; // editable fields: protected $fillable = ['title', 'body', 'user_id']; }
- in der Variable $fillable werden die Felder aufgeführt, die in Formularen vorkommen.
Model User mit Note verknüpfen
- Wir wollen nur Notizen anzeigen, die dem angemeldeten Benutzer gehören. Dazu ergänzen wir das von Laravel definierte Modul User
- Datei app/Models/User.php
public function usersNotes(){ // related Model: Note, field in users: user_id return $this->hasMany(Note::class, 'user_id'); }
- Klasse Note importieren (Doppelklick auf Note, Alt-Ctrl-I)
Formular Notiz erzeugen
- Datei resources/views/home.blade.php:
@auth <form action="/logout" method="POST"> @csrf <p>You are logged in!</p> <button>logout</button> </form> <div style="border: 3px solid black;"> <h2>Create a New Note</h2> <form action="/create-note" method="POST"> @csrf <input type="text" name="title" placeholder="note title"> <textarea type="text" name="body" placeholder="body content..."> </textarea> <button>Save Note</button> </form> @else
- Modell erstellen:
php artisan make:controller NoteController
- Es entsteht die Datei app/Http/controllers/NoteController
class NoteController extends Controller { public function createNote(Request $request) { $incomingFields = $request->validate([ 'title' => 'required', 'body' => 'required' ]); $incomingFields['title'] = strip_tags($incomingFields['title']); $incomingFields['body'] = strip_tags($incomingFields['body']); $incomingFields['user_id'] = auth()->id(); Note::create($incomingFields); return redirect('/'); } }
- Es findet eine Validierung der 2 Felder statt.
strip_tags($incomingFields['titles']);
dient der Sicherheit: Sonst kann durch Benutzereingaben Blödsinn gemacht werden.$incomingFields['user_id'] = auth()->id();
speichert die Id des angemeldeten Benutzers im Datensatz.- Klasse Note importieren: Note doppelklicken, Alt-Ctrl-I
- Datei routes/web.php:
route::post('/create-note', [NoteController::class, 'createNote']);
- Klasse NoteController importieren: Doppelklick auf NoteController, Alt-Ctrl-I
- Browser: F5
- Wenn nicht angemeldet: Anmelden
- Titel und Notiz eintragen, Button "Create Note"
- Im Terminal:
sudo mysql dbnotes <<EOS
select * from notes;
EOS
- Es wird ein Datensatz angezeigt.
Alle Notizen anzeigen
- Es sollen alle Notizen des angemeldeten Benutzers angezeigt werden.
- In resources/views/home.blade.php: Einfügen **nach** dem Formular für "Create Note":
<div style="border: 3px solid black;"> <h2>All Posts</h2> @csrf @foreach($notes as $note) <div style="background-color: lightgray; padding: 10px; margins: 10px;"> <h3>{{$note['title']}}</h3> {{$note['body']}} <p><a href="/edit-note/{{$note->id}}">Edit</a></p> <form action="/delete-note" method="POST"> @csrf @method('DELETE') <button>Delete</button> </form> </div> @endforeach </div>
- Mit der "Anotation" @foreach wird eine Schleife gemacht, mit der alle Datensätze unter dem Namen $note abgeliefert werden.
- Für jeden Datensatz wird ein Abschnitt gebaut, der Titel und Notiz anzeigt.
- in routes/web.php:
Route::get('/', function () { if (auth()->check()) { // $posts = Note::all(); // or: // $posts = Note::where('user_id', auth()->id()->get()); // or: $notes = auth()->user()->usersNotes()->latest()->get(); } return view('home', ['notes' => $notes]); });
- Wenn wir angemeldet sind (
auth()->check()
) holen wir alle Notizen des Benutzers aus der Datenbank und übergeben diese Liste der View "home":auth()->user()
liefert den aktuellen Benutzer.->usersNotes()
liefert alle Einträge des Benutzers in der Tabelle notes->latest()
sortiert so dass die jüngsten Notizen zuerst kommen->get()
liefert die Datensätze als Liste: latest() liefert einen Container.
- Im Browser: F5 Jetzt sollte die eine Notiz angezeigt werden. Noch eine Notiz erzeugen, es werden dann 2 angezeigt.
Edieren einer Notiz
- Die angezeigten Notizen enthalten einen Link auf eine Route /edit-note/<note_id>
- Wir brauchen einen Handler für diese Route:
web.php:
Route::get('/edit-note/{post}', [NoteController::class, 'showEditScreen']);
- Die Variable {post} wird verwendet, die dynamische Note-Id zu verarbeiten.
- NoteController:
public function showEditScreen(Note $note){
return view('edit-note', ['note' => $note]);
}
- resources/view/edit-note.blade.php:
...
<body>
<h1>Edit Note</h1>
<form action="/edit-note/{{$note->id}}" method="POST">
@csrf
@method('PUT')
<input type="text" name="title" value="{{$note->title}}" placeholder="Title">
<textarea name="body" placeholder="Body">{{$note->body}}
</textarea>
<button>Save Changes</botton>
</form>
</body>
...
- Browser F5: Jetzt funktioniert die Anzeige der zu edierenden Notiz.