20200807のlaravelに関する記事は9件です。

AWSでLAMP環境を構築して、Laravelアプリをデプロイする

今回はAWSのEC2、RDSを用いてLAMP環境を構築して、Laravelアプリをデプロイする手順を紹介します。

今回の流れ

1.RDSを用いてDBサーバー作成
2.EC2を用いてWEBサーバーを作成
3.サーバー間の連携
4.アプリのデプロイ

前提条件

・Macを使用
・AWSアカウントを作成済みであること
・GitHubのリモートリポジトリに、開発済みのLaravelアプリが置いてあること

1.RDSを用いてDBサーバー作成

コンソールにサインインした後、AmazonRDSに移動します。
スクリーンショット 2020-08-07 9.22.21.png
続いてオレンジ色のCreate databaseボタンをクリックします。
スクリーンショット 2020-08-07 9.24.32.png
使用するデータベースエンジンを選びます。今回はMySQLを選択します。
バージョンはよしなに選択してください。
スクリーンショット 2020-08-07 9.28.31.png
今回は無料利用枠のものを作成します。
本番環境の場合は適したプランを選択してください。
スクリーンショット 2020-08-07 9.33.25.png
インスタンス名、マスターユーザー名、パスワードを設定します。
後ほど使いますので、安全な場所にメモしておきましょう。
スクリーンショット 2020-08-07 9.35.39.png
インスタンスのスペック、ストレージの容量等を設定します。
今回はデフォルト設定で進めますが、本番環境の場合はよしなに選択してください。
スクリーンショット 2020-08-07 9.37.05.png
ネットワークの設定を行います。
VPCを作成済みの方は作成したVPCを、そうでない方はデフォルトのVPCを設定しましょう。
スクリーンショット 2020-08-07 9.43.13.png
最後にオプションの設定をします。
RDSインスタンス初期化時に自動で作られるデータベースの名前を設定します。
今後データベースに接続する際は、ここで設定したデータベース名を使用します。スクリーンショット 2020-08-07 9.51.15.png
スクリーンショット 2020-08-07 9.51.05.png
オレンジ色のCreate databaseボタンをクリックして設定したデータベースを作成します。
スクリーンショット 2020-08-07 12.28.58.png

2.EC2を用いてWEBサーバーを作成

コンソールからAmazon EC2に移動して、青色のLaunch Instanceボタンをクリックします。
スクリーンショット 2020-08-07 12.36.05.png
使用するマシンのイメージを選択します。
今回はAmazon Linux 2 AMIを用います。スクリーンショット 2020-08-07 12.39.41.png
EC2インスタンスタイプを設定します。
CPU、メモリ、ストレージ、ネットワークパフォーマンス等を考慮してよしなに選択します。
今回はt2.microを選択します。(無料利用枠の対象です)スクリーンショット 2020-08-07 13.45.57.png

スクリーンショット 2020-08-07 12.48.01.png
詳細の設定です。
VPCやサブネット等を設定できますが、今回はとりあえずVPCのみ設定しておきます。
RDSで設定したものと同じVPCを選択してください。
スクリーンショット 2020-08-07 12.50.42.png
ストレージの設定をします。
他にインスタンスを作成されない場合は30GBまでは無料枠です。
今回はデフォルトの8GBで進めていきます。
スクリーンショット 2020-08-07 12.56.42.png
続いてタグの設定ですが今回は未設定のまま進み、セキュリティグループの設定をします。
EC2インスタンスへのアクセス許可、制限を指定します。
まずはSSH接続の設定です。
Create a new security groupを選択し、新しいグループを作成します。
TypeのプルダウンからSSHを選択し、SourceのプルダウンからはMyIPを選択しましょう。
次にHTTP接続です。
Add Ruleをクリックした後、TypeのプルダウンからHTTPを選択し、SourceのプルダウンからはMyIPを選択しましょう。
今回は自分のIPからのみ接続できる設定にします。
本番環境で不特定多数のアクセスを集める場合はHTTPのSourceをAnywhereにしてください。
スクリーンショット 2020-08-07 13.45.57.png
Review and Launchをクリックし確認画面に遷移し、設定内容に問題がなければLaunchをクリックしましょう。
最後に、SSH接続するためのキーペアを作成します。
Create new key pairを選択し、キーペアの名前を設定します。
設定後、Download Key Pairをクリックして.pemファイルをダウンロードします。
このファイルがなければSSH接続できないので、安全な場所で保管してください。
青色のボタンLaunch Instanceをクリックしてインスタンスを起動します。
スクリーンショット 2020-08-07 13.59.49.png

3.サーバー間の連携

まずは先に作成したRDSの設定を変更し、EC2インスタンスからRDSインスタンスへのアクセスを可能にします。
AmazonRDSに移動します。
スクリーンショット 2020-08-07 9.22.21.png
左側のダッシュボードのDatabasesをクリックして、先に作成したデータベースを選択します。
Connectivity & securityタブのセキュリティグループをクリックします。
スクリーンショット 2020-08-07 14.11.54.png
デフォルトではEC2インスタンスからRDSインスタンスへのアクセスは許可されていません。
Inboundタブを開きeditをクリックしてセキュリティグループの編集を行います。
スクリーンショット 2020-08-07 14.22.01.png
TypeをMySQL/Auroraに、SourceをCustomeに設定し先ほど作成したEC2のセキュリティグループの名前を入力します。
利用可能なセキュリティグループが表示されるので、先ほど作成したものを選択します。自動で値が入力されます。
青色のSavaボタンをクリックし設定を反映させます。
スクリーンショット 2020-08-07 14.58.00.png
続いてEC2インスタンスにSSH接続していきます。
ターミナル上のキーペアがあるディレクトリで以下のコマンドを実行します。

ssh -i .pemファイル名 ec2-user@パブリックIP

パブリックIPは、接続するインスタンスのこちらをコピーペーストしましょう。
スクリーンショット 2020-08-07 15.15.22.png
EC2インスタンスにSSH接続できたら、RDSに接続するための準備をしていきます。
MySQLをインストールしたいのですが、MariaDBがデフォルトでインストールされていると競合してしまうので、アンインストールしておきます。

$ sudo yum remove mariadb-libs

MySQLのリポジトリを追加して、MySQLをインストールします。

$ sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
$ sudo yum install mysql

MySQLのホスト名を環境変数に設定して、データベースに接続します。
エンドポイントはRDSインスタンスのホスト名を入力します。
ユーザー名、パスワード、DB名は先に作成したものです。

$ export MYSQL_HOST=エンドポイント
$ mysql --user=ユーザー名 --password=パスワード DB名

スクリーンショット 2020-08-07 17.11.38.png
Laravelアプリのためのユーザーを作成し、データベースへのアクセス権限を付与します。

mysql> CREATE USER 'ユーザー名' IDENTIFIED BY 'パスワード';
mysql> GRANT ALL PRIVILEGES ON DB名.* TO ユーザー名;
mysql> FLUSH PRIVILEGES;
mysql> Exit

次にEC2インスタンスにApacheとPHPをインストールします。
まずはApacheのインストールです。

$ sudo yum install -y httpd
$ sudo service httpd start

パブリックIPアドレスにアクセスして、以下の画面が表示されていればインストール成功です。
スクリーンショット 2020-08-07 17.47.44.png
PHP並びにLaravelアプリに必要な拡張モジュール等をインストールしていきます。
今回のLaravelのバージョンは5.5なので、対応したPHP拡張モジュールも合わせてインストールしておきます。
また、自分の開発したアプリに必要な拡張モジュールがあれば適宜追加でインストールしてください。

$ sudo amazon-linux-extras install -y php7.2
$ sudo yum -y install php-openssl php-pdo php-mbstring php-tokenizer php-xml

これでLAMP環境を構築することができました。

4.アプリのデプロイ

Laravelアプリのデプロイ、デプロイのための最終準備をしていきます。
まずはEC2インスタンスにGitをインストールします。

$ sudo yum -y install git

続いて/var/www/htmlに移動して、完成済みのLaravelアプリをgit cloneします。

$ cd /var/www/html
$ sudo git clone URL

Apacheの設定を変更していきます。
/etc/httpd/confに移動して、httpd.confを編集します。

