Laravel初心者が掲示板作る【Laravel 8.x】

https://manablog.org/laravel_bulletin_board/

こちらの記事を参考にしてLaravel初心者がつまづいた所をまとめてみる。

# バージョン

Laravel version
8.83.27

PHP version
7.4.33

MuSQL version
5.7.39

MAMP version
6.9

# 進捗


現在、
投稿記事を表示するためのコントローラーをつくっていく
の章の
投稿一覧の表示ページを作成する
でつまづいている。


## 2024.8.1

### Seederが動かない
```terminal:ターミナル
$XXX bbc % php artisan db:seed
Database seeding completed successfully.
```
とりあえず、`php artisan db:seed`も
`php artisan migrate`みたいに
マイグレーションファイルやシーダーファイルも
一括で読んでくれるものだと勘違い。
実際はデフォルトだと`DatabaseSeeder`クラスを実行するものだから、
`Database seeding completed successfully.`が表示されちゃった。
特定ファイルを実行したい場合は`--class`オプションを使う。


https://qiita.com/oouaioi/items/1cb5c79e16619e65a3a2


↓コマンド書き換えて実行
```terminal:ターミナル
$XXX bbc % php artisan db:seed --class=PostCommentSeeder

   Error 

  Class 'Seeder' not found

  at database/seeders/PostCommentSeeder.php:3
      1▕ <?php
      2▕ 
  ➜   3▕ class PostCommentSeeder extends Seeder{
      4▕ 
      5▕ public function run(){
      6▕ 	$content = 'この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。';
      7▕ 
      8▕ 	$commentdammy = 'コメントダミーです。ダミーコメントだよ。';
      9▕ 

  • A class import is missing: You have a missing class import. Try importing this class: `Illuminate\Database\Seeder`. 

      +2 vendor frames 
  3   [internal]:0
      Composer\Autoload\ClassLoader::loadClass("Database\Seeders\PostCommentSeeder")

  4   [internal]:0
      spl_autoload_call("Database\Seeders\PostCommentSeeder")
```
PostCommentSeeder.phpの`use`に`use Illuminate\Database\Seeder;`を
書いてないからエラー出てたみたい。
`use`は外部からファイルを呼び出してパスを省略して書ける便利な所。

https://nebikatsu.com/6719.html/

`Illuminate`はLaravelにデフォルトで備わってるクラスとメソッドが書いてある所。



```terminal:ターミナル
$XXX bbc % php artisan db:seed --class=PostCommentSeeder

   Illuminate\Database\QueryException 

  SQLSTATE[HY000]: General error: 1364 Field 'comment_count' doesn't have a default value (SQL: insert into `posts` (`title`, `content`, `cat_id`, `updated_at`, `created_at`) values (1 番目の投稿, この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。, 1, 2024-08-01 05:51:27, 2024-08-01 05:51:27))

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:712
    708▕         // If an exception occurs when attempting to run a query, we'll format the error
    709▕         // message to include the bindings with SQL, which will make this exception a
    710▕         // lot more helpful to the developer instead of just the database's errors.
    711▕         catch (Exception $e) {
  ➜ 712▕             throw new QueryException(
    713▕                 $query, $this->prepareBindings($bindings), $e
    714▕             );
    715▕         }
    716▕     }

      +12 vendor frames 
  13  database/seeders/PostCommentSeeder.php:19
      Illuminate\Database\Eloquent\Model::save()

      +22 vendor frames 
  36  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
```
Seederファイルというかマイグレーションファイルの方もミスってたらしい。


```php:2024_07_05_093838_create_posts_table.php
$table->bigInteger('comment_count')->unsigned()->default('0');
```

しばらく四苦八苦してデフォルト値0を設定して修正完了。
`php artisan migrate:fresh`を行う。
Seederファイルに戻ると、
```terminal:ターミナル
miki@chatlune-air3 bbc % php artisan db:seed --class=PostCommentSeeder

   Error 

  Class 'Database\Seeders\Comment' not found

  at database/seeders/PostCommentSeeder.php:23
     19▕ 		$post->save();
     20▕ 
     21▕ 		$maxComments = mt_rand(3, 15);
     22▕ 		for ($j=0; $j <= $maxComments; $j++) {
  ➜  23▕ 			$comment = new Comment;
     24▕ 			$comment->commenter = '名無しさん';
     25▕ 			$comment->comment = $commentdammy;
     26▕ 
     27▕ 			// モデル(Post.php)のCommentsメソッドを読み込み、post_idにデータを保存する

      +22 vendor frames 
  23  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
```
また似たようなエラーが……。
モデルの方のファイルが最初スペルミスっていたのと、
`namespace`や`use`を書いてない為と思われるエラーが次々出ました。
```php:Comment.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
```
`namespace`や`use`を記述。
Category.phpについても同じく記述しました。
ところで、VS Codeを使っているのですが、
`namespace`を書いてる時に`<?php`の前に改行を入れると赤くエラーが出ます。
しばらくそれでもつまづいたのですが、
エラーメッセージ的に「前になんか入れず、一番先に書けや」的なことなのかなと思います。

