Sfoglia il codice sorgente

Implement comments

Highlight: function comment() takes a Book and a Request argument and it behaves as expected

TODO: turn the comment section + comment form into a single include since it makes no sense to keep them apart
axkuhta 1 anno fa
parent
commit
008e036489

+ 23 - 1
app/Http/Controllers/AuthorController.php

@@ -17,7 +17,7 @@ class AuthorController extends Controller {
 	}
 
 	function view(Author $author) {
-		return view("author", ["author" => $author]);
+		return view("author", ["author" => $author->load(["books", "comments"])]);
 	}
 
 	function edit(Author $author) {
@@ -43,6 +43,28 @@ class AuthorController extends Controller {
 		return view("success");
 	}
 
+	function comment(Author $author, Request $request) {
+		$request->validate([
+			"name" => "required",
+			"email" => "required|email",
+			"content" => "required"
+		], [
+			"name" => "Укажите ваше имя.",
+			"email" => "Укажите ваш email.",
+			"content" => "Введите комментарий."
+		]);
+
+		$arr = $request;
+
+		$author->comments()->create([
+			"name" => $arr->name,
+			"email" => $arr->email,
+			"content" => $arr->content
+		]);
+
+		return view("success");
+	}
+
 	function drop(Author $author) {
 		$author->delete();
 		return view("success");

+ 23 - 1
app/Http/Controllers/BookController.php

@@ -23,7 +23,7 @@ class BookController extends Controller {
 	}
 
 	function view(Book $book) {
-		return view("book", ["book" => $book]);
+		return view("book", ["book" => $book->load(["author", "comments"])]);
 	}
 
 	function edit(Book $book) {
@@ -58,6 +58,28 @@ class BookController extends Controller {
 		return view("success");
 	}
 
+	function comment(Book $book, Request $request) {
+		$request->validate([
+			"name" => "required",
+			"email" => "required|email",
+			"content" => "required"
+		], [
+			"name" => "Укажите ваше имя.",
+			"email" => "Укажите ваш email.",
+			"content" => "Введите комментарий."
+		]);
+
+		$arr = $request;
+
+		$book->comments()->create([
+			"name" => $arr->name,
+			"email" => $arr->email,
+			"content" => $arr->content
+		]);
+
+		return view("success");
+	}
+
 	function drop(Book $book) {
 		$book->delete();
 		return view("success");

+ 4 - 0
app/Models/Author.php

@@ -9,4 +9,8 @@ class Author extends Model
 	function books() {
 		return $this->hasMany(Book::class);
 	}
+
+	function comments() {
+		return $this->morphMany(Comment::class, "commentable");
+	}
 }

+ 4 - 0
app/Models/Book.php

@@ -9,4 +9,8 @@ class Book extends Model
 	function author() {
 		return $this->belongsTo(Author::class);
 	}
+
+	function comments() {
+		return $this->morphMany(Comment::class, "commentable");
+	}
 }

+ 15 - 0
app/Models/Comment.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Comment extends Model
+{
+	// Наличие fillable требуется только при использовании mass assignment, т.е. создание записи из ассоциативного массива
+	protected $fillable = [
+		"name",
+		"email",
+		"content"
+	];
+}

+ 31 - 0
database/migrations/2023_11_28_191724_create_comments_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('comments', function (Blueprint $table) {
+            $table->id();
+            $table->timestamps();
+            $table->string("name");
+            $table->string("email");
+            $table->text("content");
+            $table->morphs("commentable");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('comments');
+    }
+};

+ 8 - 0
resources/views/author.blade.php

@@ -28,4 +28,12 @@
 	@endforeach
 	</table>
 </p>
+<p>
+<div>Добавить комментарий:</div>
+@include("include.comment_form", ["comment_form_target" => "/author/$author->id/comment"])
+</p>
+<p>
+<h3>Комментарии:</h3>
+@include("include.comments", ["comments" => $author->comments])
+</p>
 @endsection

+ 8 - 0
resources/views/book.blade.php

@@ -32,4 +32,12 @@
 <p>
 <a href="/book/{{ $book->id }}/edit">Редактировать</a> | <a href="/book/{{ $book->id }}/delete">Удалить</a>
 </p>
+<p>
+<div>Добавить комментарий:</div>
+@include("include.comment_form", ["comment_form_target" => "/book/$book->id/comment"])
+</p>
+<p>
+<h3>Комментарии:</h3>
+@include("include.comments", ["comments" => $book->comments])
+</p>
 @endsection

+ 35 - 0
resources/views/include/comment_form.blade.php

@@ -0,0 +1,35 @@
+<form method="POST" action="{{ $comment_form_target }}">
+	@csrf
+
+	<div>
+		<label>
+			<div>Ваше имя:</div>
+			<input type="text" name="name" placeholder="Ваше имя..." value="{{ old("name") }}">
+			@error("name")
+				<span class="alert">{{ $message }}</span>
+			@enderror
+		</label>
+	</div>
+
+	<div>
+		<label>
+			<div>Ваше имя:</div>
+			<input type="email" name="email" placeholder="Ваш email..." value="{{ old("email") }}">
+			@error("email")
+				<span class="alert">{{ $message }}</span>
+			@enderror
+		</label>
+	</div>
+
+	<div>
+		<label>
+			<div>Комментарий:</div>
+			<textarea name="content" placeholder="Комментарий...">{{ old("comment") }}</textarea>
+			@error("comment")
+				<span class="alert">{{ $message }}</span>
+			@enderror
+		</label>
+	</div>
+
+	<input type="submit">
+</form>

+ 6 - 0
resources/views/include/comments.blade.php

@@ -0,0 +1,6 @@
+@foreach ($comments as $row)
+	<p>
+		<div>{{ $row->name }} ({{ $row->created_at }}):</div>
+		<div>{{ $row->content }}</div>
+	</p>
+@endforeach

+ 2 - 0
routes/web.php

@@ -25,6 +25,7 @@ Route::get('/book/{book}', [Controllers\BookController::class, 'view']);
 Route::get('/book/{book}/delete', [Controllers\BookController::class, 'drop']);
 Route::get('/book/{book}/edit', [Controllers\BookController::class, 'edit']);
 Route::post('/book/{book}/edit', [Controllers\BookController::class, 'store']);
+Route::post('/book/{book}/comment', [Controllers\BookController::class, 'comment']);
 Route::post('/book/add', [Controllers\BookController::class, 'store']);
 
 // Авторы
@@ -34,4 +35,5 @@ Route::get('/author/{author}', [Controllers\AuthorController::class, 'view']);
 Route::get('/author/{author}/delete', [Controllers\AuthorController::class, 'drop']);
 Route::get('/author/{author}/edit', [Controllers\AuthorController::class, 'edit']);
 Route::post('/author/{author}/edit', [Controllers\AuthorController::class, 'store']);
+Route::post('/author/{author}/comment', [Controllers\AuthorController::class, 'comment']);
 Route::post('/author/add', [Controllers\AuthorController::class, 'store']);