未経験からweb系プログラマーになるための独学履歴~アプリケーション作成を体系的に学ぶ・Laravelの基本編~

## はじめに

[前回](https://qiita.com/shitikakei/items/3aeee48dfb8900de7649) でLaravelをインストールしたので今度は実際に使っていく。

## よく使う項目

### .envファイル

Laravelの設定ファイル、踏み込んで言うとLaravelを用いて制作しているアプリケーションの環境設定情報ファイル。
暗号化キーやデータベースの接続情報を記述する。
例えばデータベースの接続情報はローカル環境で行う場合、

```
DB_CONNECTION=mysql // 使用するデータベースの種類。MariaDBの場合はこのままでOK。
DB_HOST= 127.0.0.1 // MySQLならSELECT Host, User, Password FROM mysql.user;で確認できる。
DB_PORT=3306
DB_DATABASE= // プロジェクト（アプリケーション）が参照するデータベースを指定
DB_USERNAME= // 参照するデータベースの権限を持つユーザーの名前
DB_PASSWORD= // 上記ユーザーでMySQLにアクセスするパスワード

```

とこのようになる。
ちなみに、変更を反映するには後述のartisanコマンドで`php artisan config:cache`を実行してください。
私は沼りました。


### artisanコマンド

ルートフォルダの直下にあるartisanファイルに定義されているコマンド。
`artisan 任意のコマンド`でLaravelの様々な操作を行う。
実行の際はいずれもプロジェクトのルートフォルダにディレクトリを合わせておく。
実際の制作で使うものはその都度、紹介するとしてここでは以下の3つを紹介する

### serveコマンド

PHPの組み込みサーバーでプロジェクトを動作させるコマンド。
例えば以下のようにすると前回の最後で確認したLaravelのトップページが出る。

```
php artisan serve --host=localhost --port=8000

```

### route:listコマンド

ルーティングの一覧を出すコマンド。
ルーティングに関してはルーティングの項を参照。

### tinkerコマンド

デバックで使用するコマンド。
打ち込んだコードに対して即座に結果を返してくれるので、処理の確認やオブジェクトの持つメソッドの確認に使う。

## データベースの設定

### 必要な知識……MySQL（使用するデータベース）の基本的な操作

データベースの設定をしないと始まらないのでまずはここから手を付ける。
私は沼ったので一応確認しておくが、使用するデータベース等々デフォルトの設定を変更したらyamlファイルまたは.envファイルあるいは両方について任意のコマンドを実行し、変更を反映させておくこと。
じゃないと例えばMariaDBを使いたいのにMySQLのままで一生アクセスできないで数時間費やすという悲劇が起きる。
改めてになるが、yamlファイルの場合は`vagrant up --provision`、.envファイルは`php artisan config:cache`を実行すると変更が反映される。

また、Homesteadを使う場合通常phpadminが使えないのでコマンドプロンプトでデータベースにアクセスしてテーブル等を確認することになるのだが、そのためにいちいちLaravelプロジェクトとデータベースを行ったり来たりするのは効率が良くないのでGUIソフトを使用するといい。
私は [TablePlus](https://tableplus.com/) を使用している。

では、データベースを作成する。
プロジェクトのルートフォルダにディレクトリを合わせてそこからデータベースにアクセスする。
MySQLとMariaDBの場合は

```
mysql -uDB_USERNAME -pDB_PASSWORD

```

これでアクセスできる。
今回はHomesteadにLaravelをダウンロードしたばかりという想定なのでrootでアクセスすることになるので

```
mysql -u root

```

となる。初期設定の場合、rootにパスワードは定義されていないのでまずはそのあたりから設定していく。
先程rootアクセスしたMySQL上で

```
set password = password('任意の半角英数字');

または

set password for 'root'@'localhost' = password('任意の半角英数字');

```

実行する。
前者はログイン中のユーザー、後者は特定のユーザーにパスワードを設定するためのコマンド。
つまり上記の場合はDB_HOSTがlocalhostのDB_USERNAMEがrootのユーザーにパスワードを設定するという意味になる。
ちなみにユーザーの作成は

```

create user `testuser`@`localhost` IDENTIFIED BY 'password';

grant all privileges on 権限を付与するデータベース名.* to testuser@localhost IDENTIFIED BY 'パスワード';

```

と2つのコマンドでできる。
前者はDB_HOSTがlocalhostのDB_USERNAMEがtestuser、DB_PASSWORDがpasswordというユーザーを作成する。
後者は上記のユーザーが指定したデータベースにアクセス・編集・操作できる権限を付与するという意味になる。
続いて、データベースを作る。


```
create database sample_DB;

```

これで、sample_DBができる。
そして先程紹介した権限付与のコマンドを使って権限ユーザーを決めればデータベースの作成は完了。
ここまでの作業は必ずやっておくこと、面倒くさがってrootのままでとか思うと沼るし危険。
ではexitと打ち込んで一旦MySQLからログアウトして、Laravelに戻りテーブルを作っていく。

## Laravelでのテーブル作成・編集（マイグレーション）

データベースのテーブルはPDOなどのSQLで行うが、Laravelを使うとそれをPHP範囲内で実行することができる。
そのためのコマンドがartisanコマンドの`make:migration`及び`migrate`である。
まず、マイグレーションファイルを作る。
あとあと作成するモデルとの兼ね合いでテーブルの命名はモデル名の複数形としなければいけないのでそこだけに注意して以下のコマンドを実行する。

```
php artisan make:migration create_sampleusers_table --create=sampleusers

```

これで「マイグレーションを実行した日付_create_sampleusers_table.php」という名前でマイグレーションファイルができるので、格納されている`database/migrations`ディレクトリを参照してファイルを開く。
ファイルができているのを確認したら、PHPでテーブルに登録するカラムについて書いていく。
例えば以下のようなテーブルを作成する場合は、ファイルを以下のように編集する

<img width="635" alt="2019-10-27_00h39_58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428779/1850447c-e459-2804-d9e1-af4f07ba682e.png">


```php:
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateSampleUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('sampleusers', function (Blueprint $table) {
            $table->increments('id')->comment('プライマリーキー');
            $table->string('user_name',100)->comment('ユーザー名');
            $table->string('password',255)->comment('パスワード');
            $table->string('email',128)->comment('メールアドレス');
            $table->unsignedTinyInteger('isEmailConfirmed')->comment('本登録フラグ')->nullable();;
            $table->string('token',32)->comment('トークン')->nullable();;
            $table->datetime('tokenExpire')->comment('トークンの有効期限')->nullable();
            $table->unsignedTinyInteger('loginFailureCount')->comment('ログイン失敗回数');
            $table->datetime('loginFailureDatetime')->comment('ログイン失敗日時')->nullable();
            $table->unsignedTinyInteger('deleteFlag')->comment('削除フラグ')->nullable();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('sampleusers');
    }
}


```
詳細は[ドキュメント](https://readouble.com/laravel/6.0/ja/migrations.html) を参照。
基本的に`$table->データの型（'カラム名' ,許容文字数)`に例えば注釈をつけるなら`->comment('コメント')`やNULLを許容するカラムには`->nullable()`を後述していくという理解で問題ない。
ファイルの編集が終わったら以下のコマンドを実行してエラーが出なければテーブル作成は完了。

```
php artisan migrate

```

ちなみにmigrateしたものを取り消す場合は以下のコマンドを実行する。

```
直前のmigrateを取り消す
php artisan migrate:rollback

すべてのmigrateを取り消す
php artisan migrate:reset

```

マイグレーションの便利なところはマイグレーションファイルさえ作っていればmigrateコマンドで気軽にテーブルの作成・そして初期化ができるというところである。
次に紹介するシーディングと合わせると、テスト開発におけるテーブルの作成・初期化・カラムにテストデータを挿入を楽に行うことができる。

## 作成したテーブルのカラムにデータを挿入する（シーディング）

先程作ったテーブルにレコード（各カラムの値）を追加するためにシーディングを行っていく。
下記のコードを実行してシーディングファイルを作る。

```

php artisan make:seeder SampleUsersTableSeeder

```

`database/seeds`ディレクトリにSampleUsersTableSeeder.phpができるのでそれを編集する。

```php:
<?php

use Illuminate\Database\Seeder;

class SampleUsersTableSeeder extends Seeder {

   /* 通常のデータ登録手順。複数のデータを登録するにはforeachを用いて以下のように書く。
   	  登録するデータが2つ以上ないとエラーが出るので注意。
   */
    public function run() {
		
		//　データベースを初期化する。
		DB::table('sampleusers')->truncate();
    	
    	$sampleusers = [
        ['user_name' => "田中",
        'email' => "tanaka@test.com",
        'password' => "$2y$10$8xICCr7.VU2.8okPrwh4dugGGFc1MBZM954MunkmHT9RWVymnsbvs",
        'isEmailConfirmed' => 1,
		'token' => "20789fed951fa925361d8cf130b7ccd1",
		'loginFailureCount' => 0,
		'deleteFlag' => 0],

		['user_name' => "山田",
        'email' => "yamada@test.com",
        'password' => "$2y$10$8xICCr7.VU2.8okPrwh4dugGGFc2MBZM954MunkmHT9RWVymnsbvs",
        'isEmailConfirmed' => 1,
		'token' => "20789fed95gfa925361d8cf130b7ccd1",
		'loginFailureCount' => 0,
		'deleteFlag' => 0,
        ]

    ];

    foreach($sampleusers as $sampleuser) {
    	\App\sampleuser::create($sampleuser);
    }
	}

/* ファクトリーを利用してデータベースを登録する場合。こちらはデモ用途で使用するのに便利
	public function run() {
		
		//　データベースを初期化する。
		DB::table('sampleusers')->truncate();
    	
    	// ファクトリーを利用してデータベースにデータを登録する。factoryの第2引数は登録する件数を指定する。
    	factory(App\sampleuser::class, 2)->create();
	}
*/
}

```

例によって詳細は [ドキュメント](https://readouble.com/laravel/6.0/ja/seeding.html) を参照。
当然だが本番のデータでトークンやらパスワードやらをこのようにソースで公開してはいけない。
今回はあくまでアウトプットとテスト用途のデータで適当に生成しているものなのでそのまま載せる。
今回は2人のユーザーをのデータをセットしたが、単体の場合は`insert()`を使う。
また、上記のコードに注釈しているがテスト・デモ用途で大量のデータを登録したいという場合はFactoryライブラリを使うといい。
下記のartisanコマンドを実行する。

```
artisan make:factory SampleUserFactory --model=SampleUser

```

すると`database/factories`ディレクトリに`SampleUserFactory.php`が作成されるのでこれを編集する。

```php:

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\SampleUser;
use Faker\Generator as Faker;

// データベースに登録するデータを記入。
$factory->define(SampleUser::class, function (Faker $faker) {
    return [
        'user_name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => Hash::make($faker->password()),
    ];
});


```

例えばこんな感じに。
`$faker->`の形で記入していく。
詳しくは下記ページを参考

[『Laravel』のシーディング機能を使ってみる](https://liginc.co.jp/396543)
[Fakerでランダムなフェイクデータを作成する](https://qiita.com/Sa2Knight/items/fb82be7551cc84764267)
[Fakerチートシート](https://qiita.com/tosite0345/items/1d47961947a6770053af)

factoryを使ってデータを登録するのであれば先程のシーディングファイルのrunメソッド以下を注釈部分と差し替えればいい。
データベース初期化メソッドはそのままで。
今回はforeachを使ったrunメソッドの方で話をすすめる。
シーディングファイルが完成したら

```
php artisan db:seed

```

を実行する。
エラーが出なければあとはGUIソフトやコマンドプロンプト等でテーブルを確認してレコードが登録されているかどうか確かめて確認できればOK。

最後にモデルを作ればデータベース周りの準備は一段落。
下記のartisanコマンドを実行。モデルの命名は前述の通りテーブルの単数形となるので以下の通りになる。

```
php artisan make:model SampleUser

```

`app/Http`ディレクトリに`SampleUser.php`ができるのでそれを編集する。


```php:
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;

// 日付日時関係はcabornパッケージを使う

class SampleUser extends Model
{
	// timestampsを無効化
	public $timestamps = false;

	// 使用するテーブルを指定
    protected $table = 'sampleusers';

    // fillセーブするために保存するカラム名を格納する。
    protected $fillable = ['user_name','password','email'];
}


```
artisanした時点ではクラスの中身は空である。
必要に応じて、以上のようにプロパティなどを追加していく。

ここまできたらいよいよLaravelでCRUD（Create・Read・Upload・Delete）を行う。

## ルーティング

ルーティングはリクエストに応じて処理を振り分ける役割を持つ。
ファイルは`routes/web.php`。

```

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

/*
ルーティングの基本。第1引数はgetリクエストがどこに来た場合に処理を実行するか、第2引数にその処理を定義。
この場合、ルートにgetリクエストが来た場合に、welcomeというビューを返すことになる。
*/

Route::get('/', function () {
    return view('welcome');
});

// コントローラーを経由するルーティング、@以下メソッド名をつけるとコントローラーに定義してあるメソッドに処理を振り分けられる。
Route::resource('sample', 'SampleuserController');
Route::resource('carbon', 'CarbonController');


```

`return view(welcom)`はデフォルトで設定されているルーティング。
ルートアドレスをでGETを叩くとWelcome.blade.phpへ飛ばさるということになる。
ここで重要なのはMVC（モデルビューコントローラー）という考え方。
詳しくは [MVCに基づいて設計する時に思う自分なりのベストプラクティス](http://rabbitfoot141.hatenablog.com/entry/2018/10/16/194555) 等歴々のエンジニアの方の記事を参考にして頂くとして、この記事を参考にさせて頂いて私にあり簡単に解釈すると

Model（モデル）

システムの根幹機能に関する処理全般、例えばDBからデータを取得するなどの処理などはこちらに書く。

View（ビュー）

HTML、つまりサイトの見た目。

Controller

バリデーション、Session管理、例外の振り分け、Requestを受け取ったときの処理。

という風にファイルを分類し、コードの見やすさ及び処理の流れのわかりやすさを確保しようという考え方だと思っている。
ルーティングはこのMVCをLaravelで扱うための成すものと思っていい。
ルーティングに話を戻すと、今回の場合はユーザーからリクエストを受け取った場合、コントローラーにパスする仕事をしていると思っていい。
ちなみにルーティングする場合は、上記のように`Route:get`及び`Route:resource`と書けばいいのだが、前者の場合はget処理のリクエストを受け取った場合ルーティングが発生するが、後者はリクエストの仕方によってルーティングが分岐するもの。

具体的にはこのようになる。

|リクエスト  |URI  |Route:getで書いた場合  |コントローラーメソッドの用途  |
|---|---|---|---|
|GET  |/コントローラー名  |Controller@index  |一覧画面の表示  |
|GET  |/コントローラー名/{$id}  |Controller@show  |詳細画面の表示  |
|GET  |/コントローラー名/create  |Controller@create  |登録の画面の表示  |
|POST  |/コントローラー名  |Controller@store  |登録処理  |
|GET  |/コントローラー名/{$id}/edit  |Controller@edit  |編集画面の表示  |
|PUT  |/コントローラー名/{$id}  |Controller@update  |編集処理  |
|DELETE  |/コントローラー名/{$id}  |Controller@destroy  |削除処理  |

{$id}にはデータベースに登録されているidのこと。
`Route:get`で書く場合、7種類も書かなければいけないところが一行で済むのがわかると思う。
処理としてはリクエストとURIの組み合わせでルーティングを決定すると思っていい。
ここまで来たらコントローラーを作る。

```
php artisan make:controller RestappController --resource

```

このartisanコマンドで`Route:resource`に対応したコントローラーの雛形ができる。
できたコントローラーを編集すると例えばこんな感じになる。

```php:

<?php

namespace App\Http\Controllers;

use App\sampleuser;
use App\Http\Requests\sampleuserRequest;
use Illuminate\Http\Request;


class sampleuserController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    
    // 一覧表示
    public function index() {

        // 複数のユーザーのデータをすべて受け取るので変数も複数形。
        $sampleusers = sampleuser::all();

        // compactの引数も当然複数形
        return view('sampleuser.index', compact('sampleusers'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    
    /*1件のデータを新規作成。本来は必要がない（WebAPIにおいて、画面に登録フォームを表示する画面はいらないから）。
    storeメソッドとセット。
    */
    public function create() {

        return view('sampleuser.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    
    // createメソッドで飛ばされた先の実際の処理
    public function store(sampleuserRequest $request) {
        $sampleuser = new sampleuser;

        // フォームから受け取った値をすべて格納する
        $form = $request->all();

        // fill()->save();でフォームから受け取った値をもとに複数のカラムの値を更新・追加しセーブする。
        // sampleuserのprotect $fillableの項目も参照。
        unset($form['_token']);
        $sampleuser->fill($form)->save();

        return redirect('sampleuser/' . $sampleuser->id);

    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    
     /*
    レコード表示。indexと違ってidで紐つけて1件ずつ表示する。
     */
    public function show(sampleuser $sampleuser)
    {
         return view('sampleuser.show', compact('sampleuser'));
         // オブジェクトを単なる連想配列として返すだけだとこちら。
         // return $sampleusers->toArray();
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    
    // 更新処理。updateメソッドとセット
    
    // モデル結合ルート、引数にコントローラー名とその変数をいれるとFindorFail()を含めた一連の処理を書かなくて済む。
    public function edit(sampleuser $sampleuser) {
       return view('sampleuser/edit', compact('sampleuser'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    
    // 更新処理
    public function update(sampleuserRequest $request, sampleuser $sampleuser)
    {
        // 更新するカラムの数だけインスタンスにアクセスしリクエスト変数に代入してセーブする。
        $sampleuser->user_name = $request->user_name;
        $sampleuser->email = $request->email;
        $sampleuser->save();
        return redirect('sampleuser/'.$sampleuser->id);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    
    // 削除処理
    public function destroy(sampleuser $sampleuser) {
        $sampleuser->delete();
        return redirect('sampleuser');
    }
}



```
先程書いたルーティングの対応表に沿って`view()`の引数は`view(コントローラー名/メソッド名)`あるいは
`view(コントローラー名.メソッド名)`と指定する。

また、CRUDのメソッドすべてを使うことがない場合は使わないメソッドへのルーティングを制限するので
その場合は

```
Route::resource('モデル名', 'コントローラー名', ['only' => ['使わないメソッド名',......]]);

```
という風にルーティングに追記をしておく。
コードにも注釈をつけているが、コントローラーの基本的なCRUDメソッドに関しては以下のように対応付けすると覚えやすい。

|表示に関するメソッド  |リクエストに対しての処理  |
|---|---|
|create  |store  |
|edit  |update  |

また、`compact()`や`toArray()`などを見ればわかるようにデータベースから受け取った値は必ず連想配列の形で渡さなければならない。
`$sampleuser->id`は{$id}のこと。
また、今回はコードを完結にするためモデル結合ルートを用いている。詳細は[ドキュメント](https://readouble.com/laravel/6.0/ja/routing.html)参照。
次回はviewについて確認してLaravelの基本の確認は終了となる。






## 参考
[Laravel入門 - 使い方チュートリアル](https://qiita.com/sano1202/items/6021856b70e4f8d3dc3d#%E3%83%AB%E3%83%BC%E3%83%88%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF)
[Laravel超入門 開発環境の構築（VirtualBox + Vagrant + Homestead + Composer）](https://qiita.com/7968/items/97dd634608f37892b18a)
[Laravel5.7: usersのCRUD機能を実装する](https://qiita.com/sutara79/items/cd4371b246b44a2cf87f#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9-3)
[Laravelで作るRESTなWebアプリ](https://qiita.com/MasaKu/items/82b9743383e73cb62c3e)
[Vagrant + VirtualBox でLaravel5.8環境構築メモ
](https://qiita.com/makimoch/items/f6737f02e6978423f121)
[よく使うMySQLコマンド集](https://qiita.com/CyberMergina/items/f889519e6be19c46f5f4)