これでやっとSeederが動き出しました。

## 2024.8.2

### Viewが表示されない

Seederは動いたものの、
投稿一覧の表示ページが表示されない！

![スクリーンショット 2024-08-02 16.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850982/2c6f3d53-df26-8c51-a768-bcfb6b0ef12f.png)

index.blade.phpがエラー吐いてる。

```php:index.blade.php

@extends('layouts.default')
@section('content')

<div class="col-xs-8 col-xs-offset-2">

@foreach($posts as $post)

	<h2>タイトル：{{ $post->title }}
		<small>投稿日：{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
	</h2>
	<p>カテゴリー：{{ $post->category->name }}</p>
	<p>{{ $post->content }}</p>
	<p>{{ link_to("/bbc/ {$post->id} ", '続きを読む', array('class' => 'btn btn-primary') ) }}</p>
	<p>コメント数：{{ $post->comment_count }}</p>
@endforeach

</div>

@stop
```

どうやらここがエラー吐いてるらしい。

```php:index.blade.php エラー吐いてるところ
	<p>{{ link_to("/bbc/ {$post->id} ", '続きを読む', array('class' => 'btn btn-primary') ) }}</p>
```

そもそも`link_to`というのはrailsの書き方らしい。
Laravel Collectiveというものがあり、
Laravel公式が削除した機能をフォローする非公式パッケージで、
そこで使えたようなLaravel 5.xとかの古の技術らしい。
(ということはこの個人ブログ相当前のバージョンで書かれてるんだな……)


https://blog.motikan2010.com/entry/2017/01/28/%E3%80%8ELaravel_Collective%E3%80%8F%E3%81%A7%E3%81%AEHTML%E7%94%9F%E6%88%90%E3%82%92%E7%B0%A1%E5%8D%98%E3%81%AB%E3%81%BE%E3%81%A8%E3%82%81%E3%81%A6%E3%81%BF%E3%82%8B#%E3%83%AA%E3%83%B3%E3%82%AF

![スクリーンショット 2024-08-02 18.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850982/56038157-0b39-ca80-63c1-56fbf475e0a4.png)

ということで無事投稿一覧ページが表示された。

## 2024.8.5

### 各投稿についてのページを表示させていく

今、投稿一覧ページの「続きを読む」ボタンをクリックしても、
Not Found
The requested URL was not found on this server.
が出てしまう。

URLが
http://localhost/bbc1
みたいになっているのに気づく→blade側のURL指定ミス？

```php:index.blade.php
<a href="/bbc/{{$post->id}}"><button class="btn btn-primary">続きを読む</button></a>
```

`/bbc/{{$post->id}}`の`bbc`の後ろに/が入ってなかったことによるミスだった。
URLは直ったけど、まだNot Found。

```php:PostsController.php
    public function show($id)
    {
        $post = Post::find($id);
        Log::info("post",[$post]);
        return View::make('bbc.single')->with('post', $post);
    }
```
Logを仕込んでみると、Log取れてない……。
つまり、この関数が動いてないということ？

## 2024.8.6

### 続きを読むボタンが動かない

前回Logを取れていないことから、`show($id)`の関数が動いてないのではと推測。
bladeの続きを読むボタンのaタグで飛ばしているリンクが怪しいんじゃないか？

```php:index.blade.php
<a href="{{ bbc/$post->id }}"><button class="btn btn-primary">続きを読む</button></a>
```

このページを参照して以下のようにコードを書き換えてみる。

https://qiita.com/soehina/items/0e0d2cd927dbeb97a55f

```php:index.blade.php
<a href="{{route('bbc.show',['id' => $post->id])}}"><button class="btn btn-primary">続きを読む</button></a>
```

そうするとindexページを開いた時にMissing required parameter for...のエラーが！

https://qiita.com/mumucochimu/items/b5eb5e5a524f58393068

渡すパラメータの記述がうまく行っていない？
ここを参考に以下のように直す。

```php:index.blade.php
<a href="{{route('bbc.show', $post->id)}}"><button class="btn btn-primary">続きを読む</button></a>
```

そうするとエラーがなくなり、「続きを読む」ボタンが動いた！