$ cd /etc/httpd/conf
$ vi httpd.conf

以下が編集箇所です。
119行目付近でドキュメントルートを変更し、アクセスがあった際にアプリ直下のpublicディレクトリにファイルを探しにいってくれるようにします。
131行目付近、151行目付近でpublicディレクトリ内での設定の変更を有効にします。
最終行でmod_rewriteを許可することでURLの書き換えを可能にします。

#119行目付近 
DocumentRoot "/var/www/html/Laravelアプリ/public"
#131行目付近
<Directory "/var/www/html/Laravelアプリ/public">
#151行目付近
AllowOverride All
#最終行に追加
LoadModule rewrite_module modules/mod_rewrite.so

変更後はApacheを再起動させます。

$ sudo systemctl restart httpd

続いてComposerをインストールします。
/usr/local/bin/にインストールしてファイル名を変更することで、どこからでもcomposerコマンド一つで呼び出し可能にします。

$ cd /usr/local/bin/
$ sudo php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ sudo php -r "if (hash_file('sha384', 'composer-setup.php') === 'e5325b19b381bfd88ce90a5ddb7823406b2a38cff6bb704b0acc289a09c8128d4a8ce2bbafcd1fcbdc38666422fe2806') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
Installer verified
$ sudo php composer-setup.php
$ sudo php -r "unlink('composer-setup.php');"
$ sudo mv composer.phar composer

最後の仕上げです。
アプリの環境変数の設定等を行っていきます。
まずはcomposer.lockファイルを基にパッケージをインストールします。
ディレクトリの権限も変更しておきます。こちらの変更はアプリ起動完了後によしなに変更しても良いかと思います。

$ cd /var/www/html
$ chmod 777 Laravelアプリ
$ cd Laravelアプリ
$ chmod 777 bootstrap/cache
$ chmod 777 storage/framework/sessions
$ chmod 777 storage/framework/views
$ chmod 777 storage/logs vendor
$ composer install

.env.exampleファイルeを基に.envファイルを作成します。

$ cp .env.example .env
$ vi .env

先に作成したRDCインスタンスを基に、DB接続に関する変数を定義していきます。
ユーザー名、パスワードはRDCインスタンスに接続して登録したものを設定します。

DB_CONNECTION=mysql
DB_HOST=ホスト名(エンドポイント)
DB_PORT=3306
DB_DATABASE=DB名
DB_USERNAME=ユーザー名
DB_PASSWORD=パスワード

artisanコマンドを叩いてアプリケーションキーを作成します。
マイグレーションも実行しておきます。(開発済みのアプリなのでマイグレーションファイルがあることが前提です)

php artisan key:generate
php artisan migrate

これでパブリックIPアドレスにアクセスすれば、アプリケーションが動作しているはずです!
ここまでお疲れ様でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GUIベースのタスクスケジューラー「laravel-totem」

はじめに

Laravelでタスクスケジューラーが必要になった時、セオリーとしてはKernel.phpにscheduleメソッドをつらつらと書き、cronから毎分artisanコマンド schedule:run をコールするよう設定するはずだ。そして、それで十分というプロジェクトも多いだろう。
Laravel 6.x タスクスケジュール

しかしある程度タスクが増え、実行結果確認が毎度必要で、場合によっては再実行が求められるプロジェクトでは、このやり方では甚だ不十分である。ではどうするか?

その答えのひとつが、今回紹介する codestudiohq/laravel-totem である。

laravel-totemが提供するもの

まず大前提として、laravel-totemはGUIで各種操作を提供している。GUIには、ブラウザから /totem というディレクトリに移動することでアクセスできる。

美しいGUI

百聞は一見にしかず。以下はタスク一覧。他の画面を見たい人はコチラ
tasklist.png

認証

web上に公開されている画面となるため、認証は必須である。ただしlaravel-totemが提供するのは認証の一部分のみである。どういうことかは以下のコードを見てもらえばおわかりいただけるだろう。要は既存の認証機能を使い、結果だけをlaravel-totemに連携せよということである。

AppServiceProvider.php
public function boot()
{
    Totem::auth(function($request) {
        // return true / false . For e.g.
        return Auth::check();
    });
}

あるいは、特定のIPアドレスからのみアクセスを許可するといったケースにも簡単に対応できる。

AppServiceProvider.php
use Symfony\Component\HttpFoundation\IpUtils;

public function boot()
{
    Totem::auth(function($request) {
        // return true / false . For e.g.
        return IpUtils::checkIp($request->ip(), ['192.168.1.0/24', '192.168.1.15/32']) ? true : false;
    });
}

細やかなスケジュール設定

scheduleメソッドでは時間以外の細やかな設定ができるが、それとほぼ同等の設定がGUIでできる。時間はもとより、メンテナンスモード中も実行できるか、多重実行できるか、といったオプションを気軽に指定できるのがありがたい。

手動実行

画面上のアイコンから、手動実行ができる。例えばスケジュール通りに動くべきタスクがエラーでこけていた際の再実行などで役立つはずだ。ただし、後述の留意点にある通りmax_execution_time に注意すること。

実行結果の記録

実行ログおよび、終了時間、処理秒数を記録する。これにより、例えば日々のパフォーマンスを確認してタスクのパフォーマンス改善の要不要を判断できるようになる。なお記録は希望日数分残すことができる。

実行通知

メール通知は言うに及ばずslack通知が簡単にできるのがありがたい。slackのwebhook URLを登録するだけでできる。ただ通知は非常に簡素なのので、若干物足りなさは感じるかもしれない。

導入の難易度

github上の説明を元に実施すれば、躓くことは無かった。ただし、config/totem.php を作りたい場合の手順は記載されていないので、以下のコマンドで実行する。

php artisan vendor:publish --tag=totem-config

留意点

実際使ってみたときに気づいた留意点は以下の通りである。

実行ログに記録される時間はDBのタイムゾーン依存

CURRENT_TIMESTAMPで日時を登録しているため、アプリはJST、DBのタイムゾーンがUTCというケースでは、実行ログの時間が実際の実行時間とズレているように見える。

スケジュール実行はあくまでcron依存

laravel-totemでスケジュールを設定したとしても、cronから schedule:run コマンドを毎分実行しないと、スケジュール通りに動いてくれない。例えばdockerなどのローカル環境で開発しているときには、スケジュール通り動作するかの検証は難しいかもしれない。

手動実行はmax_execution_timeの制約下

cronからキックするのではなく、laravel-totemから手動でタスクをキックする場合、php.iniのmax_execution_time の制約を受ける。つまりその値が30秒ということであれば、実行完了まで30秒を超えるタスクは、Maximum execution time of 30 seconds exceeded というメッセージとともにFatal Errorとなる。よってタスク実行専用のサーバーにてtotemを運用する場合は、思い切ってphp.iniの当該パラメータの値に余裕を持たせておくことが望ましい。一方通常のAppサーバーにてtotemを運用する場合は、各プログラム内で set_time_limit(120); というように都度制限時間を変更することが望ましい。

テーブル名の衝突に注意

totemでは、スケジュール管理、結果保存のためにDBに専用テーブルをいくつか作成する。その中には Tasks などといういかにも衝突しそうな名前のテーブルが存在するため、.envTOTEM_TABLE_PREFIXというパラメータを追加の上、totem_などのプレフィックスを設定しておくほうが良い。

テーブル設定のキャッシュ問題

どういうタイミングで起きるかは不明であるが、すでにtotem用のテーブルを作成した後何らかの理由でこれらを削除して作り直そうとすると、以下のようなエラーが発生する。

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'homestead.fuga_task_frequencies' doesn't exist

これは、totemが下記のようにCacheにテーブル情報を格納した結果発生している。
https://github.com/codestudiohq/laravel-totem/blob/2d09bd8c9dd28aa04cfe037298323bf4718bb967/src/Totem.php#L94

したがってCashe先のデータを削除する必要がある。redisの場合はkeys *totem*で関連するキャッシュが見つかるので、それらを指定して削除すれば良い。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelの基礎学習 with XAMPP

この記事の解説は独自の解釈が多いため間違っている可能性もあります。そのような箇所があれば指摘して頂けると幸いです。

