Laravel学習中の者です。
実際にアプリを作りながら習得していくことを目的として、
ファン交流サイトを作ってみます。
ER図
未作成
前提
このプログラムは下記環境で作成しています。
- MacOS
- ターミナル
- composer
- php7.3以上
- MySQL
が必要になります。
composerのインストール
composerがインストールされていない場合、インストールが必要です。
▼インストールはこちらから(公式ページ)
https://getcomposer.org/doc/00-intro.md
公式だと難しいと思う方は「Mac composer インストール」で検索すると、インストール記事が見つかります。
ターミナルを開いて
composer --version
を実行してバージョン情報が表示されればOK。
php7.3 and MySQL
MacにphpとMySQLをインストールするにはMAMPが最も簡単です。
MAMPはMac用のアプリで、PHP, MySQL, Apacheといった開発に必要なサーバー側のソフトウェアを一発でインストールできるスグレモノです。
Laravel8はPHP7.3以上でないと動かないのでPHPは7.3以上をインストールする必要があります。
MAMPをMacにインストールしたらターミナルから php -v を実行してPHPのバージョンを確認します。
php -v
PHP 7.4.25 (cli) (built: Oct 23 2021 15:38:15) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.25, Copyright (c), by Zend Technologies
基本設定
composerでプロジェクトを作成する
それでは1からファン交流サイトを作っていきます!
ホームディレクトリ直下に新規ディレクトリを作って移動します。
cd ~
mkdir program
cd program
以下のcomposerコマンドを実行します。
Laravelのバージョンは8.*の最新
プロジェクト名はfan_siteとしました。
composer create-project laravel/laravel=8.* fan_site
composerでプロジェクトが作成されたら、作成されたディレクトリでcomposer installを行いましょう。
cd fan_site
composer install
ロケールをJPにする
VScodeなどのエディタでconfig/app.phpファイルを変更します。
例:
vi config/app.php
70行目近辺
'timezone' => 'Asia/Tokyo',
83行目近辺
'locale' => 'ja',
↑この設定をすることでエラーメッセージなどが日本語に切り替わります。
109行目近辺
'faker_locale' => 'ja_JP',
↑この設定をするとテスト用データを作成するときに人の名前を日本人っぽい名前にしてくれます。
MySQLでデータベースを作成する
データベースはMySQLを使用します。
MySQLにコマンドラインでログインしてユーザーとデータベースを作成します。
MySQLに「fan_site」という名前のユーザーを作成し、fan_siteユーザーがアクセス出来る「fan_site」データベースを作成します。
使用するデータベースの作成方法はご自分の好みの方法で構いませんが、
ここではMAMPのphpMyAdminを使用していきます。
MAMPのユーザアカウント機能を使って、ユーザーとデータベースを一括で作成してしまいましょう。
入力項目は下記の通り。
ユーザ名 fan_site
ホスト名 localhost
[パスワードを生成する] ボタンをクリック(生成されたパスワードはどこかにメモしておく)
同名のデータベースを作成してすべての権限を与える。にチェックを入れる
一番下にある[実行] ボタンをクリックします。
.envを設定
.envファイルとはプロジェクトで使用する設定定義ファイルです。秘匿にすべきパスワード情報なども入っています。取り扱い要注意です。
cp -p .env.example .env
上記を実行して.envを用意します。
以下の設定は例です。ご自分のMySQLに合わせて設定を行ってください。
変更箇所のみ抜粋
APP_NAME=ファン交流サイト
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=fan_site
DB_USERNAME=fan_site
DB_PASSWORD=#mypassword#
key generate と laravel/uiのインストール
Laravel8の認証機能を使うために以下のコマンドを実行します。
php artisan key:generate
composer require laravel/ui
composer install
php artisan ui vue --auth
試しに migration してみる
基本的なデータベース設定が済んだところでちゃんと接続できるか試してみましょう。
以下のコマンドを実行します。
php artisan migrate
すると、私の場合はこんなエラーが出ました。
エラーメッセージで検索して、こちらの記事を参考に進めたところ解消できました。
https://qiita.com/mineaki27th/items/5effcc2605fe90ff6997
修正した箇所
①.env
DB_PASSWORD="パスワード" ←ダブルクォーテーションでパスワードを囲む
②database.php
mysqlのunix_socketの箇所を下記に変更
'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',
③キャッシュクリア
$ php artisan config:cache
$ php artisan cache:clear
その上で再度以下のコマンドを実行します。
php artisan migrate
今度は成功しました!
phpMyAdminを見てみると、usersテーブル等が作成されています。
データベースアクセスクラスの用意
artisan make:modelコマンドで、データベースにアクセスする用のクラスを作成していきます。
まずはPostsテーブルを作成
php artisan make:model Post --migration
成功すると以下のような表示になります。
php artisan make:model Post --migration
Model created successfully.
Created Migration: 2021_11_24_020205_create_posts_table
php artisan make:model Role --migrationを実行したときに以下のファイルが作られます。
database/migrations/#YYYY_MM_DD_NNNN#_create_posts_table.php
app/Models/Post.php
YYYY_MM_DD_NNNN#_create_posts_table.phpは、投稿テーブルpostsの定義ファイルです。
Post.phpはpostsテーブルにアクセスするためのEloquentモデルクラスファイルです。
EloquentとはLaravelのデータベースアクセスクラスです。
EloquentとはLaravelの一部で、データベースにアクセスする機能がまとまっているファイルです。データベースの1テーブルに対して1つのファイルを作ります。
postsテーブルの定義
マイグレーションファイルはartisanコマンドで作った直後にはidとtimestampsカラムしかありません。
postsテーブルにtitleとbodyカラムを追加します。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title', 8)->comment('タイトル'); // ← 追記 *********
$table->text('body')->comment('本文'); // ← 追記 *********
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
$table->string('title', 8)->comment('タイトル'); の部分がカラムの定義になります。
('title', 8)の「8」は●●●●を意味しています。
Blueprintクラスのインスタンス $tableに対して stringメソッドを呼んで文字列型のカラムを追加しています。
$table->integer('amount');のようにintegerメソッドを呼ぶと数値型を格納するカラムを追加出来ます。
他にもDateなど日付を扱う指定もできます。
テーブル定義が出来たところで migrate:refreshしてみる
php artisan migrate:refresh
マイグレーションが実行されてテーブルが作成されました。
ファクトリの作成(割愛)
ファクトリはテスト用にダミーデータを作る仕組みです。TDDでの開発が楽に出来るようになりますが、必須ではないので今回は割愛します。
シーダーの作成
seederというテスト用データ作成クラスを作ります。今回はシーダーを使って会員情報、投稿内容を作っていきます。
以下のコマンドを実行してシーダークラスを作成します。
php artisan make:seeder UsersTableSeeder
php artisan make:seeder PostsTableSeeder
UsersTableSeederの編集
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; // ← 追記 *********
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// ↓追記 ***メールアドレスを受信可能なものに設定すると通知メール試験でメールを受け取れます***
DB::table('users')->insert(['id' => 1, 'name' => '山田花子', 'email' => 'sute1@example.com', 'email_verified_at' => "2021-09-15 15:22:10", 'password' => bcrypt('password')]);
DB::table('users')->insert(['id' => 2, 'name' => '畠山まさみ', 'email' => 'sute2@example.com', 'email_verified_at' => "2021-10-12 16:22:10", 'password' => bcrypt('password')]);
DB::table('users')->insert(['id' => 3, 'name' => '伊藤順子', 'email' => 'sute3@example.com', 'email_verified_at' => "2021-11-14 17:22:10", 'password' => bcrypt('password')]);
DB::table('users')->insert(['id' => 4, 'name' => '西岡京子', 'email' => 'sute4@example.com', 'email_verified_at' => "2021-11-22 18:22:10", 'password' => bcrypt('password')]);
}
}
PostsTableSeederの編集
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; // ← 追記 *********
class PostsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// ↓ 追記 *********
DB::table('posts')->insert(['id'=>1,'title'=>'大橋担','body'=>'お友達になりませんか?']); // ← 追記 *********
DB::table('posts')->insert(['id'=>2,'title'=>'高橋担','body'=>'語り合いましょう']); // ← 追記 *********
DB::table('posts')->insert(['id'=>3,'title'=>'西畑担','body'=>'お話ししましょ']); // ← 追記 *********
DB::table('posts')->insert(['id'=>4,'title'=>'大西担','body'=>'よろしくお願いします!']); // ← 追記 *********
}
}
デフォルトで定義されているDatabaseSeeder.phpに、実行するシーダーを登録
DatabaseSeederクラスのrun関数にある $this->callの引数に実行するシーダークラスを追記します。
それによりシードの実行順序を制御できます。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
// $this->call(UsersTableSeeder::class);
$this->call([
UsersTableSeeder::class,
PostsTableSeeder::class,
]);
}
}
試しにマイグレーション
php artisan migrate:refresh
シーダーを実行してみる
php artisan db:seed
phpMyAdminを確認すると、こんな感じでシーダーで設定したデータが登録されているはずです。
ブラウザで表示してみる
ポート番号を指定できるので指定します。省略すると8000ポートが使われます。
php artisan serve --port=9999
デフォルトのWelcome画面が表示されます。
Log inを押すと、Bootstrapが反映されておらず質素なページになっています。
なので反映させていきます。
下記コマンドを実施してください。
npm install
npm run dev //1回目
npm run dev //2回目
前もって作っておいたid 1番の人のemailとpasswordを入れて、ログインしてみると...
ログインできました!
新規投稿ページの作成
まずはルーティング
では、次に新規投稿ページを設定していきましょう。
まずはweb.phpを開き、こちらを追加します。
Route::get('/post/create', [App\Http\Controllers\PostController::class, 'create'])->name('create');
localhost:9999/post/createにアクセスすると、PostControllerのcreateメソッドを呼び出す設定になります。
name('create')とすることで、任意のnameを設定できますが、これは後ほどコントローラーやビューで活かされます。
次はコントローラー
PostController.phpファイルを作成します。
php artisan make:controller PostController --resource --model=Post
--resource オプションを入れることで PostControllerに予めCRUD処理を行う関数が作成されます。
--modelはこのコントローラーで操作するModelを指定します。投稿(Post)を扱うため Postモデルを指定します。
PostControllerを開いてみましょう。
下記のように記述されているはずです。
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show(Post $post)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function edit(Post $post)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function destroy(Post $post)
{
//
}
}
createメソッド編集
試しに下記のようにcreateメソッドの箇所を編集して、
public function create()
{
{
return '新規投稿ページです';
};
}
localhost:9999/post/createにアクセスしてみてください。↓
後ほど、入力フォームを追加していきます。
indexメソッド
次にindexメソッドを編集して、投稿が一覧表示されるようにしていきます。
まずはルーティングから
Route::get('/post/index', [App\Http\Controllers\PostController::class, 'index'])->name('index');
次にコントローラー
Postモデルを使いたいので、頭のほうで
use App\Model\Post;
としておいてください。
public function index()
{
$query = Post::query();
//全件取得
$posts = $query->get();
//ページネーション
$posts = $query->orderBy('id','desc')->paginate(10);
//post/index.blade.phpに$postsという変数を渡す場合
return view('post/index', ['posts' => $posts]);
}
view(ビューファイル名,ビューに渡したいもの)とすることでコントローラからビューへ指示を出すことができます。
postsがビューで使うときの変数名、$postsはコントローラ内で定義した変数になります。
コントローラの中では、ビューで使う用の変数名に$をつけませんが、viewファイル内(bladeファイル)では変数の$をつけたものを使います。ややこしいので注意!
下記のような書き方も可能です。
public function index()
{
$query = Post::query();
//全件取得
$posts = $query->get();
//ページネーション
$posts = $query->orderBy('id','desc')->paginate(10);
//post/index.blade.phpに$postsという変数を渡す場合
return view('post.index')->with('posts',$posts);
}
一覧だけなら、posts=Post::all();とかでもいいのですが、ここではqueryオブジェクトを生成して対応しています(その理由は検索機能の実装等で便利だからですが、ここでは触れません)。
またせっかくなので、orderByで最新登録が先頭に来るようにしているのと、10行毎にページ処理をしています。
取得したデータはcompact()等で返してもいいのですが、わかりやすく-with()を利用しています。
view('view名')-with('viewでの変数名','実データ'); という形式になります。
ビューの編集
postディレクトリを作成して、その中にindexファイルを作成します。
下記のように編集してみましょう。
@extends('layouts.app')
@section('content')
<h1>一覧表示</h1>
<table class="table table-striped">
@foreach($posts as $post)
<tr>
<td>{{$post->title}}</td>
<td>{{$post->body}}</td>
</tr>
@endforeach
</table>
<!-- page control -->
{!! $posts->render() !!}
@endsection
localhost:9999/post/indexを開いてみましょう。
予めDBに登録しておいたpostデータが表示されたはずです。
投稿の保存
ここからは、入力フォームの内容をDBに保存できるように実装していきたいと思います。
▼参考記事
https://nodoame.net/archives/11612
まずはルーティングから
Route::post('/post/store', [App\Http\Controllers\PostController::class, 'store'])->name('store');
※storeメソッドはPOST送信になります。
コントローラー
createメソッドとstoreメソッドを使用することになりますが、storeメソッドの方は最も重要な箇所です。
まずはcreateメソッド。
public function create()
{
//createに転送
return view('post.create');
}
基本的に、postディレクトリのcreate.blade.phpファイルに処理を転送しているだけになります。
そして、store。
createが投げてきた値を受け取り、DBに保存。そして、一覧表示へリダイレクトさせています。
public function store(Request $request)
{
//postオブジェクト生成
$post = Post::create();
//値の登録。
//右側はviewのnameから持ってきたもの
//左側はモデルのカラム名
$post->title = $request->title;
$post->body = $request->body;
//保存
$post->save();
//一覧にリダイレクト
return redirect()->to('/post/index');
}
入力フォームを作って見た目を整える
createアクション用のビューを作っていきます。
post/create.blade.phpを作成し、下記のように編集してみましょう。
@extends('layouts.app')
@section('content')
<h1>新規投稿</h1>
<div class="row">
<div class="col-sm-12">
<a href="/post/index" class="btn btn-primary" style="margin:20px;">一覧に戻る</a>
</div>
</div>
<!-- form -->
<form method="post" action="/post/store">
<div class="form-group">
<label>タイトル</label>
<input type="string" name="title" value="" class="form-control">
</div>
<div class="form-group">
<label>本文</label>
<input type="text" name="body" value="" class="form-control">
</div>
<input type="hidden" name="_token" value="{{csrf_token()}}">
<input type="submit" value="投稿" class="btn btn-primary">
</form>
@stop
post先(action)はstore(/post/store)。methodはpost。
hiddenでLaravelでpostするときに原則必要となるcsrf_tokenを送っています。
▼参考記事
動作確認として、入力フォームに値を入れて投稿してみます。
残念。エラーです。
解決するためには、DBの厳密モードを変更する必要があります。無効にするには、以下の手順に従ってください。
①Config/database.phpを開きます
②find 'strict'値をtrueからfalseに変更して、再試行します
これで無事にDBに入力フォームの値が保存されました。
今回の記事ではリレーションの設定については割愛しました。
また別の記事にて投稿したいと思います。
その他学習したこと
フォームから受け取った値を一度加工してからDBに格納するためにはEloquentが必要。
Eloquentとは
DB のデータを操作する機能のこと。
▼参考記事
https://laraweb.net/knowledge/2324/
DBに保存する方法として、
fillメソッドとsaveメソッドがありますが、
メソッドチェーンで連結しています。
fillメソッド
実行するSQL文のプレースホルダに値をバインドする処理
saveメソッド
insertする処理
です。
プレースホルダとは
実際の内容を後から挿入するために、とりあえず仮に確保した場所のこと。 また、そのことを示す標識などのこと。
バインドとは
束縛(する)、拘束(する)、結びつける、関連付ける、などの意味を持つ英単語。 ITの分野では、何らかの要素やデータ、ファイルなどが相互に関連付けられている状態や、そのような状態を実現する機能などのことを指すことが多い。