こちらの記事を参考にしてLaravel初心者がつまづいた所をまとめてみる。
バージョン
Laravel version
8.83.27
PHP version
7.4.33
MuSQL version
5.7.39
MAMP version
6.9
進捗
現在、
投稿記事を表示するためのコントローラーをつくっていく
の章の
投稿一覧の表示ページを作成する
でつまづいている。
2024.8.1
Seederが動かない
$XXX bbc % php artisan db:seed
Database seeding completed successfully.
とりあえず、php artisan db:seed
も
php artisan migrate
みたいに
マイグレーションファイルやシーダーファイルも
一括で読んでくれるものだと勘違い。
実際はデフォルトだとDatabaseSeeder
クラスを実行するものだから、
Database seeding completed successfully.
が表示されちゃった。
特定ファイルを実行したい場合は--class
オプションを使う。
↓コマンド書き換えて実行
$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
は外部からファイルを呼び出してパスを省略して書ける便利な所。
Illuminate
はLaravelにデフォルトで備わってるクラスとメソッドが書いてある所。
$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ファイルというかマイグレーションファイルの方もミスってたらしい。
$table->bigInteger('comment_count')->unsigned()->default('0');
しばらく四苦八苦してデフォルト値0を設定して修正完了。
php artisan migrate:fresh
を行う。
Seederファイルに戻ると、
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
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は動いたものの、
投稿一覧の表示ページが表示されない!
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
どうやらここがエラー吐いてるらしい。
<p>{{ link_to("/bbc/ {$post->id} ", '続きを読む', array('class' => 'btn btn-primary') ) }}</p>
そもそもlink_to
というのはrailsの書き方らしい。
Laravel Collectiveというものがあり、
Laravel公式が削除した機能をフォローする非公式パッケージで、
そこで使えたようなLaravel 5.xとかの古の技術らしい。
(ということはこの個人ブログ相当前のバージョンで書かれてるんだな……)
ということで無事投稿一覧ページが表示された。
2024.8.5
各投稿についてのページを表示させていく
今、投稿一覧ページの「続きを読む」ボタンをクリックしても、
Not Found
The requested URL was not found on this server.
が出てしまう。
URLが
http://localhost/bbc1
みたいになっているのに気づく→blade側のURL指定ミス?
<a href="/bbc/{{$post->id}}"><button class="btn btn-primary">続きを読む</button></a>
/bbc/{{$post->id}}
のbbc
の後ろに/が入ってなかったことによるミスだった。
URLは直ったけど、まだNot Found。
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タグで飛ばしているリンクが怪しいんじゃないか?
<a href="{{ bbc/$post->id }}"><button class="btn btn-primary">続きを読む</button></a>
このページを参照して以下のようにコードを書き換えてみる。
<a href="{{route('bbc.show',['id' => $post->id])}}"><button class="btn btn-primary">続きを読む</button></a>
そうするとindexページを開いた時にMissing required parameter for...のエラーが!
渡すパラメータの記述がうまく行っていない?
ここを参考に以下のように直す。
<a href="{{route('bbc.show', $post->id)}}"><button class="btn btn-primary">続きを読む</button></a>
そうするとエラーがなくなり、「続きを読む」ボタンが動いた!
2024.8.8
投稿機能を作成する
以下のファイルを新規作成すると、新規投稿ページができるらしいが……
@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
public function create()
{
return View::make('bbc.create');
}
create関数に記述を書き足す。
問題2
formタグに書き直して、{{ csrf_field() }}
のおまじないを添える
<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への保存機能作りだが……。
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();
}
}
上記を記述し、試しにバリデーションを機能させてみようと適当に投稿すると
エラーが出る。
このエラーはFormタグのaction要素の遷移先が間違ってたりすると出るぽい
<form action="{{route('bbc.create')}}" method="POST" class="form-horizontal">
このルーティングに問題があるようなのだが……。
まだどうしたらいいのかわからない。
2024.8.19
新規投稿をちゃんと動作させる
<form action="{{route('bbc.create')}}" method="POST" class="form-horizontal">
ここのルーティングに問題がありそうなので、
PostsController.phpのstore関数の記述を一旦取って、
<form action="{{route('bbc.store')}}" method="POST" class="form-horizontal">
にしたら、前回のエラーは出なくなった。
store関数の記述を戻すと、
またエラーが出る!
でもこのページを見るに、actionの遷移先はstoreで合っていそう?
次回もう一度調べる。
2024.8.20
バリデーションを動作させたい
どうもactionの遷移先はstoreで合っていそう。
- create : 入力画面の生成とstoreへのデータの送信
- store : 情報を受け取り保存(一覧へリダイレクト)
ビューでフォームに入力した情報を、storeメソッドで受け取る、
で認識が合ってそうなので、
create.blade.phpでフォームに入力するactionの遷移先はstoreだろう。
ということはstoreメソッドの中身が悪そう。
Validator
ファザードとRedirector
インスタンスについて
namespaceにuseの記述を足す。
use Illuminate\Support\Facades\Validator;
use Illuminate\Routing\Redirector;
また、Validator::make()
の第一引数の書き方が違うので訂正。
元々Input::all()
となっていたけど、これも昔のLaravelのバージョンに
Inputファサードがあったっぽい。
ちなみにValidator::make()
の引数についてはこちらを参考にした。
$validator = Validator::make($request->all(), $rules, $messages);
更に、redirectについて、
return
以降の書き方が違うみたいなので、書き直し。
return back()->with('message', '投稿が完了しました。');
}else{
return back()->withErrors($validator)->withInput();
}
ここまで書き直したらバリデーションが上手くいった!
2024.8.22
特定のカテゴリーに属する記事一覧が表示できるようにする
まず、元記事のようにindex.blade.phpとPostsController.phpを編集する。
<!-- <p>カテゴリー:{{ $post->category->name }}</p> -->
<p>{{ link_to("/category/{$post->category->id}", $post->category->name, array('class' => '')) }}</p>
public function showCategory($id)
{
$category_posts = Post::where('cat_id', $id)->get();
return View::make('category')
->with('category_posts', $category_posts);
}
更に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を以下のように書き換え。
<a href="/category/{{$post->category->id}}">{{$post->category->name}}</a>
<a href="/bbc/{{$category_post->id}}"><button class="btn btn-primary">続きを読む</button></a>
これで
http://localhost/public/bbc
のカテゴリーのリンクを押下すると
Not Foundになる。
showCategoryメソッド通ってない気がする。
Logを仕込んだら通っていない。
そもそも一覧ページにリンクするaタグの遷移先が違うのでは?と考えて、
href要素の中身を弄った。
<a href="{{route('bbc.category', $post->category->id)}}">{{$post->category->name}}</a>
それに伴って、ルーティングも弄ってみた。
Route::get('bbc/category/{$id}',[PostsController::class, 'showCategory'])->name('bbc.category');
弄っているうちにエラーは出なくなったけど、まだ表示されない。
→ルーティングが間違っている?
{$id}
の$を抜いたら動いた!
なんか抜く前はshow
メソッドに行ってたっぽい
Route::get('bbc/category/{id}', [PostsController::class, 'showCategory'])->name('bbc.category');
2024.8.23
コメント投稿機能を作る
新しくコメント投稿機能を作る。
まず、ビューから。
<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
その後、コントローラーを新規作成
$ php artisan make:controller CommentsController
出来たコントローラーに以下を記述
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();
}
}
ルーティングを記載。
Route::resource('comment', CommentsController::class);
single.blade.phpは、このままだとFormファザードの書き方で、エラーが出てしまうので、
以下のように書き換え。
<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.8.26
コメント投稿機能が動かない
まず、web.phpにコントローラーの記述を足す。
use App\Http\Controllers\CommentsController;
また、CommentsController.phpに各種useを足す。
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のログをとると、なんか変。
[2024-08-26 09:01:06] local.INFO: request {"_token":"P7xnAf1P6CWDPh4ICSYI8rVhKpKDWNaZNUhFjIlu","title":"aaaa","content":"aaaa","post_id":"1"}
コメントの$requestなのにtitleとcontentになってる。
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::
がエラー吐いてきた。
→書き換える。
$comment->commenter = $request->get('commenter');
$comment->comment = $request->get('comment');
$comment->post_id = $request->get('post_id');
これにて無事元ブログの指示する掲示板は完成!