## 2024.8.8

### 投稿機能を作成する

以下のファイルを新規作成すると、新規投稿ページができるらしいが……

```php:create.blade.php
@extends('layouts.default')
@section('content')

<div class="col-xs-8 col-xs-offset-2">

<h1>投稿ページ</h1>

{{-- 投稿完了時にフラッシュメッセージを表示 --}}
@if(Session::has('message'))
	<div class="bg-info">
		<p>{{ Session::get('message') }}</p>
	</div>
@endif

{{-- エラーメッセージの表示 --}}
@foreach($errors->all() as $message)
	<p class="bg-danger">{{ $message }}</p>
@endforeach

{{ Form::open(['route' => 'bbc.store'], array('class' => 'form')) }}

	<div class="form-group">
		<label for="title" class="">タイトル</label>
		<div class="">
			{{ Form::text('title', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<label for="cat_id" class="">カテゴリー</label>
		<div class="">
			<select name="cat_id" type="text" class="">
				<option></option>
				<option value="1" name="1">電化製品</option>
				<option value="2" name="2">食品</option>
			</select>
		</div>
	</div>

	<div class="form-group">
		<label for="content" class="">本文</label>
		<div class="">
			{{ Form::textarea('content', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>

{{ Form::close() }}

</div>

@stop
```

問題1
ControllerにViewを表示させるメソッドを書いてないからこのままだとViewが表示されない
→Controllerに記述を足す

問題2
前問題になったLaravel Collectiveの書き方であるFormファザードが入ってるので動かない
→htmlのタグのformタグで書き直す

### 問題1

```php:PostsController.php

    public function create()
    {
        return View::make('bbc.create');
    }

```
create関数に記述を書き足す。

### 問題2

formタグに書き直して、`{{ csrf_field() }}`のおまじないを添える

https://www.sejuku.net/blog/64093

https://html-coding.co.jp/annex/dictionary/html/form/

```php:create.blade.php
<form action="{{route('bbc.create')}}" method="POST" class="form-horizontal">
  {{ csrf_field() }}

	<div class="form-group">
		<label for="title" class="">タイトル</label>
		<div class="">
            <input type="text" name="title">
		</div>
	</div>

	<div class="form-group">
		<label for="cat_id" class="">カテゴリー</label>
		<div class="">
			<select name="cat_id" type="text" class="">
				<option></option>
				<option value="1" name="1">電化製品</option>
				<option value="2" name="2">食品</option>
			</select>
		</div>
	</div>

	<div class="form-group">
		<label for="content" class="">本文</label>
		<div class="">
            <textarea rows="6" name="content"></textarea>
		</div>
	</div>

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>

</form>
```

これで新規投稿ページが表示された！

## 2024.8.8

### 投稿できない

次は投稿フォームのバリデーションとDBへの保存機能作りだが……。

```php:PostsController.php
public function store()
{
	$rules = [
		'title' => 'required',
		'content'=>'required',
		'cat_id' => 'required',
	];

	$messages = array(
		'title.required' => 'タイトルを正しく入力してください。',
		'content.required' => '本文を正しく入力してください。',
		'cat_id.required' => 'カテゴリーを選択してください。',
	);

	$validator = Validator::make(Input::all(), $rules, $messages);

	if ($validator->passes()) {
		$post = new Post;
		$post->title = Input::get('title');
		$post->content = Input::get('content');
		$post->cat_id = Input::get('cat_id');
		$post->save();
		return Redirect::back()
			->with('message', '投稿が完了しました。');
	}else{
		return Redirect::back()
			->withErrors($validator)
			->withInput();
	}
}

```

上記を記述し、試しにバリデーションを機能させてみようと適当に投稿すると

![スクリーンショット 2024-08-09 15.23.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850982/50bdac1e-03aa-2244-f505-2686e60fc8bc.png)

エラーが出る。
このエラーはFormタグのaction要素の遷移先が間違ってたりすると出るぽい

https://qiita.com/annzu/items/e265833d264c4955c7d0

```php:create.blade.php
<form action="{{route('bbc.create')}}" method="POST" class="form-horizontal">
```

このルーティングに問題があるようなのだが……。
まだどうしたらいいのかわからない。

## 2024.8.19

### 新規投稿をちゃんと動作させる

```php:create.blade.php
<form action="{{route('bbc.create')}}" method="POST" class="form-horizontal">
```

ここのルーティングに問題がありそうなので、
PostsController.phpのstore関数の記述を一旦取って、

```php:create.blade.php
<form action="{{route('bbc.store')}}" method="POST" class="form-horizontal">
```