目標

Laravelで簡易的なサイトが作れる程度の基礎を習得する

環境

  • Windows 10 home
  • XAMPP
  • Laravel

Laravelの勉強

まずは初心者のためのLaravel入門 - libroを軸に勉強を進めていく。
学習の手順としては入れ替えた方が良い箇所もあるかもしれないが、自分にとって親しみやすい順で進めていく。

Laravelのインストール

Composerのインストール

LaravelのインストールにはComposerというパッケージ管理ツールを使う。
PHPで使用するソフトウェアやアプリケーションをインストールしたい時に、そのソフトウェアなどが動くのに必要な依存関係のある他のソフトウェアなども一緒にインストールしてくれる便利なツール。
Composer 公式からダウンロードして、PATHを通して、ターミナルなどで次のような表示がされればOK。
screenshot.jpg

Laravelインストーラーの導入

Laravelでは設定ファイルやコードなどを1つのプロジェクトとしてまとめて作業を行う。
ディレクトリやフォルダと同じ認識。

では、Laravelのプロジェクトを作成していく。
今後もLaravelプロジェクトを作成することを考えて、ComposerでLaravelインストーラーを導入してからLaravelのプロジェクトを作成する。
Laravelインストーラーは下記のコマンドをターミナル実行して、インストールする。

$ composer global require "laravel/installer"

Laravelインストーラーのダウンロードが終わったら、赤下線部分をエクスプローラーで開く。
screenshot.jpg
そこから~\vendor\binまで移動し、そこまでのパスをコピーする。

C:\(各自のパス)\AppData\Roaming\Composer\vendor\bin

その後、Windows10の左下にある検索窓から「環境変数」を入力してシステム環境変数の編集を開く

システムのプロパティが開けたら下の環境変数(赤枠部)をクリック。
screenshot.jpg

その後、下にあるシステム環境変数(S)からPathを探してダブルクリック。
すると、環境変数名の編集が開けるので、右上の新規をクリックし、先程のパスを貼り付けて、OKを押す。

Laravelプロジェクトの作成

ターミナルに戻り、下記コマンドを実行。

$ laravel new blog(プロジェクト名)

これでLaravelのプロジェクトが作成される。
今後、Laravelのプロジェクトを作成したいときは、$ laravel new (プロジェクト名)をターミナルで実行するだけで作成できるようになった。

作成できたプロジェクトを実際に実行してみる。
ターミナルから以下のコマンドを実行。

$ cd (プロジェクト名)
$ php artisan serve

screenshot.jpg

$ php artisan serveLaravelの内蔵サーバーを起動できる。
つまり、このコマンドを利用することでローカルのアプリケーションとしてプロジェクトの状態確認が可能に。
ターミナルに表示された http://127.0.0.1:8000 にアクセスしてみると、Laravelと中央に大きく書かれたサンプルページが開かれる。
ターミナルでCtrl + Cを押すとサーバーを閉じる。

プロジェクト(フォルダ)構成について

プロジェクトを作成した際、一緒にインストールされたファイルなどはLaravelをスタートしよう(4/5):初心者のためのLaravel入門 - libroに解説が載っている。
ただ、この記事の情報は古いため、必要があれば下記コマンドでLaravelのバージョンなどを確認し、公式ドキュメントなどで各自フォルダ構成について調査を。

$ php artisan --version

ルーティング処理

ルーティング処理: どのアドレスでアクセスされたら、どの処理を返すかを定義するもの

Laravelでは(プロジェクト名)\routes\web.phpでルーティング処理が指定されており、実際にファイルを確認してみると、以下のような宣言がある。

(プロジェクト名)\routes\web.php
Route::get('/', function () {
    return view('welcome');
});

上記のコードをRoute::メソッド(第一引数, 第二引数)として解説を行う。

  • Route: クラス名。::の後に続くメソッドを呼び出して処理を実行する。
  • メソッド: Routeクラスで定義されている処理から、どの処理を実行するかを指定する。ここによって次の第一引数の値が変わる。
  • 第一引数: メソッドによって値が変わる。(例: getメソッドではアドレスを表すテキスト。groupメソッドではアドレス情報をまとめた配列になる)
  • 第二引数: 第一引数にアクセスされた際に返す処理。web.phpではファイル名が指定されているがテキストなども返すことができる。

以上の解説を踏まえて、現在のweb.phpを見てみると、/(ルート)にアクセスされたらview(welcome)を返すルーティング処理であることがわかる。
このルーティング処理で呼び出されるview(welcome)がどこにあるか、どのファイルかという質問に対する答えは、(プロジェクト名)\resources\views\welcome.blade.php

view()関数については次章で説明する。
welcome.blade.phpbladeという見慣れない拡張子があるが、これはLaravelで利用できるテンプレートの仕組み。
この仕組みを利用することで、blade拡張子がついたファイル同士でコードを共有しあったり、Laravelに搭載されている機能を簡単に呼び出したりすることができるようになる。

ルーティング処理についてわかったところで、Hello,World!!を表示するようにweb.phpを変更してみる。
この後の作業で使用するため、変更前のコードをコメントアウトなどして残しておく。

(プロジェクト名)\routes\web.php
Route::get('/', function () {
    return 'Hello,World!!';
});

screenshot.jpg

表示用のファイル(テンプレート)について

web.phpで特定のURLにアクセスされた際の処理を定義できることが分かった所で、その結果を表示するページを作成していく。
今回は簡単なPHPファイルを作成するが、welcome.blade.phpのようなファイルを作成することもある。むしろ、そちらが主流。そのような.blade.php拡張子ファイルはテンプレートと呼ばれ、この先で作成するため覚えておいてほしい。

では、表示用のページとなるファイルから作成していく。
(プロジェクト名)\resources\views\template.phpを作成し、下記の内容にする。

(プロジェクト名)\resources\views\template.php
<!DOCTYPE HTML>
<html>
    <head>
        <title>template</title>
        <style>
            body{color:gray;}
            h1{font-size:18pt; font-weight:bold;}
        </style>
    </head>
    <body>
        <h1>Template</h1>
        <p><?php echo $message; ?></p>
    </body>
</html>

次に、web.phpでこのファイルをを表示するルーティング処理を定義する。

(プロジェクト名)\routes\web.php
Route::get('/template', function () {
    return view('template',['message' => 'Study Template']);
});

ルーティング処理の内容は/templateにアクセスされたらtemplate.phpを返すというものだが、view()の中に連想配列が指定されている。

ここでルーティング処理の所で飛ばしたview()関数の説明をする。
view()関数はview(第一引数, 第二引数)という形をとり、次のように宣言する。

  • 第一引数: ファイル名、テンプレート名を指定する。拡張子を除いた名前を宣言する
  • 第二引数: 第一引数に渡す値などを指定する。今回では連想配列を用いて、template.phpの変数$messageStudy Templateという文字列を渡している。

以上のファイル、ルーティング処理の作成によって表示されるページは次のようなものとなる。
http://127.0.0.1:8000/template

screenshot.jpg

コントローラー

(プロジェクト名)\routes\web.phpにルーティング処理を定義することで、(プロジェクト名)\resources\views\にある表示用のファイルやテンプレートを呼び出せるようになったがある問題が潜んでいる。
それはview()の第二引数を利用する処理が増えると、web.phpのコードが複雑になることだ。
テンプレートの作成では第二引数に指定する連想配列のキーと値は1つだけだったが、web.phpで宣言するルーティング処理が増え、連想配列の数も増えれば見づらく、読みにくいコードとなってしまう。

そのような問題を防ぐために使用されるのがコントローラーだ。
実際に作成しながら解説をしていく。

コントローラーは(プロジェクト名)\app\Http\Controllersに作成する。
今回はその階層にTemplateController.phpというファイルを作成し、次の内容にする。

(プロジェクト名)\app\Http\Controllers\TemplateController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class TemplateController extends Controller
{
    public function getIndex()
    {
        return view('template', ['message' => 'Study Template']);
    }
}
?>

