Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

前回 で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 を使用している。

では、データベースを作成する。
プロジェクトのルートフォルダにディレクトリを合わせてそこからデータベースにアクセスする。
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でテーブルに登録するカラムについて書いていく。
例えば以下のようなテーブルを作成する場合は、ファイルを以下のように編集する

2019-10-27_00h39_58.png

<?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');
    }
}


詳細はドキュメント を参照。
基本的に$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

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();
    }
*/
}

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

artisan make:factory SampleUserFactory --model=SampleUser

するとdatabase/factoriesディレクトリにSampleUserFactory.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』のシーディング機能を使ってみる
Fakerでランダムなフェイクデータを作成する
Fakerチートシート

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

php artisan db:seed

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

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

php artisan make:model SampleUser

app/HttpディレクトリにSampleUser.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に基づいて設計する時に思う自分なりのベストプラクティス 等歴々のエンジニアの方の記事を参考にして頂くとして、この記事を参考にさせて頂いて私にあり簡単に解釈すると

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

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}のこと。
また、今回はコードを完結にするためモデル結合ルートを用いている。詳細はドキュメント参照。
次回はviewについて確認してLaravelの基本の確認は終了となる。

参考

Laravel入門 - 使い方チュートリアル
Laravel超入門 開発環境の構築(VirtualBox + Vagrant + Homestead + Composer)
Laravel5.7: usersのCRUD機能を実装する
Laravelで作るRESTなWebアプリ
Vagrant + VirtualBox でLaravel5.8環境構築メモ

よく使うMySQLコマンド集

shitikakei
ITパスポート取得をきっかけに2019年、0から勉強をスタート。 同年4~7月までHTML・CSS・Javascript。 同年7~10月半ばまでPHP。 同年11月〜2020/1月にLaravelを学びながら成果物を作成。2020/4月よりPython・Djangoの学習を始め、同年5月~6月にチーム開発企画に参加。現在フリーターから就職先を探しています。
https://www.resume.id/shitikamiyako
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away