にしたら、前回のエラーは出なくなった。

store関数の記述を戻すと、
またエラーが出る！

https://django9102.amebaownd.com/posts/5672738/

でもこのページを見るに、actionの遷移先はstoreで合っていそう？
次回もう一度調べる。

## 2024.8.20

### バリデーションを動作させたい

どうもactionの遷移先はstoreで合っていそう。

>
> * create : 入力画面の生成とstoreへのデータの送信
> * store : 情報を受け取り保存（一覧へリダイレクト）
>

ビューでフォームに入力した情報を、storeメソッドで受け取る、
で認識が合ってそうなので、
create.blade.phpでフォームに入力するactionの遷移先はstoreだろう。
ということはstoreメソッドの中身が悪そう。

`Validator`ファザードと`Redirector`インスタンスについて
namespaceにuseの記述を足す。

```php:PostsController.php
use Illuminate\Support\Facades\Validator;
use Illuminate\Routing\Redirector;
```
また、`Validator::make()`の第一引数の書き方が違うので訂正。
元々`Input::all()`となっていたけど、これも昔のLaravelのバージョンに
Inputファサードがあったっぽい。

ちなみに`Validator::make()`の引数についてはこちらを参考にした。

https://qiita.com/oouaioi/items/b9011a8199290f154b87


```php:PostsController.php
$validator = Validator::make($request->all(), $rules, $messages);
```

更に、redirectについて、
`return`以降の書き方が違うみたいなので、書き直し。

```php:PostsController.php
return back()->with('message', '投稿が完了しました。');
}else{
return back()->withErrors($validator)->withInput();
}
```

ここまで書き直したらバリデーションが上手くいった！


## 2024.8.22

### 特定のカテゴリーに属する記事一覧が表示できるようにする

まず、元記事のようにindex.blade.phpとPostsController.phpを編集する。

```php:index.blade.php
<!-- <p>カテゴリー：{{ $post->category->name }}</p> -->
<p>{{ link_to("/category/{$post->category->id}", $post->category->name, array('class' => '')) }}</p>
```

```php:PostsController.php
public function showCategory($id)
{
	$category_posts = Post::where('cat_id', $id)->get();

	return View::make('category')
		->with('category_posts', $category_posts);
}
```

更にcategory.blade.phpを新規作成。

```php:category.blade.php
@extends('layouts.default')
@section('content')

<div class="col-xs-8 col-xs-offset-2">

@foreach($category_posts as $category_post)

	<h2>タイトル：{{ $category_post->title }}
		<small>投稿日：{{ date("Y年 m月 d日",strtotime($category_post->created_at)) }}</small>
	</h2>

	<p>{{ $category_post->content }}</p>

	<p>{{ link_to("/bbc/{$category_post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
	<p>コメント数：{{ $category_post->comment_count }}</p>
	<hr />
@endforeach

</div>

@stop
```

以前の例でlink_toは古いLaravelの書き方なので、bladeを以下のように書き換え。

```php:index.blade.php
<a href="/category/{{$post->category->id}}">{{$post->category->name}}</a>
```

```php:category.blade.php
<a href="/bbc/{{$category_post->id}}"><button class="btn btn-primary">続きを読む</button></a>
```

これで
http://localhost/public/bbc
のカテゴリーのリンクを押下すると

![スクリーンショット 2024-08-22 19.09.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850982/d8847eb9-3c61-6dee-6b79-9cfc30fcb0f5.png)

Not Foundになる。
showCategoryメソッド通ってない気がする。
Logを仕込んだら通っていない。

そもそも一覧ページにリンクするaタグの遷移先が違うのでは？と考えて、
href要素の中身を弄った。

```php:index.blade.php
<a href="{{route('bbc.category', $post->category->id)}}">{{$post->category->name}}</a>
```

それに伴って、ルーティングも弄ってみた。
```php:web.php
Route::get('bbc/category/{$id}',[PostsController::class, 'showCategory'])->name('bbc.category');
```

弄っているうちにエラーは出なくなったけど、まだ表示されない。
→ルーティングが間違っている？

`{$id}`の$を抜いたら動いた！
なんか抜く前は`show`メソッドに行ってたっぽい

```php:web.php
Route::get('bbc/category/{id}', [PostsController::class, 'showCategory'])->name('bbc.category');
```

## 2024.8.23

### コメント投稿機能を作る

新しくコメント投稿機能を作る。
まず、ビューから。