そして、web.phpRoute::get('/template', ~を下記のように変更する。

(プロジェクト名)\routes\web.php
Route::get('/template','TemplateController@getindex');

Routeクラスの第二引数に指定されているTemplateController@getindexTemplateControllergetIndex()メソッドを呼び出すことを宣言している。

TemplateController.phpのようなコントローラーの仕組みを説明をしていく。
新規作成したコントローラーのファイルではuse App\Http\Controllers\Controller;App\Http\Controllers\Controllerというクラスを継承することを忘れずに宣言する。
public function getIndex()で宣言されているgetIndex()は、Route::get()などのGETアクセスでindexというアドレスにアクセスした際に呼び出されるメソッドであることを定義している。
このTemplateController.php自体がweb.phpのルーティング処理において、Route::get()/templateに割り当てられているため、/template/index(トップページ)にアクセスすると、getIndex()が呼び出され、view()で定義した処理が実行される仕組みとなっている。

コントローラーで指定するメソッド(getIndex()など)はHTTPメソッドの種類 + アクセスするアドレスによって名前が自動的に決まるため、このルールを覚えておく必要がある。

http://127.0.0.1:8000/template にアクセスして、エラーが表示されていないか確認。

Requestクラス

ここではRequestクラスを利用して、フォームを使用したページ間でのデータの送受信ができるようにする。
この記事の軸にしていたサイトの情報が古かったので、ここではLaravel5 チュートリアル ブログもどきを作る(2) ブログ記事投稿フォームの作成 - Qiitaをメインに進めていく。

まずはテンプレートの作成から。
GETメソッド以外でフォームを利用する場合、Laravelの仕様でCSRF(ログイン状態で悪意あるURLにアクセスするとログイン情報が盗まれ悪用される事)の対策をしないとエラーが発生する。
その対策として活用できるのがLaravelの機能であるbladeテンプレートだ。
(プロジェクト名)\resources\views\form.blade.phpを作成し、次の内容にする。

(プロジェクト名)\resources\views\form.blade.php
<!DOCTYPE HTML>
<html>
    <head>
        <title>Form</title>
        <style>
            body{color:gray;}
            h1{font-size:18pt; font-weight:bold;}
        </style>
    </head>
    <body>
        <h1>フォームを利用したデータの送受信</h1>
        <p>{{ $message }}</p>
        <form method="POST" action="/form">
            {{ csrf_field() }}
            <input type="text" name="str">
            <input type="submit">
        </form>
    </body>
</html>

{{ }}bladeテンプレートの記法。
{{}}自体は<?php echo ~ ?>の代わりで、{{ csrf_field() }}はこれだけでLaravelにおけるCSRF対策の機能を呼び起こし、利用できる。

続いて、コントローラーを作成する。
(プロジェクト名)\app\Http\ControllersFormController.phpを作成し、次の内容にする。

(プロジェクト名)\app\Http\Controllers\FormController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class FormController extends Controller
{
    public function getIndex(Request $request)
    {
        return view('form', ['message' => 'データを入力してください。']);
    }
    public function postIndex(Request $request)
    {
        $res = "入力内容: ".$request -> input('str');
        return view('form', ['message' => $res ]);
    }
}
?>

postIndex()はテンプレートの章でも説明したように、POSTアクセスでindexに接続した際に実行される処理がそれ以降に記載されている。
そのため、POSTアクセスが行われていない何もデータが入力されていない時に表示する用のページとして、getIndex()のメソッドも作成しておくことも必要。

そして、今回の主題となるのがRequestクラスを利用した(Request $request)だ。
Requestクラスではユーザーからのアクセスを始めとする各種情報を管理している。
その内容を$requestに入れ、今回はinput('str')という形でデータを取り出している。
inputに関するデータはinput(name属性)で取り出せるため、このような記述となる。

(プロジェクト名)\routes\web.phpに次のルーティング処理を追記する。

web.php
Route::get('/form','FormController@getindex');
Route::post('/form','FormController@postindex');

ここで意図した設計で稼働しているか確認してみる。
http://127.0.0.1:8000/form にアクセス。

screenshot.jpg

この状態で送信を押すと、

screenshot.jpg

このように変化する。

Requestクラスの基本(3/5):初心者のためのLaravel入門 - libro 以降ではクエリやURLの取得、リダイレクトについて記載されているため、確認してみては。

データベースとの連携

ここではXAMPPMySQLを利用して、Laravelとデータベースを連携させる。

まずはデータベースの準備から。
XAMPPを起動したら、XAMPPのコントロールパネルにおけるMySQLAdminをクリックして、phpMyAdminに接続する。

screenshot.jpg

phpMyAdminにログインできたら、データベースタブから下記画像のように新規データベースを作成する。(画像ではデータベース名が頭文字が大文字だったが作成したら小文字になった。)
screenshot.jpg

そして、新規テーブルを作成する。
好きな名前とカラム数を設定してテーブルを作成し、
screenshot.jpg

各カラムの設定を行い、
screenshot.jpg

サンプルデータを何個か入れる。
screenshot.jpg

ここまで(↓)設定できたら、次はLaravel側の設定に移る。
screenshot.jpg

今回はMySQLを使用するが、他のデータベースを利用したい場合は、(プロジェクト名)\config\database.phpを開いて、下記の部分を使用したいデータベースに変える。

(プロジェクト名)\config\database.php
'default' => env('DB_CONNECTION', 'mysql'),

どのデータベースを使用するか設定できたら、(プロジェクト名)\.envを開いて、下記にデータベース情報を入力していく。
デフォルトで値が入っているが、必要があれば変更する。

(プロジェクト名)\.env
DB_CONNECTION=
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=

ここからはデータベースに接続し、値を取得、ページに表示するまでを説明していく。

コントローラーの作成から行っていく。
(プロジェクト名)\app\Http\ControllersDatabaseController.phpを作成し、下記の内容にする。

(プロジェクト名)\app\Http\Controllers\DatabaseController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB; 
use App\Http\Requests;
use App\Http\Controllers\Controller;

class DatabaseController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = DB::select('select * from sample');
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>

use DB; を忘れないように注意。
DB::select はデータベースに対してSELECTのクエリ文を実行するための関数。

select以外にもDBクラスにはデータベースを操作するためのメソッドがあり、それらを CRUD処理 と呼ぶ。
CRUD処理 とは、Create(生成) , Read(読み取り) , Update(更新) , Delete(削除) の処理における頭文字を並べたもの。
それぞれのDBクラスにおけるメソッドはCreate(生成) = DB:insert() , Read(読み取り) = DB:select() , Update(更新) = DB:update() , Delete(削除) = DB:delete() となるので覚えておく。

余談となるが、複数人がページやサイトにアクセスしていて、同時にデータベースにCRUD処理を実行した場合、UpdateDeleteが同時に実行する命令が起きるようなデータの不整合が起きる可能性がある。
そのような事態に陥るのを防ぐために行われるのが トランザクション で、DB::beginTransaction(); から DB::commit(); の間に書かれた処理が実行されている間は他の命令が実行されることを防ぐことができるようになる。
本番環境でデータの書き換えを行うような処理を定義する場合は忘れずに記述するようにしておく。

本題に戻って、コントローラーが取得したデータベースのデータを表示するページを作成していく。
(プロジェクト名)\resources\views\database.blade.phpを作成し、下記のような内容に。

(プロジェクト名)\resources\views\database.blade.php
<!DOCTYPE HTML>
<html>
    <head>
        <title>Form</title>
        <style>
            body{color:gray;}
            h1{font-size:18pt; font-weight:bold;}
              th{color:white; background:#999;}
              td{color:black; background:#eee; padding:5px 10px;}
        </style>
    </head>
    <body>
        <h1>Laravelとデータベースの連携</h1>
        <p>{{ $message; }}</p>
        <table>
            <tr>
                <th>ID</th>
                <th>NAME</th>
                <th>PASS</th>
                <th>CREATE_DAY</th>
            </tr>
            @foreach($data as $value)
            <tr>
                <td>{{ $value -> id; }}</td>
                <td>{{ $value -> name }}</td>
                <td>{{ $value -> pass }}</td>
                <td>{{ $value -> create_day }}</td>
            </tr>
            @endforeach
    </table>
    </body>
</html>

@foreach($data as $value)でコントローラーが取得したデータベースの各値が入っている$data$valueに移す。
{{ $value -> (カラム名) }}で各カラムに入っているデータを取得して表示している。

(プロジェクト名)\routes\web.phpに今回のルーティング処理を実装して、実際にページを確認してみる。

(プロジェクト名)\routes\web.php
Route::get('/database','DatabaseController@getindex');

自分の今までに掲載した画像の設定と同じ設定にすれば次のように表示されるはず。
http://127.0.0.1:8000/database

screenshot.jpg

ORM(Object/Relational Mapping)について

さっきは自分でデータベースを作成して値を取得、表示まで行ったが、仕事でも同じような状況で作業ができるとは限らない。
違う人がデータベースを作成する事なんて普通だし、そもそもデータベースを見れずに手探りでデータを取得しなければならないことだってあり得る。
そのような状況で、今までのようなやり方では不都合が多い。

そこでPHPのようなオブジェクト指向言語で用いられる技術が ORM(Object/Relational Mapping) だ。
この技術を用いることで、データベースのテーブルに存在しているデータ、値をPHPのオブジェクトに変換したり、その逆の変換も行えるようになる。
その上、PHP側で用意したクラスを操作するだけで、それに対応するデータベースのテーブルを自動的に操作できるようになるという。

Laravelでは Eloquent というORMが利用できるため早速使用してみる。

最初にテーブルに対応するモデルと呼ばれるクラスの作成を行う。
ターミナルでプロジェクトのトップディレクトリに移動し、下記コマンドを実行。
自分はどのテーブルを扱うのかわかりやすいよう、テーブル: sampleに対し、モデル: Sampleを作成した。

 $ php artisan make:model Sample(モデル名)

上記のコマンドが成功すると、(プロジェクト名)\appSample(モデル名).phpが作成されているので、開いて確認してみると次のような内容になっている。

(プロジェクト名)\app\Sample(モデル名).php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
    //
}

//とコメントアウトにされている箇所があるが、そこを protected $table = 'sample'; に変更して、使用するテーブル名を定義する。
protectedを付けることで、そのクラス自身と継承したクラス限定でアクセスが可能となるため、テーブルを保護するためにも欠かさずに付与する。
モデルの作成はこれで完了。コントローラーの作成に移る。

(プロジェクト名)\app\Http\ControllersORMController.phpを作成し、下記の内容を入力する。
データベースとの連携で使用した表示用のファイル(プロジェクト名)\resources\views\database.phpを使用するため、view()関数の第一引数はdatabaseにする。

(プロジェクト名)\app\Http\Controllers\ORMController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Sample; 
use App\Http\Requests;
use App\Http\Controllers\Controller;

class ORMController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = Sample::all();
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>

use App\Sample; で今回作成したモデルを使用することを宣言。
Sample::all() では、Sampleクラスでモデル: Sampleに対応しているテーブル: sampleの全データをallメソッドを使用して取得している。

一回ここで、モデルなどが問題なく使えているか確かめる。
(プロジェクト名)\routes\web.phpにルーティング処理を実装し、実際にページを確認してみる。

web.php
Route::get('/orm','ORMController@getindex');

http://127.0.0.1:8000/orm にアクセスしてみて、http://127.0.0.1:8000/database と同じ内容が表示されているか確かめる。
screenshot.jpg

all の他にもデータベースにおける処理に関するメソッドがモデルクラスには用意されている。
その中の一つが検索機能の where だ。
whereモデル名::where(カラム名, 取得したい値) でテーブルに検索をかけて、 get() でその結果を取得する。
コントローラーに実装して、試してみるとそれぞれ次のようになる。

ORMController.php
class ORMController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = Sample::where('id', 2)->get();
        return view('database', ['message' => 'データベース名: sample','data' => $data]);
    }
}
?>

