- 投稿日:2020-08-07T21:30:10+09:00
AWSでLAMP環境を構築して、Laravelアプリをデプロイする
今回はAWSのEC2、RDSを用いてLAMP環境を構築して、Laravelアプリをデプロイする手順を紹介します。
今回の流れ
1.RDSを用いてDBサーバー作成
2.EC2を用いてWEBサーバーを作成
3.サーバー間の連携
4.アプリのデプロイ前提条件
・Macを使用
・AWSアカウントを作成済みであること
・GitHubのリモートリポジトリに、開発済みのLaravelアプリが置いてあること1.RDSを用いてDBサーバー作成
コンソールにサインインした後、AmazonRDSに移動します。
続いてオレンジ色のCreate databaseボタンをクリックします。
使用するデータベースエンジンを選びます。今回はMySQLを選択します。
バージョンはよしなに選択してください。
今回は無料利用枠のものを作成します。
本番環境の場合は適したプランを選択してください。
インスタンス名、マスターユーザー名、パスワードを設定します。
後ほど使いますので、安全な場所にメモしておきましょう。
インスタンスのスペック、ストレージの容量等を設定します。
今回はデフォルト設定で進めますが、本番環境の場合はよしなに選択してください。
ネットワークの設定を行います。
VPCを作成済みの方は作成したVPCを、そうでない方はデフォルトのVPCを設定しましょう。
最後にオプションの設定をします。
RDSインスタンス初期化時に自動で作られるデータベースの名前を設定します。
今後データベースに接続する際は、ここで設定したデータベース名を使用します。
オレンジ色のCreate databaseボタンをクリックして設定したデータベースを作成します。
2.EC2を用いてWEBサーバーを作成
コンソールからAmazon EC2に移動して、青色のLaunch Instanceボタンをクリックします。
使用するマシンのイメージを選択します。
今回はAmazon Linux 2 AMIを用います。
EC2インスタンスタイプを設定します。
CPU、メモリ、ストレージ、ネットワークパフォーマンス等を考慮してよしなに選択します。
今回はt2.microを選択します。(無料利用枠の対象です)
詳細の設定です。
VPCやサブネット等を設定できますが、今回はとりあえずVPCのみ設定しておきます。
RDSで設定したものと同じVPCを選択してください。
ストレージの設定をします。
他にインスタンスを作成されない場合は30GBまでは無料枠です。
今回はデフォルトの8GBで進めていきます。
続いてタグの設定ですが今回は未設定のまま進み、セキュリティグループの設定をします。
EC2インスタンスへのアクセス許可、制限を指定します。
まずはSSH接続の設定です。
Create a new security groupを選択し、新しいグループを作成します。
TypeのプルダウンからSSHを選択し、SourceのプルダウンからはMyIPを選択しましょう。
次にHTTP接続です。
Add Ruleをクリックした後、TypeのプルダウンからHTTPを選択し、SourceのプルダウンからはMyIPを選択しましょう。
今回は自分のIPからのみ接続できる設定にします。
本番環境で不特定多数のアクセスを集める場合はHTTPのSourceをAnywhereにしてください。
Review and Launchをクリックし確認画面に遷移し、設定内容に問題がなければLaunchをクリックしましょう。
最後に、SSH接続するためのキーペアを作成します。
Create new key pairを選択し、キーペアの名前を設定します。
設定後、Download Key Pairをクリックして.pemファイルをダウンロードします。
このファイルがなければSSH接続できないので、安全な場所で保管してください。
青色のボタンLaunch Instanceをクリックしてインスタンスを起動します。
3.サーバー間の連携
まずは先に作成したRDSの設定を変更し、EC2インスタンスからRDSインスタンスへのアクセスを可能にします。
AmazonRDSに移動します。
左側のダッシュボードのDatabasesをクリックして、先に作成したデータベースを選択します。
Connectivity & securityタブのセキュリティグループをクリックします。
デフォルトではEC2インスタンスからRDSインスタンスへのアクセスは許可されていません。
Inboundタブを開きeditをクリックしてセキュリティグループの編集を行います。
TypeをMySQL/Auroraに、SourceをCustomeに設定し先ほど作成したEC2のセキュリティグループの名前を入力します。
利用可能なセキュリティグループが表示されるので、先ほど作成したものを選択します。自動で値が入力されます。
青色のSavaボタンをクリックし設定を反映させます。
続いてEC2インスタンスにSSH接続していきます。
ターミナル上のキーペアがあるディレクトリで以下のコマンドを実行します。ssh -i .pemファイル名 ec2-user@パブリックIPパブリックIPは、接続するインスタンスのこちらをコピーペーストしましょう。
EC2インスタンスにSSH接続できたら、RDSに接続するための準備をしていきます。
MySQLをインストールしたいのですが、MariaDBがデフォルトでインストールされていると競合してしまうので、アンインストールしておきます。$ sudo yum remove mariadb-libsMySQLのリポジトリを追加して、MySQLをインストールします。
$ sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm $ sudo yum install mysqlMySQLのホスト名を環境変数に設定して、データベースに接続します。
エンドポイントはRDSインスタンスのホスト名を入力します。
ユーザー名、パスワード、DB名は先に作成したものです。$ export MYSQL_HOST=エンドポイント $ mysql --user=ユーザー名 --password=パスワード DB名
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アドレスにアクセスして、以下の画面が表示されていればインストール成功です。
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 URLApacheの設定を変更していきます。
/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アドレスにアクセスすれば、アプリケーションが動作しているはずです!
ここまでお疲れ様でした。
- 投稿日:2020-08-07T21:25:41+09:00
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
百聞は一見にしかず。以下はタスク一覧。他の画面を見たい人はコチラ。
認証
web上に公開されている画面となるため、認証は必須である。ただしlaravel-totemが提供するのは認証の一部分のみである。どういうことかは以下のコードを見てもらえばおわかりいただけるだろう。要は既存の認証機能を使い、結果だけをlaravel-totemに連携せよということである。
AppServiceProvider.phppublic function boot() { Totem::auth(function($request) { // return true / false . For e.g. return Auth::check(); }); }あるいは、特定のIPアドレスからのみアクセスを許可するといったケースにも簡単に対応できる。
AppServiceProvider.phpuse 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
などといういかにも衝突しそうな名前のテーブルが存在するため、.env
にTOTEM_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*
で関連するキャッシュが見つかるので、それらを指定して削除すれば良い。
- 投稿日:2020-08-07T20:13:45+09:00
Laravelの基礎学習 with XAMPP
この記事の解説は独自の解釈が多いため間違っている可能性もあります。そのような箇所があれば指摘して頂けると幸いです。
目標
Laravelで簡易的なサイトが作れる程度の基礎を習得する
環境
- Windows 10 home
- XAMPP
- Laravel
Laravelの勉強
まずは初心者のためのLaravel入門 - libroを軸に勉強を進めていく。
学習の手順としては入れ替えた方が良い箇所もあるかもしれないが、自分にとって親しみやすい順で進めていく。Laravelのインストール
Composerのインストール
Laravel
のインストールにはComposer
というパッケージ管理ツールを使う。
PHP
で使用するソフトウェアやアプリケーションをインストールしたい時に、そのソフトウェアなどが動くのに必要な依存関係のある他のソフトウェアなども一緒にインストールしてくれる便利なツール。
Composer 公式からダウンロードして、PATH
を通して、ターミナルなどで次のような表示がされればOK。
Laravelインストーラーの導入
Laravel
では設定ファイルやコードなどを1つのプロジェクトとしてまとめて作業を行う。
ディレクトリやフォルダと同じ認識。では、
Laravel
のプロジェクトを作成していく。
今後もLaravel
プロジェクトを作成することを考えて、Composer
でLaravelインストーラーを導入してからLaravel
のプロジェクトを作成する。
Laravelインストーラーは下記のコマンドをターミナル実行して、インストールする。$ composer global require "laravel/installer"Laravelインストーラーのダウンロードが終わったら、赤下線部分をエクスプローラーで開く。
そこから~\vendor\bin
まで移動し、そこまでのパスをコピーする。C:\(各自のパス)\AppData\Roaming\Composer\vendor\binその後、
Windows10
の左下にある検索窓から「環境変数」を入力してシステム環境変数の編集
を開く
システムのプロパティ
が開けたら下の環境変数
(赤枠部)をクリック。
その後、下にある
システム環境変数(S)
からPath
を探してダブルクリック。
すると、環境変数名の編集
が開けるので、右上の新規
をクリックし、先程のパスを貼り付けて、OK
を押す。Laravelプロジェクトの作成
ターミナルに戻り、下記コマンドを実行。
$ laravel new blog(プロジェクト名)これで
Laravel
のプロジェクトが作成される。
今後、Laravel
のプロジェクトを作成したいときは、$ laravel new (プロジェクト名)
をターミナルで実行するだけで作成できるようになった。作成できたプロジェクトを実際に実行してみる。
ターミナルから以下のコマンドを実行。$ cd (プロジェクト名) $ php artisan serve
$ php artisan serve
でLaravel
の内蔵サーバーを起動できる。
つまり、このコマンドを利用することでローカルのアプリケーションとしてプロジェクトの状態確認が可能に。
ターミナルに表示された http://127.0.0.1:8000 にアクセスしてみると、Laravel
と中央に大きく書かれたサンプルページが開かれる。
ターミナルでCtrl + C
を押すとサーバーを閉じる。プロジェクト(フォルダ)構成について
プロジェクトを作成した際、一緒にインストールされたファイルなどはLaravelをスタートしよう(4/5):初心者のためのLaravel入門 - libroに解説が載っている。
ただ、この記事の情報は古いため、必要があれば下記コマンドでLaravel
のバージョンなどを確認し、公式ドキュメントなどで各自フォルダ構成について調査を。$ php artisan --versionルーティング処理
ルーティング処理: どのアドレスでアクセスされたら、どの処理を返すかを定義するもの
Laravel
では(プロジェクト名)\routes\web.php
でルーティング処理が指定されており、実際にファイルを確認してみると、以下のような宣言がある。(プロジェクト名)\routes\web.phpRoute::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.php
にblade
という見慣れない拡張子があるが、これはLaravel
で利用できるテンプレートの仕組み。
この仕組みを利用することで、blade
拡張子がついたファイル同士でコードを共有しあったり、Laravel
に搭載されている機能を簡単に呼び出したりすることができるようになる。ルーティング処理についてわかったところで、
Hello,World!!
を表示するようにweb.php
を変更してみる。
この後の作業で使用するため、変更前のコードをコメントアウトなどして残しておく。(プロジェクト名)\routes\web.phpRoute::get('/', function () { return 'Hello,World!!'; });表示用のファイル(テンプレート)について
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.phpRoute::get('/template', function () { return view('template',['message' => 'Study Template']); });ルーティング処理の内容は
/template
にアクセスされたらtemplate.php
を返すというものだが、view()
の中に連想配列が指定されている。ここで
ルーティング処理
の所で飛ばしたview()
関数の説明をする。
view()
関数はview(第一引数, 第二引数)
という形をとり、次のように宣言する。
第一引数
: ファイル名、テンプレート名を指定する。拡張子を除いた名前を宣言する。第二引数
:第一引数
に渡す値などを指定する。今回では連想配列を用いて、template.php
の変数$message
にStudy Template
という文字列を渡している。以上のファイル、ルーティング処理の作成によって表示されるページは次のようなものとなる。
http://127.0.0.1:8000/templateコントローラー
(プロジェクト名)\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.php
のRoute::get('/template', ~
を下記のように変更する。(プロジェクト名)\routes\web.phpRoute::get('/template','TemplateController@getindex');
Route
クラスの第二引数に指定されているTemplateController@getindex
でTemplateController
のgetIndex()
メソッドを呼び出すことを宣言している。
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\Controllers
にFormController.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.phpRoute::get('/form','FormController@getindex'); Route::post('/form','FormController@postindex');ここで意図した設計で稼働しているか確認してみる。
http://127.0.0.1:8000/form にアクセス。この状態で
送信
を押すと、このように変化する。
Requestクラスの基本(3/5):初心者のためのLaravel入門 - libro 以降ではクエリやURLの取得、リダイレクトについて記載されているため、確認してみては。
データベースとの連携
ここでは
XAMPP
のMySQL
を利用して、Laravel
とデータベースを連携させる。まずはデータベースの準備から。
XAMPP
を起動したら、XAMPP
のコントロールパネルにおけるMySQL
のAdmin
をクリックして、phpMyAdmin
に接続する。
phpMyAdmin
にログインできたら、データベース
タブから下記画像のように新規データベースを作成する。(画像ではデータベース名が頭文字が大文字だったが作成したら小文字になった。)
そして、新規テーブルを作成する。
好きな名前とカラム数を設定してテーブルを作成し、
ここまで(↓)設定できたら、次は
Laravel
側の設定に移る。
今回は
MySQL
を使用するが、他のデータベースを利用したい場合は、(プロジェクト名)\config\database.php
を開いて、下記の部分を使用したいデータベースに変える。(プロジェクト名)\config\database.php'default' => env('DB_CONNECTION', 'mysql'),どのデータベースを使用するか設定できたら、
(プロジェクト名)\.env
を開いて、下記にデータベース情報を入力していく。
デフォルトで値が入っているが、必要があれば変更する。(プロジェクト名)\.envDB_CONNECTION= DB_HOST= DB_PORT= DB_DATABASE= DB_USERNAME= DB_PASSWORD=ここからはデータベースに接続し、値を取得、ページに表示するまでを説明していく。
コントローラーの作成から行っていく。
(プロジェクト名)\app\Http\Controllers
にDatabaseController.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処理
を実行した場合、Update
とDelete
が同時に実行する命令が起きるようなデータの不整合が起きる可能性がある。
そのような事態に陥るのを防ぐために行われるのがトランザクション
で、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.phpRoute::get('/database','DatabaseController@getindex');自分の今までに掲載した画像の設定と同じ設定にすれば次のように表示されるはず。
http://127.0.0.1:8000/databaseORM(Object/Relational Mapping)について
さっきは自分でデータベースを作成して値を取得、表示まで行ったが、仕事でも同じような状況で作業ができるとは限らない。
違う人がデータベースを作成する事なんて普通だし、そもそもデータベースを見れずに手探りでデータを取得しなければならないことだってあり得る。
そのような状況で、今までのようなやり方では不都合が多い。そこで
PHP
のようなオブジェクト指向言語で用いられる技術がORM(Object/Relational Mapping)
だ。
この技術を用いることで、データベースのテーブルに存在しているデータ、値をPHP
のオブジェクトに変換したり、その逆の変換も行えるようになる。
その上、PHP
側で用意したクラスを操作するだけで、それに対応するデータベースのテーブルを自動的に操作できるようになるという。
Laravel
ではEloquent
というORM
が利用できるため早速使用してみる。最初にテーブルに対応するモデルと呼ばれるクラスの作成を行う。
ターミナルでプロジェクトのトップディレクトリに移動し、下記コマンドを実行。
自分はどのテーブルを扱うのかわかりやすいよう、テーブル: sample
に対し、モデル: Sample
を作成した。$ php artisan make:model Sample(モデル名)上記のコマンドが成功すると、
(プロジェクト名)\app
にSample(モデル名).php
が作成されているので、開いて確認してみると次のような内容になっている。(プロジェクト名)\app\Sample(モデル名).php<?php namespace App; use Illuminate\Database\Eloquent\Model; class Sample extends Model { // }
//
とコメントアウトにされている箇所があるが、そこをprotected $table = 'sample';
に変更して、使用するテーブル名を定義する。
protected
を付けることで、そのクラス自身と継承したクラス限定でアクセスが可能となるため、テーブルを保護するためにも欠かさずに付与する。
モデルの作成はこれで完了。コントローラーの作成に移る。
(プロジェクト名)\app\Http\Controllers
にORMController.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.phpRoute::get('/orm','ORMController@getindex');http://127.0.0.1:8000/orm にアクセスしてみて、http://127.0.0.1:8000/database と同じ内容が表示されているか確かめる。
all
の他にもデータベースにおける処理に関するメソッドがモデルクラスには用意されている。
その中の一つが検索機能のwhere
だ。
where
はモデル名::where(カラム名, 取得したい値)
でテーブルに検索をかけて、get()
でその結果を取得する。
コントローラーに実装して、試してみるとそれぞれ次のようになる。ORMController.phpclass ORMController extends Controller { public function getIndex(Request $request) { $data = Sample::where('id', 2)->get(); return view('database', ['message' => 'データベース名: sample','data' => $data]); } } ?>検索を実行できる
where
には様々な使い方がある。
>
やlike
といった演算子を使いたい場合はwhere(カラム名, 演算子, 取得したい値)
、and
条件ならwhere(条件1) -> where(条件2)
、or
条件ならwhere(条件1) -> orWhere(条件2)
という風になる。
データベースから値を取得する機会は多いので、少なくともこれらだけでも覚えておきたい。Laravelからデータベースのデータを操作する
CRUD処理
において、Read
に関してはORM
のwhere
で触れたが、Create
とUpdate
,Delete
がまだなので、今回はそれらに触れていく。前準備
ORM
の際に作成したモデルに2つのコードを追加する。(プロジェクト名)\app\Sample(モデル名).phpclass 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
を適用したいカラムを選択して、変更
をクリック。
その後、
A_I
の下のチェックボックスにチェックを入れ、保存。
もし、使用しない場合は
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.phpRoute::get('/create','CreateController@getindex'); Route::post('/create','CreateController@postindex');
post
後(ID
の5,6が抜けてるのは作成中にエラーの対応をしていたため)
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.phpclass 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.phpRoute::get('/update','UpdateController@getindex'); Route::post('/update','UpdateController@postindex');
post
前: http://127.0.0.1:8000/update?id=7
フォームの内容を変更したい内容に変えてある。
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.phpclass 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.phpRoute::get('/delete','DeleteController@getindex'); Route::post('/delete','DeleteController@postindex');
post
前: http://127.0.0.1:8000/delete
番外編: バリデーション
CRUD処理
の番外編としてバリデーションにも触れていく。
この機能は入力内容をチェックし、設定した条件を満たしているかどうかを判断するもので実装する方法は複数あるが、今回はフォームのバリデーションを実装する。
フォームのバリデーションはLaravel
において、フォームリクエストと呼ばれる。
今回はUpdate
で使用したファイル達に、このフォームリクエストを適用していく。フォームリクエストは以下のコマンドをターミナルで実行して作成する。
$ php artisan make:request UpdateRequest(作成したいファイル名)処理が完了すると
(プロジェクト名)\app\Http\Requests
にUpdateRequest(作成したいファイル名).php
が作成される。
UpdateRequest(作成したいファイル名).php
の各メソッドを次のように変更する。(プロジェクト名)\app\Http\Requests\UpdateRequest(作成したいファイル名).phppublic 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.phpuse 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>これでバリデーションが適用された際、どのフォームが条件を満たしていないかが赤字で表示されるようになった。
Laravel
からテーブルを操作するここまでで
Laravel
側からデータベースのテーブルに対する操作ができることを学んだが、Laravel
ではテーブルそのものを作成することもできる。ここからはLaravel入門 - 使い方チュートリアル - - QiitaとLaravel5 チュートリアル ブログもどきを作る(1) DB設定・マイグレーション - Qiitaシリーズを軸に進めていく。
マイグレーション
Laravel
のテーブルそのものを作成する仕組み、それがマイグレーション
だ。まずはデータベースにテーブルを作成するためのマイグレーションファイルを作成するところから始まる。
今回はlaravels
というテーブル名で、それを作成するためのマイグレーションファイルを以下のコマンドをターミナルに入力して作成する。
テーブル名の最後にs
を忘れないように。$ php artisan make:migration laravels(作成したいマイグレーションファイル名) --create=laravels(作成したいテーブル名)そうすると、
(プロジェクト名)\database\migrations
に2020_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(作成したいマイグレーションファイル名).phppublic 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_at
とupdate_at
のカラムは自動で作成され、AUTO_INCREMENT
は自動挿入、timestamp
は日時が自動で挿入される機能。では、このファイルを実行して、テーブルを作成してみる。
ターミナルに次のコマンドを入力することで、マイグレーションファイルが実行される。
$ php artisan migrate
migrate
でテーブルを作成するpublic function up()
の処理が行われた。
public function down()
の処理はmigrate:rollback
やmigrate: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\seeds
にStudySeeder(作成したいシーディングファイル名).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(作成したいシーディングファイル名).phppublic 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.phppublic function run() { $this->call(StudySeeder::class); }
StudySeeder
の部分を各自のシーディングファイル名に変更。以上で設定は終わりなのでシーディングを実行してみる。
シーディングの実行はターミナルで次のコマンドを叩く。$ php artisan db:seedLaravelシステム作成手順
今回の学習を踏まえて
Laravel
の作成手順をまとめる。0.
(プロジェクト名)\.env
にデータベース設定を記述
1. マイグレーションでテーブルを作成
2. シーディングでテーブルにデータ挿入
3.(プロジェクト名)\resources\views\
に表示用のファイル、blade
テンプレートを使用したファイルを作成
4.(プロジェクト名)\app\Http\Controllers\
に3で作成したファイルへデータなどを渡すコントローラーを作成
5. バリデーション作成
6.(プロジェクト名)\routes\web.php
でルーティング処理おわりに
今回は
Laravel
で簡易的なサイトが作れるようになるまでの基礎を学んだ。
Laravel
にはもっと多くの機能があり、この記事では触れられていないことが多い。
下記の参考資料などを参考に学習を進めていき、自分が作成したいサイトやシステムをLaravel
で実装できるようにしていく。参考資料
- 初心者のためのLaravel入門 - libro
- Laravel - Laravelで「"Attribute [controller] does not exist."」というエラーに困ってます。|teratail
- Laravel5 チュートリアル ブログもどきを作る(2) ブログ記事投稿フォームの作成 - Qiita
- PHPのアクセス修飾子public, protected, privateの違い | UX MILK
- 【Laravel】Trying to get property フィールド名 of non-objectについて – ネコと征く戦場
- 【Laravel5.8】FormRequestを使うとThis action is unauthorized.が吐き出される - Laravelとねころっけくん5.8
- Laravel入門 - 使い方チュートリアル - - Qiita
- Laravel5 チュートリアル ブログもどきを作る(1) DB設定・マイグレーション - Qiitaシリーズ
- 投稿日:2020-08-07T16:12:27+09:00
使用してきた関数(メソッド)を忘れないように記載していくよ(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に入っていることを想定 //このことで「.」を使用して、画像のパスを返していることになります。
- 投稿日:2020-08-07T15:19:59+09:00
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するんだから、「外部キーがないよ」ってなるのは当たり前か。
一気にマイグレーションファイルを作ってからマイグレートでいいけど、ファイルの作成順番が大事ということで。
- 投稿日:2020-08-07T15:16:21+09:00
【Laravel】生SQLの書き方
はじめに
Laravelで複雑な生SQLを書きたい時ってありますよね
(Eloquentで書くのも、クエリビルダでも面倒だなという時です)生のSQLの書き方が中々見つからなかったり、別の書き方ではうごかなったりだったので、残しておきます。
書き方
これだけです。
sql.phpDB::select( // 生のSQL文 );パラメータや変数の値をSQL分に含めたい時は、以下の通り。
sql.php$user_id = $request['user_id']; DB::select( // 生のSQL文 :user_id // 生のSQL文 , ['user_id' => $user_id]);SQL文中に変数を代入する部分は、「:変数名」としてあげて、連想配列の形で定義済み変数を渡して上げましょう。
- 投稿日:2020-08-07T15:02:03+09:00
Laravelでユーザーの生年月日をちゃんと表示する
ユーザーの生年月日をdate型でデータベースに保存するようにします
そのまま表示しようとすると
1998-09-25みたいな表示になるので
format関数を使って○月○日みたいな表示を可能にさせます
モデルの変更
対象となるモデルに記述(ここではUser.php)
User.phpprotected [ 'birthday' ] ## 表示させたいカラムを指定はいこれだけ、
これでformat関数が使えます
あとは指定すれば
<p>{{ $user->birthday->format(Y年m月d年) }}</p>こう表示される
1998年09月25日モデルに設定を記述しないとエラーが出る
- 投稿日:2020-08-07T10:51:04+09:00
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');
- 投稿日:2020-08-07T00:06:06+09:00
【Strategyパターン】Laravel で( ゚ェ゚)・∵.ゴフッ
TwitterAPIを使ったサービス作っている際に使ったので記録
Strategyとは
普通にプログラミングしていると、メソッドの中に溶け込んだ形でアルゴリズムを実装してしまうことがよくあStrategy パターンは、コンピュータープログラミングの領域において、アルゴリズムを実行時に選択することができるデザインパターンである。
Strategy パターンは、アプリケーションで使用されるアルゴリズムを動的に切り替える必要がある際に有用である。Strategy パターンはアルゴリズムのセットを定義する方法を提供し、これらを交換可能にすることを目的としている。Strategy パターンにより、アルゴリズムを使用者から独立したまま様々に変化させることができるようになる。
参考: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); } } }