```php:single.blade.php

<h3>コメント一覧</h3>
@foreach($post->comments as $single_comment)
	<h4>{{ $single_comment->commenter }}</h4>
	<p>{{ $single_comment->comment }}</p><br />
@endforeach

<h3>コメントを投稿する</h3>
{{-- 投稿完了時にフラッシュメッセージを表示 --}}
@if(Session::has('message'))
	<div class="bg-info">
		<p>{{ Session::get('message') }}</p>
	</div>
@endif

{{-- エラーメッセージの表示 --}}
@foreach($errors->all() as $message)
	<p class="bg-danger">{{ $message }}</p>
@endforeach

{{ Form::open(['route' => 'comment.store'], array('class' => 'form')) }}

	<div class="form-group">
		<label for="commenter" class="">名前</label>
		<div class="">
			{{ Form::text('commenter', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<label for="comment" class="">コメント</label>
		<div class="">
			{{ Form::textarea('comment', null, array('class' => '')) }}
		</div>
	</div>

	{{ Form::hidden('post_id', $post->id) }}

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>


{{ Form::close() }}


</div>

@stop

```

その後、コントローラーを新規作成

```terminal
$ php artisan make:controller CommentsController
```

出来たコントローラーに以下を記述

```php:CommentsController.php
public function store()
{
	$rules = [
		'commenter' => 'required',
		'comment'=>'required',
	];

	$messages = array(
		'commenter.required' => 'タイトルを正しく入力してください。',
		'comment.required' => '本文を正しく入力してください。',
	);

	$validator = Validator::make(Input::all(), $rules, $messages);

	if ($validator->passes()) {
		$comment = new Comment;
		$comment->commenter = Input::get('commenter');
		$comment->comment = Input::get('comment');
		$comment->post_id = Input::get('post_id');
		$comment->save();
		return Redirect::back()
			->with('message', '投稿が完了しました。');
	}else{
		return Redirect::back()
			->withErrors($validator)
			->withInput();
	}
}
```

ルーティングを記載。

```php:web.php
Route::resource('comment', CommentsController::class);
```

single.blade.phpは、このままだとFormファザードの書き方で、エラーが出てしまうので、
以下のように書き換え。

```php:single.blade.php
<h3>コメントを投稿する</h3>
{{-- 投稿完了時にフラッシュメッセージを表示 --}}
@if(Session::has('message'))
	<div class="bg-info">
		<p>{{ Session::get('message') }}</p>
	</div>
@endif

{{-- エラーメッセージの表示 --}}
@foreach($errors->all() as $message)
	<p class="bg-danger">{{ $message }}</p>
@endforeach

<form action="{{route('comment.store')}}" method="POST" class="form">
  {{ csrf_field() }}

	<div class="form-group">
		<label for="commenter" class="">名前</label>
		<div class="">
			<input type="commenter" name="title">
		</div>
	</div>

	<div class="form-group">
		<label for="comment" class="">コメント</label>
		<div class="">
			<textarea rows="6" name="content"></textarea>
		</div>
	</div>

	<input type="hidden" name="post_id" value="{{$post->id}}">

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>

</form>


</div>

@stop
```

以上で、見かけはコメント投稿フォームが出来たが、
投稿するとエラーが出るのでまた次回対策する。

![スクリーンショット 2024-08-23 18.43.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850982/4accbd48-e71e-feac-d21b-df67775395ff.png)

## 2024.8.26

### コメント投稿機能が動かない

まず、web.phpにコントローラーの記述を足す。

```php:web.php
use App\Http\Controllers\CommentsController;
```

また、CommentsController.phpに各種useを足す。

```php:CommentsController.php
use App\Models\Comment;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Routing\Redirector;
```

ここらへんで、エラーは出ないのに、バリデーションが働いてコメントが投稿されなくなる。
$requestのログをとると、なんか変。

```php:laravel.log
[2024-08-26 09:01:06] local.INFO: request {"_token":"P7xnAf1P6CWDPh4ICSYI8rVhKpKDWNaZNUhFjIlu","title":"aaaa","content":"aaaa","post_id":"1"} 
```

コメントの$requestなのにtitleとcontentになってる。
single.blade.phpを修正。

```php:single.blade.php
	<div class="form-group">
		<label for="commenter" class="">名前</label>
		<div class="">
			<input type="text" name="commenter">
		</div>
	</div>

	<div class="form-group">
		<label for="comment" class="">コメント</label>
		<div class="">
			<textarea rows="6" name="comment"></textarea>
		</div>
	</div>
```

そうすると、`Input::`がエラー吐いてきた。
→書き換える。

```php:CommentsController.php
            $comment->commenter = $request->get('commenter');
            $comment->comment = $request->get('comment');
            $comment->post_id = $request->get('post_id');
```

これにて無事元ブログの指示する掲示板は完成！