screenshot.jpg

検索を実行できるwhereには様々な使い方がある。
>likeといった演算子を使いたい場合は where(カラム名, 演算子, 取得したい値)and条件なら where(条件1) -> where(条件2)or条件なら where(条件1) -> orWhere(条件2) という風になる。
データベースから値を取得する機会は多いので、少なくともこれらだけでも覚えておきたい。

Laravelからデータベースのデータを操作する

CRUD処理 において、Readに関してはORMwhereで触れたが、CreateUpdate,Deleteがまだなので、今回はそれらに触れていく。

前準備

ORMの際に作成したモデルに2つのコードを追加する。

(プロジェクト名)\app\Sample(モデル名).php
class Sample extends Model
{
    protected $table = 'sample';

    protected $guarded = array('id');

    public $timestamps = false;
}

protectedはテーブルだけでなく、データも保護できる。
protected $guarded = array('id');主キーを保護する。
更新や削除の際にprotectedで保護されていないと、連携しているテーブルにも影響を与えてしまう。
それらを防ぐためにもテーブルや主キーには protectedで忘れずに保護をかける。

Laravelでデータベースにデータを作成、追加する際、create_at,update_atという、それぞれ作成日時と更新日時を示す項目が自動的に作成される。
今回利用するテーブルではこれらの項目を設けていないため、何もしない状態でデータベースにデータを作成、追加してしまうと、エラーの原因となる。
それを防ぐのが public $timestamps = false; の部分。
このコードを追加することで、データベースにデータを作成、追加する際にcreate_at,update_atが生成されなくなる。
データベースにデータを作成、追加する処理をLaravelに実装する際は、このコードを追加するかテーブルにcreate_at,update_atカラムの作成を忘れないように。

Create

表示用のページとして(プロジェクト名)\resources\views\create.blade.phpを作成し、次のような内容に。

(プロジェクト名)\resources\views\create.blade.php
<!DOCTYPE HTML>
<html>
<head>
    <title>CRUD</title>
    <style>
    body{color:gray; }
    h1{font-size:18pt; font-weight:bold;}
    th{color:white; background:#999;}
    td{color:black; background:#eee; padding:5px 10px;}
    </style>
</head>
<body>
    <h1>LaravelからのCRUD処理</h1>
    <p>{{ $message }}</p>
    <table>
            <tr>
                <th>ID</th>
                <th>NAME</th>
                <th>PASS</th>
                <th>CREATE_DAY</th>
            </tr>
            @foreach($data as $value)
            <tr>
                <td>{{ $value -> id }}</td>
                <td>{{ $value -> name }}</td>
                <td>{{ $value -> pass }}</td>
                <td>{{ $value -> create_day }}</td>
            </tr>
            @endforeach
    </table>
    <table>
    <form method="post" action="/create">
        {{ csrf_field() }}
        <tr><td>NAME:</td><td><input type="text" name="name"></td></tr>
        <tr><td>PASS:</td><td><input type="text" name="pass"></td></tr>
        <tr><td>CREATE_DAY:</td><td><input type="text" name="day"></td></tr>
        <tr><td></td><td><input type="submit"></td></tr>
    </form>
    </table>
</body>
</html>

大まかな内容としては、テーブルのデータを表示して、postで作成するデータを送信するというもの。

IDに値する内容を入力するフォームを作成していないが、これはデータベースのAUTO_INCREMENTを利用しているため。
AUTO_INCREMENTとは他のデータが挿入された際に、適用しているカラムに自動でデータを入力してくれるデータベースの機能。
この機能を適用させるには、phpMyAdminを開いて、AUTO_INCREMENTを適用したいカラムを選択して、変更をクリック。
screenshot.jpg

その後、A_Iの下のチェックボックスにチェックを入れ、保存。
screenshot.jpg

もし、使用しない場合はIDの値を入力するフォームを作成を忘れないように。

postから投げられたデータはコントローラーでデータベースのテーブルに挿入する。
その処理は以下のような内容。

(プロジェクト名)\app\Http\Controllers\CreateController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use DB; 
use App\Sample; 
use App\Http\Requests;
use App\Http\Controllers\Controller;

class CreateController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = DB::select('select * from sample');
        return view('create', ['message' => 'Create処理を実行する','data' => $data]);
    }

    public function postIndex(Request $request)
    {
        $name = $request -> input('name');
        $pass = $request -> input('pass');
        $day = $request -> input('day');
        $data = array(
            'name' => $name,
            'pass' => $pass,
            'create_day' => $day
        );
        Sample::create($data);
        return redirect()->action('CreateController@getindex');
    }
}
?>

データベースのテーブルにデータを作成する処理、Createではモデル名::create()メソッドを使用する。

getIndex() はデータベースの連携の際の内容と同じなので説明を省略。

postIndex()postが実行されたときに行われる処理を示している。
inputに入力されたname,pass,day$dataという連想配列に格納して、モデル名::create($data)$dataの内容をデータベースのテーブルに格納。
その後、getIndex()にリダイレクトするという流れになっている。

最後に(プロジェクト名)\routes\web.phpに下記のルーティング処理を実装し、実際にページを確認してみる。

(プロジェクト名)\routes\web.php
Route::get('/create','CreateController@getindex');
Route::post('/create','CreateController@postindex');

post
screenshot.jpg

post後(IDの5,6が抜けてるのは作成中にエラーの対応をしていたため)
screenshot.jpg

Update

表示用のページとして(プロジェクト名)\resources\views\update.blade.phpを作成し、form以下を次の内容に。
それ以外はCreateで作成したcreate.blade.phpと同じ。

(プロジェクト名)\resources\views\update.blade.php
    <form method="post" action="update">
        {{ csrf_field() }}
        <tr>
            <td>ID:</td>
            <td>
                {{ optional($data)->id }}
                <input type="hidden" name="id" value="{{ optional($data)->id }}">
            </td>
        </tr>
        <tr>
            <td>NAME:</td>
            <td><input type="text" name="name" value="{{ optional($data)->name }}"></td>
        </tr>
        <tr>
            <td>PASS:</td>
            <td><input type="text" name="pass" value="{{ optional($data)->pass }}"></td>
        </tr>
        <tr>
            <td>CREATE_DAY:</td>
            <td><input type="text" name="day" value="{{ optional($data)->create_day }}"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit"></td>
        </tr>
    </form>

id以外の各カラムの更新内容を入力するフォームを作成。

optional()引数に指定したオブジェクトにアクセスしたり、そのプロパティを取得する 関数。
オブジェクトがnullの時はnullを返す。

postから投げられたデータをデータベースに更新する処理を記述するコントローラーのclass以下は次のような内容。
classより上はCreateで作成したcreate.blade.phpと同じ。

(プロジェクト名)\app\Http\Controllers\UpdateController.php
class UpdateController extends Controller
{
    public function getIndex(Request $request)
    {
        $id = $request -> id;
        $table = DB::select('select * from sample');
        $data = Sample::find($id);
        $msg = 'Update  Sample Table [id = ' . $id . ']';
        return view('update', ['message' => $msg,'Table' => $table,'data' => $data]);
    }

    public function postIndex(Request $request)
    {
        $id = $request -> input('id');
        $data = Sample::find($id);
        $data -> name = $request -> input('name');
        $data -> pass = $request -> input('pass');
        $data -> create_day = $request -> input('day');
        $data->save();
        return redirect()->action('UpdateController@getindex');
    }
}

$id = $request -> id;URLにおけるクエリパラメータ(~/~?id=123などの?以降の部分)を取得している。
そこで取得した$idモデル名::find() の引数に使用することで、引数に一致するレコードをデータベースから取得し、$dataなどのインスタンスに格納できるようにしている。
データベースのテーブルにおけるデータを更新する際は save() メソッドを使用する。

(プロジェクト名)\routes\web.phpに下記のルーティング処理を実装し、実際にページを確認してみる。

(プロジェクト名)\routes\web.php
Route::get('/update','UpdateController@getindex');
Route::post('/update','UpdateController@postindex');

post前: http://127.0.0.1:8000/update?id=7
フォームの内容を変更したい内容に変えてある。
screenshot.jpg

post
screenshot.jpg

Delete

表示用のページとして(プロジェクト名)\resources\views\delete.blade.phpを作成し、formを次の内容に。
それ以外はCreateで作成したcreate.blade.phpと同じ。

(プロジェクト名)\resources\views\delete.blade.php
    <form method="post" action="update">
        {{ csrf_field() }}
        <tr>
            <td>削除したいレコードのID:</td>
            <td>
                <input type="text" name="id" value="{{ optional($data)->id }}">
            </td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit"></td>
        </tr>
    </form>

削除したいレコードのIDを入力するフォームと送信ボタンだけでOK。

指定されたレコードをデータベースから削除する処理を記述するDeleteController.phpは次のような内容。
classより上はCreateで作成したcreate.blade.phpと同じ。

(プロジェクト名)\app\Http\Controllers\DeleteController.php
class DeleteController extends Controller
{
    public function getIndex(Request $request)
    {
        $data = DB::select('select * from sample');
        return view('update', ['message' => 'レコードの削除','data' => $data]);
    }

    public function postIndex(Request $request)
    {
        $id = $request -> input('id');
        $data = Sample::find($id);
        $data -> delete();
        return redirect()->action('DeleteController@getindex');
    }
}

Create,Updateで使用したコントローラーの内容がわかっていれば $data -> delete(); 以外説明することもない。
$data -> delete();Updateで使用したsave()メソッドと同じような使い方をして、そのデータを削除する使い方をするものだという覚え方で問題はない。

いつも通り、(プロジェクト名)\routes\web.phpに下記のルーティング処理を実装し、実際にページを確認してみる。

(プロジェクト名)\routes\web.php
Route::get('/delete','DeleteController@getindex');
Route::post('/delete','DeleteController@postindex');

post前: http://127.0.0.1:8000/delete
screenshot.jpg

post
screenshot.jpg

番外編: バリデーション

CRUD処理の番外編としてバリデーションにも触れていく。
この機能は入力内容をチェックし、設定した条件を満たしているかどうかを判断するもので実装する方法は複数あるが、今回はフォームのバリデーションを実装する。
フォームのバリデーションはLaravelにおいて、フォームリクエストと呼ばれる。
今回はUpdateで使用したファイル達に、このフォームリクエストを適用していく。

フォームリクエストは以下のコマンドをターミナルで実行して作成する。

$ php artisan make:request UpdateRequest(作成したいファイル名)

処理が完了すると(プロジェクト名)\app\Http\RequestsUpdateRequest(作成したいファイル名).phpが作成される。
UpdateRequest(作成したいファイル名).phpの各メソッドを次のように変更する。

(プロジェクト名)\app\Http\Requests\UpdateRequest(作成したいファイル名).php
public function authorize()
    {
        return true;
    }

public function rules()
    {
        return [
            'name' => 'required|string|max:10',
            'pass' => 'required',
            'day' => 'required|string|max:10',
        ];
    }

バリデーションする条件の指定は、このように連想配列の形をとる。
どのような条件が指定できるかは公式ドキュメントに記載されているため、必要があれば確認を。

そしたら、(プロジェクト名)\app\Http\Controllers\UpdateControllers.phpに作成したバリデーションを適用させていく。

(プロジェクト名)\app\Http\Controllers\UpdateControllers.php
use App\Http\Requests;
use App\Http\Requests\UpdateRequest;

// 中略 

    public function postIndex(UpdateRequest $request)
    {

変更といっても、useの箇所に use App\Http\Requests\UpdateRequest; を追加、public function postIndex(Request $request)public function postIndex(UpdateRequest $request) に変えるだけ。

これで http://127.0.0.1:8000/update?id=4 にアクセスして、フォームの中を全て空にして送信を押すと、最初の状態に戻り、バリデーションが効いていることがわかる。

ただ、エラーメッセージもなしに画面が遷移するのはわかりにくいので、表示用のページである(プロジェクト名)\resources\views\update.blade.phpも変更する。

(プロジェクト名)\resources\views\update.blade.php
// 略

    .alert{color:red;}
    </style>
</head>

// 中略


 </table>
    @if ($errors->any())
        <div class="alert">
          <ul>
              @foreach ($errors->all() as $error)
                  <li>{{ $error }}</li>
              @endforeach
          </ul>
        </div>
    @endif
</body>

これでバリデーションが適用された際、どのフォームが条件を満たしていないかが赤字で表示されるようになった。
image.png

Laravelからテーブルを操作する

ここまででLaravel側からデータベースのテーブルに対する操作ができることを学んだが、Laravelではテーブルそのものを作成することもできる。

ここからはLaravel入門 - 使い方チュートリアル - - QiitaLaravel5 チュートリアル ブログもどきを作る(1) DB設定・マイグレーション - Qiitaシリーズを軸に進めていく。

マイグレーション

Laravelのテーブルそのものを作成する仕組み、それが マイグレーション だ。

まずはデータベースにテーブルを作成するためのマイグレーションファイルを作成するところから始まる。
今回はlaravelsというテーブル名で、それを作成するためのマイグレーションファイルを以下のコマンドをターミナルに入力して作成する。
テーブル名の最後にsを忘れないように

$ php artisan make:migration laravels(作成したいマイグレーションファイル名) --create=laravels(作成したいテーブル名)

そうすると、(プロジェクト名)\database\migrations2020_08_06_095118_laravels(作成したいマイグレーションファイル名).phpが作成される。

(プロジェクト名)\database\migrations\2020_08_06_095118_laravels(作成したいマイグレーションファイル名).php
<?php

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

class Laravels extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('laravels', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

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

public function up() にはテーブルを作成するときの処理が、public function down() にはテーブルを削除する処理が記載されている。
このまま、このファイルを実行してもテーブルを作成してもよいが、次のように少しカラムの設定を宣言してみる。

(プロジェクト名)\database\migrations\2020_08_06_095118_laravels(作成したいマイグレーションファイル名).php
    public function up()
    {
        Schema::create('laravels', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 10);
            $table->timestamps();
        });
    }

この状態でmigrationが実行されると、次の設定が反映されたカラムになる。

カラム名 設定 
id AUTO_INCREMENT
name VARCHAR(10)
create_at timestamp
update_at timestamp

上でも説明したように、create_atupdate_atのカラムは自動で作成され、AUTO_INCREMENTは自動挿入、timestampは日時が自動で挿入される機能。

では、このファイルを実行して、テーブルを作成してみる。

ターミナルに次のコマンドを入力することで、マイグレーションファイルが実行される。

$ php artisan migrate

phpMyAdminで確認してみる。
image.png

migrateテーブルを作成するpublic function up()の処理が行われた。
public function down()の処理はmigrate:rollbackmigrate:resetで実行する。

migrate:rollback最後に行ったマイグレーション操作を取り消す
migrate:reset全てのマイグレーションを削除する

シーディング

シーディング はテーブルの初期化やテストデータとなるレコードを挿入するLaravelの仕組み。
今回はこの仕組みを利用して、マイグレーションで作成したmigrationテーブルを初期化(最初のデータを挿入)する。

シーディングマイグレーション同様、ファイルの作成から始めるが、その前にマイグレーションで作成したテーブルに対応するモデルの作成を行う。

$ php artisan make:model laravel(テーブル名の最後のs抜き)

マイグレーションの時のテーブル名における最後の文字にsを付けてもらった理由がここにある。
モデル名はテーブル名の単数形にすることで自動的にテーブルを判断する機能がある。
テーブル名: 複数形モデル名: 単数形の命名規則を忘れないように。

ファイルを編集する必要はないので(プロジェクト名)\app\laravel(テーブル名の最後のs抜き).phpがあるのを確認すればOK。

その後、ターミナルで下記のコマンドを実行。

$ php artisan make:seeder StudySeeder(作成したいシーディングファイル名)

そうすると、(プロジェクト名)\database\seedsStudySeeder(作成したいシーディングファイル名).phpが作成される。

(プロジェクト名)\database\seeds\StudySeeder(作成したいシーディングファイル名).php
<?php

use Illuminate\Database\Seeder;

class StudySeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

migrationテーブルに挿入するデータは下の表。

id name create_at update_at
1 Laravel 作成日時 作成日時
2 Migration 作成日時 作成日時
3 Seeding 作成日時 作成日時

StudySeeder(作成したいシーディングファイル名).phpで、この表の内容を入力できるようにするには次の内容にする。

(プロジェクト名)\database\seeds\StudySeeder(作成したいシーディングファイル名).php
public function run()
    {
        DB::table('laravels')->truncate();

        $table_data = [
            ['name' => 'Laravel'],
            ['name' => 'Migration'],
                ['name' => 'Seeding']
        ];

        foreach($table_data as $data) {
            \App\laravel::create($data);
        }
    }

DB::table('laravels')->truncate(); でシーディングの対象となるテーブルの指定と初期化。
$migrationdata~ には連想配列の形式で入力したいレコードのデータを挿入。id,create_at,update_atは自動挿入されるようにテーブル側で設定されているため、nameカラムだけ指定。
foreach($table_data as $data)~ で挿入するデータを一つずつテーブルに挿入していく。
\App\laravel::create();laravel部分は各自のモデル名に。

シーディングではコマンド実行時に同じディレクトリにあるDatabaseSeeder.phpを実行するため、このファイルも編集する。

(プロジェクト名)\database\seeds\DatabaseSeeder.php
public function run()
    {
        $this->call(StudySeeder::class);
    }

StudySeederの部分を各自のシーディングファイル名に変更。

以上で設定は終わりなのでシーディングを実行してみる。
シーディングの実行はターミナルで次のコマンドを叩く。

$ php artisan db:seed

phpMyAdminを確認してみる。
image.png

Laravelシステム作成手順

今回の学習を踏まえてLaravelの作成手順をまとめる。

0. (プロジェクト名)\.envにデータベース設定を記述
1. マイグレーションでテーブルを作成
2. シーディングでテーブルにデータ挿入
3. (プロジェクト名)\resources\views\に表示用のファイル、bladeテンプレートを使用したファイルを作成
4. (プロジェクト名)\app\Http\Controllers\に3で作成したファイルへデータなどを渡すコントローラーを作成
5. バリデーション作成
6. (プロジェクト名)\routes\web.phpでルーティング処理

おわりに

今回はLaravelで簡易的なサイトが作れるようになるまでの基礎を学んだ。
Laravelにはもっと多くの機能があり、この記事では触れられていないことが多い。
下記の参考資料などを参考に学習を進めていき、自分が作成したいサイトやシステムをLaravelで実装できるようにしていく。

参考資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

使用してきた関数(メソッド)を忘れないように記載していくよ(PHP版 随時更新)

はじめに

今まで使用してきたメソッド
これから使用してみるメソッド
忘れないように、随時更新していきます。

時間の都合上、
コードは載せる場合と、
載せない場合があります。

例)
▶︎ メソッド

意味:

参考コード

雛形

一つ一つ書くのが手間なので、
雛形を書かせていただきました!

書いていきます٩( ᐛ )و

▶︎ is_null

意味:nullであればtrue,それ以外であればfalseを返す

参考コード

<?php

$value = NULL;

if (is_null($value)){
  echo 'NULLです。';
}else{
  echo 'NULLではありません。';
}

実行結果
//NULLです。
?>

▶︎ asset

意味:「publicディレクトリ」のパスを返すヘルパ関数
    ヘルパとはviewファイルで使えるメソッドのことです。
    現在のURLのスキーマ(httpかhttps)を使い、
    アセットへのURLを生成するメソッド

参考コード

<img src="{{ asset('storage/image/' . $headline->image_path) }}">
//保存した画像のファイル名が $head->image_pathに入っていることを想定
//このことで「.」を使用して、画像のパスを返していることになります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelの学習備忘録 その3

プログラマー初心者です。
Laravelを触って頑張っています。
Laravelでアプリを作りながら学んだことを雑多に記していきます。
記事の正確性は低めです。なので、各項目ごとの参考を参照したほうが良いと思います。
それでは!

バリデーション

参考:ドキュメント「バリデーション」
Laravelではバリデーションの方法がいくつかあるようだ。
- validate()メソッドを使う
- FormRequestを使う←おすすめとのこと。

FormRequestを使う方法は、学習済み。

validateメソッドの方法でも試してみよう。
やりかたは、コントローラの中で、$requestを受けるときに、
$validated_date = $request->validate([バリデーションルールを記述]);
でオッケー。簡単。

でも、FormRequestを使おう。なぜなら、コントローラーをすっきりさせて、見通しを良くしたいから。
また、より複雑なロジックを組める。

$fillableか$guardedか

参考:Qiita「僕がLaravelのEloquentに$fillableでなく$guardedを指定する理由」
\$fillableで指定したもののみ代入可能(ホワイトリスト化)。
\$guardedは指定したものが代入不可能(ブラックリスト化)。
記事の内容が僕にはまだ理解しづらかったので、とりあえず今はfillableをつかう。

中間テーブル

参考:Qiita「中間テーブルとは」
- 多対多のテーブル同士のリレーションだと、お互い関係させようとすると、カラムが無駄に多くなったり、空白になってしまう。
- 例:articlesテーブルとtagsテーブルがあるときに、例えば、articlesタグにtagカラムをつけようとすると、1つの記事にタグをつけたいけど、いくつつくかわからないし、tagカラムがいっぱい作っておかないといけないし、空白フィールドもできて管理しづらくなる。
そこで間に1つテーブル入れることで、空白のカラムをつくることなく、管理しやすくなる。詳しくは上の参考を見るのが一番いい。
- なお、laravelで中間テーブルのマイグレーションを作るときは、単数形で!

マイグレーションでのつまづき

複数形

テーブル、マイグレーション作成時に複数形にするとLaravelではきちんと関係性を読み込んでくれるのだが、複数形にするときに困ったのが、'diary'の複数形。
'diarys' or 'diaries' どっちだ。

答えはdiaries

'diarys'で最初作ったら、マイグレートのときにエラーが出て先に進めなかった。やり直して、diariesでいったら、通った。単数形にsをつけるだけじゃないんだね。英語の初歩って感じだけど、複数形の法則ってちゃんとデータベースに仕組みが入っているのね。

マイグレーションファイルの作成順番

外部キー制約させたい元のテーブルのマイグレーションファイルは先に作っておかないと、エラーがでるので、マイグレーションの順番にもちょっと注意が必要。
よく考えてみれば、日付が新しい順から実行してマイグレーションupするんだから、「外部キーがないよ」ってなるのは当たり前か。
一気にマイグレーションファイルを作ってからマイグレートでいいけど、ファイルの作成順番が大事ということで。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】生SQLの書き方

はじめに

Laravelで複雑な生SQLを書きたい時ってありますよね
Eloquentで書くのも、クエリビルダでも面倒だなという時です

生のSQLの書き方が中々見つからなかったり、別の書き方ではうごかなったりだったので、残しておきます。

書き方

これだけです。

sql.php
DB::select(

 // 生のSQL文

);

パラメータや変数の値をSQL分に含めたい時は、以下の通り。

sql.php
$user_id = $request['user_id'];

DB::select(

 // 生のSQL文

 :user_id

 // 生のSQL文

, ['user_id' => $user_id]);

SQL文中に変数を代入する部分は、「:変数名」としてあげて、連想配列の形で定義済み変数を渡して上げましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでユーザーの生年月日をちゃんと表示する

ユーザーの生年月日をdate型でデータベースに保存するようにします

そのまま表示しようとすると

1998-09-25

みたいな表示になるので

format関数を使って○月○日みたいな表示を可能にさせます

モデルの変更

対象となるモデルに記述(ここではUser.php)

User.php
protected [
  'birthday'
]

## 表示させたいカラムを指定

はいこれだけ、
これでformat関数が使えます


あとは指定すれば

<p>{{ $user->birthday->format(Y年m月d年) }}</p>

こう表示される

1998年09月25日

モデルに設定を記述しないとエラーが出る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのタスクスケジュールが動かない(24時設定)

昨日まで動いていたのに、今日は動かない・・・
昨日のリリースが悪いのかしら。。でも何も悪いことしていないのに・・・

スケジュール定義を見直そう

スケジュールタスクは全部App\Console\Kernelクラスのscheduleメソッドの中に定義します。
この定義でミスしていました。
毎日24時に実行したいからって

$schedule->command('cms:update-article-point')->dailyAt('24:00');

と書くと落ちます。こんなログを吐いて死にます。

In CronExpression.php line 155:
  Invalid CRON field value 24 at position 1

このように書きましょう。

$schedule->command('cms:update-article-point')->dailyAt('00:00');
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Strategyパターン】Laravel で( ゚ェ゚)・∵.ゴフッ

TwitterAPIを使ったサービス作っている際に使ったので記録

Strategyとは

普通にプログラミングしていると、メソッドの中に溶け込んだ形でアルゴリズムを実装してしまうことがよくあStrategy パターンは、コンピュータープログラミングの領域において、アルゴリズムを実行時に選択することができるデザインパターンである。
Strategy パターンは、アプリケーションで使用されるアルゴリズムを動的に切り替える必要がある際に有用である。Strategy パターンはアルゴリズムのセットを定義する方法を提供し、これらを交換可能にすることを目的としている。Strategy パターンにより、アルゴリズムを使用者から独立したまま様々に変化させることができるようになる。
参考:Wiki

クラス図

wiki

TwitterAPIを用いて、いいね、リツイート、ミュートをする処理を書きたい

まずはインターフェースをつくる
handleメソッドでツイートに対する処理をする

app/Strategy/Interfaces/ActionInterface.php
<?php

namespace App\Strategy\Interfaces;

interface ActionInterface
{
    public function handle($tweetId);
}

こいつからいいねクラスなどを実装する

app/Strategy/Favorite.php
<?php

namespace App\Strategy;

class Favorite implements ActionInterface
{
    protected $service;
    public function __construct(TwitterApiService $service)
    {
        $this->service = $service;
    }

    public function handle($tweetId)
    {
        return $this->service->postFavorite($tweetId);
    }
}

app/Strategy/Retweet.php
<?php

namespace App\Strategy;

class Retweet implements ActionInterface
{
    protected $service;
    public function __construct(TwitterApiService $service)
    {
        $this->service = $service;
    }

    public function handle($tweetId)
    {
        return $this->service->postRetweet($tweetId);
    }
}

app/Strategy/Mute.php
<?php

namespace App\Strategy;

class Mute implements ActionInterface
{
    protected $service;
    public function __construct(TwitterApiService $service)
    {
        $this->service = $service;
    }

    public function handle($tweetId)
    {
        return $this->service->postMute($tweetId);
    }
}

TwitterApiServiceで、APIでのあれこれを処理して呼び出す感じで書いてます

次にコンテキストクラスを作ります

コンテキストとは、プログラムの実行に必要な各種情報のことである。
「context」(コンテキスト)は、「文脈」、「前後関係」などと訳されるが、IT用語としては意味がイメージしづらく、単にコンテキストとある場合は、何らかの制御情報と考える方がわかりやすいことが多い。

app/Strategy/Context.php
<?php

namespace App\Strategy;

class Context
{
    private $action;

    public function __construct(ActionInterface $action)
    {
        $this->action = $action;
    }

    public function execute($tweet)
    {
        return $this->action->handle($tweet);
    }
}

使う
画面側からツイートのID入力欄があるみたいなイメージでの実装

<?php

namespace App\Http\Controllers;

use App\Strategy\{Context,Favorite};

class TestController extends Controller
{
    public function index(Request $reqest)
    {
        // いいねしたい!
        $action = app()->make(Favorite::class);

        $context = new Context($action);
        $context->handle($request->tweetId);
    }
}

蛇足

実際今作ってるやつでは、Laravel-enumで
処理してました
良いか悪いかはわからない

<?php

namespace App\Enums;

use App\Strategy\Favorite;
use App\Strategy\Follow;
use App\Strategy\Retweet;
use BenSampo\Enum\Contracts\LocalizedEnum;
use BenSampo\Enum\Enum;

final class TaskType extends Enum implements LocalizedEnum
{
    const Follow = 0;
    const Favorite = 5;
    const Retweet = 10;

    public static function getAction(int $param)
    {
        switch ($variable) {
            case $param === self::Follow:
                return app()->make(Follow::class);
            case $param === self::Favorite:
                return app()->make(Favorite::class);
            case $param === self::Retweet:
                return app()->make(Retweet::class);
            default:
                return app()->make(Follow::class);
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む