tanaka's Programming Memo

プログラミングについてのメモ。

mac にインストールした apache の自動起動を停止する

mac に自分でインストールした apache自動起動を開始、停止する方法のメモです。

自動起動を停止

以下で、起動の設定を確認します。

ls /Library/LaunchDaemons

列挙される中から httpd の文字が入っているファイルを探します。例えば homebrew.mxcl.httpd24.plist というのがあった場合、以下で自動起動を停止します。

sudo launchctl unload -w /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist

自動起動を開始

停止した自動起動を開始するには、停止した時の設定名を、 load フラグで実行します。

sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist

以上です。

参考URL

MySQLでMEDIUMBLOB型のデータをMEDIUMTEXT型で取り出したい時

MySQLで、MEDIUMBLOB型のフィールドに文字列を入れていた場合、そのままでは日本語などは化けてしまいます。MySQL側で型変換することで解決しました。

例えば、MySQLの文字エンコードEUC-JP だった場合は、以下のようにして型変換して取り出します。

SELECT CONVERT(column USING ujis) FROM table;

PHPから操作する際、PHP文字コードUTF-8 だったとしても、上記の文字コードMySQL文字コードにしてください。MySQLUTF-8 だった場合は、 ujis ではなく、 utf8 にします。

PHP7.1以降と、MySQL5.5以降の組み合わせであれば、MySQLからPHPへの文字エンコードの変換は、 PDO の初期化時に、PHP 側の文字エンコードを指定しておけば、自動的に変換してくれます。

参考URL

macの OS をバージョンアップした時にやること(自分用メモ)

mac の OS をバージョンアップすると、Apache などの設定が初期化されてローカルの環境が気づかないうちに動かなくなったりするので、自分向けのメモ。

目次

Xcode の確認とバージョンアップ

  • Launchpad から Xcode を起動
  • 更新したり、許可する必要があれば行う
  • 問題がなければ、Xcode を終了
  • 端末を起動して、以下を実行
xcode-select --install

Homebrewのアップデート

  • 端末で、以下を実行
brew update
brew update
brew upgrade
  • 以下を実行して、「Your system is ready to brew.」を表示されれば完了。
brew doctor

上記で、警告が表示される場合、何らかの対応方法が書かれていることが多いので、それを実施して、再度 brew doctor を実行して、なるべく警告を減らします。

MySQLのセキュリティ設定

  • 以下を実行
mysql_secure_installation
  • rootのパスワードを入力
  • 以下は、テスト用で簡単なパスワードも許可しておきたいので no
VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: 
  • パスワードの変更は不要なので no
Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n
  • 何か使っていると面倒なので no
Remove anonymous users? (Press y|Y for Yes, any other key for No) : n
  • リモートアクセスは不要なので y
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
  • テスト用のデータベースは不要なので y
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
  • 特権テーブルをすぐにリロードしておくので y
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y

以上で、 mysql -u root -p として、パスワードを入力すると、MySQLへの接続ができるようになります。起動すると、自動的にサービスは起動します(自分の設定が最初からそうなっていたからかも)

古いバージョンの削除

いらないバージョンが出たら削除できます。mysql は最新版以外不要になったら、以下で古いものを削除できます。

brew cleanup mysql

文字コードの設定(2017/2/27追加)

目的としている MySQL のデータベースと、文字コードの設定が異なる場合は修正しないと文字化けを起こします。まずは、正しい設定を確認しておきます。 MySQL に接続して、以下の SQL を実行します。

use 確認したいデータベース;
show variables like '%character%';

以下のような結果が表示されたとします。

f:id:am1tanaka:20170227200929p:plain

データベースごとの文字コードの設定方法がよくわからなかったので、 PHP のプログラム側で設定することにします。データベースに接続するコードで、以下のように exec コマンドで、各設定をします。

    $db = new PDO('mysql:host=<データベースのホストアドレス>;dbname=<データベース名> , <ユーザー>, <パスワード>');
    $db->exec("SET character_set_client=utf8");
    $db->exec("SET character_set_connection=utf8");
    $db->exec("SET character_set_database=ujis");
    $db->exec("SET character_set_results=utf8");
    $db->exec("SET character_set_server=ujis");
    $db->exec("SET character_set_system=utf8");      

以上で文字コードが設定されるので、文字化けを防げます。

MySQLの起動と停止

MySQLのサービスの開始と停止は、 brew から呼び出すと動きます(mysql.server start はやり方が悪かったからか、エラーになったので、以下で良いかと)。

brew services start mysql
brew services stop mysql

Apache の設定

以下のブログの設定を参考に、現状に合わせて作業します。

$ sudo apachectl stop
$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null
$ brew install httpd24 --with-privileged-ports --with-http2
  • インストールが完了したら、インストール先のパスが表示されるので、記録しておく。以下の場合、[/usr/local/Cellar/httpd24/2.4.25]フォルダー f:id:am1tanaka:20170223190012p:plain
  • 以下を実行する。[2.4.25]の部分は、実際のバージョンに読み換える
$ sudo cp -v /usr/local/Cellar/httpd24/2.4.25/homebrew.mxcl.httpd24.plist /Library/LaunchDaemons
$ sudo chown -v root:wheel /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist
$ sudo chmod -v 644 /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist
$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist

以上で、Apache自動起動が設定されます。すでに起動しているので、 http://localhost にアクセスすれば、[It Works!]の表示を確認できます。

以下を実行しておくと、エラーを監視できます。

$ tail -f /usr/local/var/log/apache2/error_log

apache自動起動を解除する(2017/3/23追記)

valet などを利用するためにポート80を開けたいなど、 apache自動起動を無効にしたい場合は、以下を実行します。

$ sudo launchctl unload -w /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist

設定の変更

  • 設定ファイルの場所は、以下で確認できる
$ /usr/local/Cellar/httpd24/2.4.25/bin/httpd -V

f:id:am1tanaka:20170223183237p:plain

  • ビルド時の設定が表示されて、[-D SERVER_CONFIG_FILE=]の後ろに、設定ファイルへのパスが表示されます。画像の例では[/private/etc/apache2/httpd.conf]が該当するパス。今回のインストールでは[/usr/local/etc/apache2/2.4/httpd.conf]になる
  • テキストエディターで httpd.conf を開く
$ open -e /usr/local/etc/apache2/2.4/httpd.conf
  • DocumentRoot の設定を探して、設定したいフォルダーに書き換える(ダブルクォーテーションは消した方が良いらしいので、消しておく)
DocumentRoot /Library/WebServer/Documents
<Directory /Library/WebServer/Documents>
  • Directory タグ内の [AllowOverride]設定を以下のように[All]に書き換える
    AllowOverride All
  • [mod_rewrite.so]を利用できるようにするために、同モジュールを読み込む行を探して、行頭の # を以下のように削除
LoadModule rewrite_module libexec/mod_rewrite.so
  • ユーザーとグループを daemon から自分のものに変更する。[User daemon]という行を探して、以下のように修正(<自分のユーザーアカウント名>は実際のアカウント名に書き換える。staff はそのままで良い。現在の設定を確認したいときは、 id -p で確認する)
User 自分のユーザーアカウント名
Group staff
  • 以下の行を探して、行頭の # を削除
LoadModule socache_shmcb_module libexec/mod_socache_shmcb.so
...
LoadModule ssl_module libexec/mod_ssl.so
...
Include /usr/local/etc/apache2/2.4/extra/httpd-ssl.conf
...
Include /usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf
  • 上書き保存したら、次は以下を開く
$ open -e /usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf
  • 以下を追加
<VirtualHost *:443>
    DocumentRoot "/Library/WebServer/Documents"
    ServerName localhost
    SSLEngine on
    SSLCertificateFile "/usr/local/etc/apache2/2.4/server.crt"
    SSLCertificateKeyFile "/usr/local/etc/apache2/2.4/server.key"
</VirtualHost>
  • SSLの設定を開く
$ open -e /usr/local/etc/apache2/2.4/extra/httpd-ssl.conf
  • 以下の設定を探して、修正
#   General setup for the virtual host
DocumentRoot "/Library/WebServer/Documents"
ServerName localhost:443
ServerAdmin admin@example.com
  • 上書き保存する。認証用のファイルを作成する
$ cd /usr/local/etc/apache2/2.4
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
$ sudo apachectl configtest
  • Syntax OK と表示されなかった場合、ここまで手順を再確認する。表示されたら、以下で apache を再起動する
$ sudo apachectl -k restart

以上で、設定完了です。 http://localhost などは普通に開けるはずです。

https://localhost を開こうとすると、警告が表示されます。詳細をクリックしたり、エラー内容をクリックして、動作を許可してください。

mac にプライベート認証局を設置する場合は、以下の記事を参照してください。

PHP のインストール

PHPを複数バージョンインストールします。以下、 PHP5.6 と PHP7.1 をインストールする例です。

$ brew install php71 --with-httpd24
$ brew install --build-from-source php71-imagick
$ brew unlink php71
$ brew install php56 --with-httpd24
$ brew install --build-from-source php56-imagick

エラーが発生したら、 unlink をする必要があるかもしれません。エラーメッセージを読んで、指示の通りにコマンドを実行してから、再度インストールしてください。また、インストール済みの時は、念のため、 reinstall しておきます。

PHPの設定ファイルの場所は以下の場所です。

/usr/local/etc/php/5.6/php.ini
/usr/local/etc/php/7.1/php.ini

以下で、設定ファイルを開いて、 date.timezone を東京に設定します。

$ open -e /usr/local/etc/php/5.6/php.ini
  • date.timezone を検索して、設定がなければ以下のように追記
date.timezone = "Asia/Tokyo"
  • 上書き保存
  • 以上を、インストールした全てのPHPの設定ファイルに行う

ApachからPHPを利用する設定

httpd.conf に PHP の設定をします。httpd.conf を開いていたら、設定が変更されているので、一度閉じてから、以下で再起動します。

$ open -e /usr/local/etc/apache2/2.4/httpd.conf
  • LoadModule で php を読み込んでいる以下の行を削除します。
LoadModule php7_module        /usr/local/Cellar/php71/7.1.2_13/libexec/apache2/libphp7.so
LoadModule php5_module        /usr/local/Cellar/php56/5.6.29_5/libexec/apache2/libphp5.so
  • 削除した行の代わりに、以下の設定を追加
# Brew PHP LoadModule for `sphp` switcher
LoadModule php5_module /usr/local/lib/libphp5.so
#LoadModule php7_module /usr/local/lib/libphp7.so
  • ディレクトリ設定を書き換える。まずは以下のブロックを探す
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>
  • 以下に書き換える
<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

<FilesMatch .php$>
    SetHandler application/x-httpd-php
</FilesMatch>

PHPバージョンスイッチスクリプトを設定

PHPのバージョンを切り替えるためのスクリプト sphp をインストールします。

$ curl -L https://gist.github.com/w00fz/142b6b19750ea6979137b963df959d11/raw > /usr/local/bin/sphp
$ chmod +x /usr/local/bin/sphp

切り替えを試して見ます。PHP7.1を設定してみます。

$ sphp 71

以上で、切り替え割ります。切り替わったら、自動的に apache が再起動するので、アクセスすればバージョンが切り替わっていることが確認できます。

次に、以下で PHP5.6 に切り替えます。

$ sphp 56

以上で、環境の復活作業は完了です。


PHPの切り替え後、 Apache が停止した場合

sphp でバージョンを切り替えた時に、phpの設定がコメントアウトされないことがありました。以下で対処します。

  • 設定ファイルを開く
open -e /usr/local/etc/apache2/2.4/httpd.conf
  • php を検索して、以下のブロックを探し、片方の設定の前に # を追加して無効にする。以下は、 php5.x の方を有効にする例
# Brew PHP LoadModule for `sphp` switcher
LoadModule php5_module /usr/local/lib/libphp5.so
#LoadModule php7_module /usr/local/lib/libphp7.so
  • 設定を変更して保存したら、以下で apache を起動する
sudo apachectl start

brew upgrade時の警告

最初に brew upgrade をした時の、主要なアプリの警告です。

MySQL

==> /usr/local/Cellar/mysql/5.7.17/bin/mysqld --initialize-insecure --user=<ユーザー名>
Last 15 lines from /Users/yutanaka/Library/Logs/Homebrew/mysql/post_install.01.mysqld:
2017-02-25 01:08:47 +0900

/usr/local/Cellar/mysql/5.7.17/bin/mysqld
--initialize-insecure
--user=<ユーザー名>
--basedir=/usr/local/Cellar/mysql/5.7.17
--datadir=/usr/local/var/mysql
--tmpdir=/tmp

2017-02-24T16:08:47.181867Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2017-02-24T16:08:47.188144Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.
2017-02-24T16:08:47.188199Z 0 [ERROR] Aborting

Warning: The post-install step did not complete successfully
You can try again using `brew postinstall mysql`
==> Caveats
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
==> Summary
🍺  /usr/local/Cellar/mysql/5.7.17: 321 files, 234.4M

nginx

brew services start nginxでサービスをスタートできるという表示。

php56-imagick

==> Pouring php56-imagick-3.4.3_1.sierra.bottle.tar.gz
==> Caveats
To finish installing imagick for PHP 5.6:
  * /usr/local/etc/php/5.6/conf.d/ext-imagick.ini was created,
    do not forget to remove it upon extension removal.
  * Validate installation via one of the following methods:
  *
  * Using PHP from a webserver:
  * - Restart your webserver.
  * - Write a PHP page that calls "phpinfo();"
  * - Load it in a browser and look for the info on the imagick module.
  * - If you see it, you have been successful!
  *
  * Using PHP from the command line:
  * - Run `php -i "(command-line 'phpinfo()')"`
  * - Look for the info on the imagick module.
  * - If you see it, you have been successful!
==> Summary
🍺  /usr/local/Cellar/php56-imagick/3.4.3_1: 3 files, 321.7K

php-xdebug

==> Caveats
To finish installing xdebug for PHP 5.6:
  * /usr/local/etc/php/5.6/conf.d/ext-xdebug.ini was created,
    do not forget to remove it upon extension removal.
  * Validate installation via one of the following methods:
  *
  * Using PHP from a webserver:
  * - Restart your webserver.
  * - Write a PHP page that calls "phpinfo();"
  * - Load it in a browser and look for the info on the xdebug module.
  * - If you see it, you have been successful!
  *
  * Using PHP from the command line:
  * - Run `php -i "(command-line 'phpinfo()')"`
  * - Look for the info on the xdebug module.
  * - If you see it, you have been successful!
==> Summary
🍺  /usr/local/Cellar/php56-xdebug/2.5.0: 3 files, 194K

参考URL

さくらインターネットのメーリングリストのパスワードエラー

さくらインターネットメーリングリストの管理者操作をしようと、操作メールを送信しても、パスワードが違うと言われて操作ができませんでした。

原因は、niftyのメールアドレスからの操作だったようで、さくらインターネットレンタルサーバーで作成したメールからは操作できました。

勿論、操作しようとしたニフティのメールアドレスは、メーリングリストの管理者用メールアドレスとして登録していました。

エンコードとかその辺のようですが、とりあえずニフティからは操作しない方がよさそうということで。

Laravel5.4の開発環境をHomesteadでmacにインストール

注意:メインメモリー容量が 8GByte 以上ないと、動作が遅くて実用的ではないかもしれません。

Laravel5.4 の開発環境を mac に構築します。必要なソフトを全て揃える方法以外に、 Laravel HomesteadLaravel Valet の2種類の簡単に構築する方法が公式ホームページで紹介されています。

Homestead は、VirtualBox などの仮想 PC 上に開発環境を構築します。そのため、macWindowsLinuxのいずれでも利用できますが、少し手間が多いです。

Valet は、mac 専用の環境構築ツールですが、より簡単に構築ができます。また、メモリーサイズが足りない場合は選択肢になるようです。

ここでは他の OS でも使えるように Homestead での構築方法をまとめます。

前提条件

  • PHP がインストールされていること
  • composer がインストールされていること
  • メインメモリーが 8GByte 以上あること(4GByte でも動きますが、遅いです)

VirtualBox のインストール

VirtualBox5.1以降や、VMWareParallels などの仮想PCのソフトが必要です。ここでは VirtualBoxで進めます。

  • Downloads – Oracle VM VirtualBox を開く
  • インストールしたい環境の platform packages を選択してダウンロード(今回は mac) f:id:am1tanaka:20170218221952p:plain
  • ダウンロードしたファイルを起動
  • ウィンドウが表示されたら、VirtualBox.pkg アイコンをダブルクリック
  • しばらく待って、画面が表示されずに f:id:am1tanaka:20170214200238p:plain が跳ね始めたらそれをクリック
  • [続ける]>[続ける]>[インストール]をクリック
  • 管理者パスワードを要求されたら入力して[ソフトウェアをインストール]をクリック
  • インストールが完了するまで待つ
  • インストールが完了して、インストーラーをゴミ箱に入れるかが表示されたら[ゴミ箱に入れる]をクリック

続けて、拡張パックをインストールしておきます。

  • Downloads – Oracle VM VirtualBox を開く
  • エクステンションパックをダウンロードする f:id:am1tanaka:20170218222116p:plain
  • ダウンロードしたファイルを起動する
  • VirtualBoxが起動して、インストールするか質問が表示されるので、[インストール]をクリック
  • [同意します]をクリック
  • パスワード画面が表示されたら入力して[OK]
  • インストールが完了したら[OK]を押す

以上で、 VIrtualBoxのインストールが完了しました。次は Vagrant をインストールします。

VAGRANT のインストール

  • Download - Vagrant by HashiCorp を開いて、自分の環境のものをダウンロード
  • ダウンロードしたファイルを起動する
  • Vagrant.pkg をダブルクリックして起動する f:id:am1tanaka:20170214202507p:plain
  • インストーラーが起動したら、[続ける]>[インストール]をクリック
  • パスワード画面が表示されたら、入力して、[ソフトウェアをインストール]をクリック
  • インストールが完了したら[閉じる]をクリック
  • インストーラーをゴミ箱に入れるかを聞かれたら[ゴミ箱に入れる]をクリック

以上で Vagrant のインストール完了です。

Laravel Homestead のインストールとセットアップ

端末を起動して、以下を実行してください。 laravel/homestead ボックスが Vagrant にインストールされます。

vagrant box add laravel/homestead

以下のような選択肢が表示されたら、今回は VirtualBox で進めているので 2 を入力して[Enter]キーを押します。 f:id:am1tanaka:20170214212929p:plain

時間がかかるので完了するまで待ってください。

Laravel Installer のインストール

Laravel の動作環境は仮想PC にインストールしますが、 Laravel プロジェクトを作成するための環境は、 mac にもインストールしておきます。端末から以下を実行してください。

composer global require "laravel/installer"

インストールが完了すれば、基本的なインストールは完了です。

hosts 情報の設定

mac から仮想PC 内の Webサーバーにアクセスしやすくするために、homestead.app というドメインを、仮想PC の Web サーバーとして設定される 192.168.10.10 に割り当てておきましょう。

  • 端末から以下を入力
sudo vi /etc/hosts
  • パスワードを要求されたら入力
  • [i] キーを押して、入力モードにする
  • 下キーを繰り返し押して、カーソルを移動できるところまで下に移動させる
  • 右キーを繰り返し押して、カーソルを移動できるところまで右に移動させる
  • [Enter]キーを押して、新しい行を入力
  • 以下の行を追加する
192.168.10.10   homestead.app

f:id:am1tanaka:20170214221417p:plain

  • [ESC]キーを押してから、[:][w][q][Enter]キーの順に入力して、保存して、 vi を終了

これで環境構築が完了です。ここまでの作業は、一度やれば次からは不要です。

Laravel プロジェクトを作成

Laravel のプロジェクトを開始したい時はこの作業から始めます。

mac 上で Laravel プロジェクトを作成します。以下は、ユーザーフォルダー内に laravel5-4-test という名前の Laravelのプロジェクトフォルダーを作成する例です。

  • 端末を起動するか、起動中の端末に切り替える
  • 以下で、 Laravel プロジェクトを作成
cd ~
laravel new laravel5-4-test

これで Laravel プロジェクトが作成できます。次は Laravel Homestead の設定です。

Laravel Homestead の設定を生成

引き続き、端末で操作します

  • 以下を実行して、Laravel Homestead の設定を生成
cd ~/laravel5-4-test
composer require laravel/homestead --dev

画面に変化がなくても、数分間は待ってください。少し時間がかかります。

インストールが完了して、プロンプトが表示されたら、以下で設定ファイルを生成します。これはすぐに終わります。

php vendor/bin/homestead make

[Homestead Installed!]と表示されたら完了です。 f:id:am1tanaka:20170219000820p:plain

Vagrant で仮想 PC に開発環境を立ち上げる

端末で、以下のコマンドを実行すると、仮想PC に開発環境を作成して、起動します。

vagrant up

途中で、セキュリティーの確認が表示されたら[許可する]などで通信できるようにしてください。以下のようになれば完了です。f:id:am1tanaka:20170218230136p:plain

最終行にエラーっぽい行が表示されても、「すでに composer がインストールされている」という表示なので気にしなくて結構です。

Webブラウザーで、 http://homestead.app にアクセスしてください。 Laravel のデフォルトページが表示されます。 f:id:am1tanaka:20170218233735p:plain

Laravel をビルド可能にする

Laravel でプロジェクトをビルドできるようにします。端末から以下を実行してください。仮想PC に端末から接続します。

vagrant ssh

以下のように、最下段が[vagrant@laravel5-4-test]から始まっていれば成功です。 f:id:am1tanaka:20170218230732p:plain

仮想PC に端末がログインしたので、ここからの指示は 仮想 PC へのものになります。プロジェクトフォルダーに移動して、 node 環境と composer 環境を揃えます。

cd laravel5-4-test
sudo npm upgrade --global yarn
yarn install
composer install

自動ビルドを開始します。

yarn watch

しばらく待つと、緑色の字で[emitted]という字が並んで、変更の監視状態になります。あとは、 Laravel のファイルを変更すれば、自動的にビルドされます。 f:id:am1tanaka:20170219001911p:plain

開発を開始

Laravel のプロジェクトフォルダーは、 mac と仮想PC で共有されているので、作業は mac 側で行うことができます。

Atom などのエディターで、作成した Laravelプロジェクトを開きます。

  • プロジェクトフォルダー内の resources/views/welcome.blade.php を開く
  • 82行目にある Laravel を書き換える。例えば、 Homestead を追加するなど f:id:am1tanaka:20170219003604p:plain
  • 上書き保存する

ファイルが変更されたら、それを仮想PC の環境が検出してプロジェクトがリビルドされます。mac の Webブラウザーhttp://homestead.app を表示したり、再読み込みをしていると、そのうちに変更が反映されます。

f:id:am1tanaka:20170219003915p:plain

いつビルドが完了するか分からないのは不便です。 macBrowserSync をインストールして、プロジェクトフォルダー内の public フォルダーの変更をトリガーにして、ブラウザーをリロードする設定をすると良いでしょう。やり方はここでは割愛しますので、インターネットで調べてみてください。

以上で、開発が整いました。あとは、開発を進めていってください。

停止方法

仮想PC の停止方法です。

  • 仮想PC に接続した端末で、[Ctrl]+[C]キーを押して、監視を停止する
  • コマンドが入力できるようになるので、以下で仮想PCをシャットダウンする
sudo shutdown -h now
  • exit を入力して [Enter]キーを押すと、端末が終了する
  • 終了した端末の[x]をクリックして閉じる

以上で停止完了です。

再開方法

開発を再開したい時の手順です。

  • VirtualBoxをランチャーなどから起動
  • プロジェクト名の仮想マシン(laravel5-4-testなど)を選択して、[起動]ボタンで起動 f:id:am1tanaka:20170219005301p:plain
  • 端末を開いて以下のように プロジェクトフォルダー に移動 > 仮想PCにログイン > ファイルの変更を監視する
cd laravel5-4-test
vagrant ssh
yarn watch

仮想PC の削除方法

テストなどで作成した仮想PC を削除したい場合の操作です。

  • 仮想PC が起動していたら停止する
  • 端末を起動する
  • 以下のコマンドで、プロジェクトフォルダーに移動 > 仮想PC を削除する
cd ~/laravel5-4-test
vagrant destroy --force
  • プロジェクトフォルダーが不要ならば、以下でフォルダーを削除
cd ..
rm -rf laravel5-4-test

まとめ

macPHP, Composer, VirtualBox, Vagrant, Laravel Installer がインストールされていれば、あとは仮想PC 上に、Webサーバーやデータベースサーバーなどの Laravel を開発する環境を構築することができました。

mac の Webブラウザーで、 http://homestead.app にアクセスすると、 Laravel のページが表示されました。また、ファイルの変更があったらリビルドする設定をして、表示されるページの文字を変更してみました。

最後に、仮想PC の停止方法や、作業の再開方法、仮想PC の削除方法をまとめました。

やってみると手順がわからない部分がいくつかあって、公式サイトに書いてあるほど手軽ではありませんでした。とはいえ、依存関係やバージョンによるトラブルが発生しないのはやはり楽です。

最大のネックは、メインメモリーでしょう。公式サイトにも書いてありますが、(Laravelは7MByteで動作する、という文言を読み間違えてました。2017/2/19 修正)8GByte 以上欲しいです。4GByte の MacBook Air だと遅くて開発は厳しいと感じました。その場合は、 mac なら Laravel Valet を検討するか、必要な環境を揃えて手順通りにインストールしてください。処理速度はそちらの方が有利でしょう。

参考URL

Laravel5.3から5.4へのアップグレードガイドのメモ

Laravel 公式ページの Laravel5.3 から Laravel5.4 へのアップグレードガイドのメモです。

Upgrade Guide - Laravel - The PHP Framework For Web Artisans

想定時間は、1〜2時間程度とあります。GitHubの手順で利用できるようにマークダウン書式にしてみました。

# 依存関係の更新

- [ ] composer.json の変更
  - [ ] laravel/framework のバージョンを 5.4.* に書き換える
  - [ ] phpunit/phpunit のバージョンを ~5.7 に書き換える
  - [ ] 以上終えたら、 composer update で更新する
- [ ] bootstrap/cache/compiled.php があれば、フレームワークで使うことはなくなったので削除
- [ ] 以下を実行して、 Illuminate\View\Factory::getFirstLoop()を削除したことに関連するエラーを解決する。ついでに、ルートのキャッシュをクリアしておく
 ```
php artisan view:clear
php artisan route:clear
 ```
- [ ] tinker Artisan コマンドを引き続き利用したい場合は、以下で laravel/tinker パッケージのインストールが必要
composer require laravel/tinker
  - [ ] インストールしたら、config/app.php の providers 配列に、 Laravel\Tinker\TinkerServiceProvider::class を追加
- [ ] Guzzle 6.0以上が必要

# Authorization

- [ ] getPolicyFor($class) メソッドを利用していた場合、以前は引数のクラスのためのポリシーが見つからなかった場合、例外が発生していたが、 null が返されるようになったので、以下のように null のチェックを追加すること
 ```php
$policy = Gate::getPolicyFor($class);

if ($policy) {
    // code that was previously in the try block
} else {
    // code that was previously in the catch block
}
 ```

# Blade

- [ ] @sectionに渡されたインラインコンテントが、自動的にHTMLエスケープされるようになった。エスケープされていない文字列を section で描画したい場合は、いわゆる "long form" スタイルを利用する
 ```php
@section('title')
  {!! $content !!}
@stop
 ```

# Bootstrappers

- [ ] HTTPかConsoleカーネルで、 $bootstrappers 配列を手動でオーバーライドしていた場合、 DetectEnvironment を LoadEnvironmentVariables に名前変更する

# Broadcasting

- [ ] Laravel5.3で、チャンネルネームプレースホルダーとして * を使っていた場合、 5.4では、 {foo} スタイルのプレースホルダーに書き換える
 ```php
Broadcast::channel('App.User.{userId}', function ($user, $userId) {
    return (int) $user->id === (int) $userId;
});
 ```

# Collections

- [ ] every メソッドが nth メソッドに変更(Loadshのメソッド名に合わせた)
- [ ] $collection->random(1) は、新しい collection インスタンスを返すようになった。これまでは、1つのオブジェクトを返していた。引数なしで呼び出された場合のみ 単体のオブジェクトが返される

# Container

- [ ] bind や instance メソッドによって、コンテナの Alias を登録する機能が削除された。 Alias の登録は alias メソッドに変更する
 ``` php
$container->alias(FooContract::class, 'foo');
 ```
- [ ] container の make メソッドの第2パラメーターに配列パラメーターが渡せなくなったので、他の、より直感的な生成方法に変更する
- [ ] container の resolving メソッドと afterResoliving メソッドは、第1引数に クラス名か binding key を指定することが必須になった
- [ ] share メソッドが削除されたので、 singleton メソッドに変更する
 ```php
$container->singleton('foo', function () {
    return 'foo';
});
 ```

# Console

- [ ] Illuminate\Console\AppNamespaceDetectorTrait への参照があったら Illuminate\Console\DetectsApplicationNamespace に変更する

# Database

- [ ] サービスコンテナに、カスタムのデータベース接続のインスタンスを解決するキーとして、 db.connection.{ドライバーネーム} をバインドしていた場合、 AppServiceProvider の register メソッド内で、 Illuminate\Database\Connection::resolverFor メソッドで登録するように変更する
 ```php
use Illuminate\Database\Connection;

Connection::resolverFor('driver-name', function ($connection, $database, $prefix, $config) {
    //
});
 ```
- [ ] configuration ファイルで PDO の "fetch mode" が使えなくなり、 PDO::FETCH_OBJ が常に使われるようになる。今後も、 fetch mode を変更したい場合は、新設された Illuminate\Database\Events\StatementPrepared イベントを監視して、そこで設定する
 ```php
Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(...);
});
 ```

# Eloquent

- [ ] date キャストをすると Carbon(DateTimeを拡張するPHPのライブラリ)のオブジェクトに変換され、startOfDay メソッドが呼ばれるようになった。時間まで記録したい場合は、datetime キャストを使うこと
- [ ] リレーションを定義するときに、明示的に外部キーを定義していない場合、テーブル名と主キーの名前をモデルを関連づけるための外部キー名として使うようになった。これを変更したい場合は、該当するモデルの getKeyName メソッドをオーバーライドして、以下のようにすると、 テーブル名_key が外部キーのフィールド名として利用される
 ```php
public function getKeyName()
{
    return 'key';
}
 ```
- [ ] hasOne や hasMany のリレーションの createMany メソッドを呼び出すと、配列ではなく、 collection のオブジェクトが返されるようになったので、必要なら対応すること
- [ ] リレーションが設定されたモデルは、デフォルトのデータベース接続ではなく、親モデルと同じ接続を利用するようになった。デフォルトの接続を利用したい場合は、モデルの接続をデフォルトのものにするように明示的に設定する
- [ ] Model::create と Model::forceCreate メソッドが、マルチコネクション上でモデルを作成しやすくするために Illuminate\Database\Eloquent\Builder に移動された。独自のモデルでこれらのメソッドを拡張していた場合は、 builder 上で create メソッドを呼び出すように実装を変更すること
 ```php
public static function create(array $attributes = [])
{
    $model = static::query()->create($attributes);

    // ...

    return $model;
}
 ```
- [ ] カスタムの接続名を hydrate メソッドに渡していたら、 on メソッドを使うようにする
 ```php
User::on('connection')->hydrate($records);
 ```
- [ ] Model::hydrateRaw メソッドの名前が fromQuery に変更された。また、カスタムの接続名をこのメソッドに渡していたら、 on メソッドを使うようにする
 ```php
User::on('connection')->fromQuery('...');
 ```
- [ ] factory(User::class, 1)->make() か factory(User::class, 1)->create() を呼び出すと、アイテムが一つの collection インスタンスを返すようになったので、必要であれば対応すること。これまではモデルを1つ返していた。モデルが生成されない時のみ、単体のモデルを返す

# Events

- [ ] アプリやパッケージで、手動で Illuminate\Contracts\Events\Dispatcher を実装していたら、 fire メソッドの名前を dispatch に変更すること
- [ ] "priorities" イベントハンドラーが非対応になった。一連の同期メソッドを呼び出す方法に変更すること。他のイベントハンドラー内から、新しいイベントを dispatch することで、無関係なハンドラーの処理の後に、与えられたイベントが処理されるようにする
- [ ] Event::firing メソッドが削除された。ワイルドカードイベントハンドラーは、第1引数にイベント名を、第2引数にイベントデータを配列で受け取るようになった
 ```php
Event::listen('*', function ($eventName, array $data) {
    //
});
 ```
- [ ] kernel.handled イベントは Illuminate\Foundation\Http\Events\RequestHandled クラスを使ったオブジェクトベースのイベントになったので、必要なら対応する
- [ ] locale.changed イベントは Illuminate\Foundation\Events\LocaleUpdated クラスを使ったオブジェクトベースのイベントになったので、必要なら対応する
- [ ] illuminate.log イベントは Illuminate\Log\Events\MessageLogged クラスを使ったオブジェクトベースのイベントになったので、必要なら対応する

# Exceptions

- [ ] Illuminate\Http\Exception\HttpResponseException は、 Illuminate\Http\Exceptions\HttpResponseException に名前が変更になった
- [ ] Exception が複数形の Exceptions になったので、 Illuminate\Http\Exception\PostTooLargeException も Illuminate\Http\Exceptions\PostTooLargeException に変更になった

# Mail

- [ ] Mail::send('view.name', $data, 'Class@send') のように、 'Class@method' という文法を使っていたら、非対応になるので mailables に変更すること
- [ ] Markdownメールに対応させるため、以下の設定を mail の config ファイルに追加する
 ```php
'markdown' => [
    'theme' => 'default',

    'paths' => [
        resource_path('views/vendor/mail'),
    ],
],
 ```
- [ ] Mail::queue や Mail::later メソッドにメールメッセージとして、Closure を設定に渡す方法が非対応になるので、 mailables に変更する

# Redis

- [ ] Redis Cluster 機能を利用する場合、 config/database.php ファイルに以下の設定を追加する
 ```php
'redis' => [

    'client' => 'predis',

    'options' => [
        'cluster' => 'redis',
    ],

    'clusters' => [
        'default' => [
            [
                'host' => env('REDIS_HOST', '127.0.0.1'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
            ],
        ],
    ],

],
 ```

# Routing

- [ ] Illuminate\Foundation\Http\Middleware\VerifyPostSize が Illuminate\Foundation\Http\Middleware\ValidatePostSize に変更になった
- [ ] Illuminate\Routing\Router クラスの middleware メソッドが aliasMiddleware() に変更された。HTTPカーネル内で使われているもので、影響はほぼないはずだが、もし使っているようなら対応する
- [ ] Illuminate\Routing\Route クラスの getUri メソッドが削除されたので、 uri メソッドに変更する
- [ ] Illuminate\Routing\Route クラスの getMethods メソッドが削除されたので、 methods メソッドに変更する
- [ ] Illuminate\Routing\Route クラスの getParameter メソッドが削除されたので、 parameter メソッドに変更する

# Sessions

Session について、 Symfony の SessionInterface が非対応になり、 Illuminate\Contracts\Session\Session が定義されたので、以下の対応が必要。

- [ ] 全てのSymfony の ->set() メソッドを ->put() メソッドに変更する(Laravel内ではドキュメントに記載していないこの機能は利用していないが、ユーザー側で利用していたら対応すること)
- [ ] 全てのSymfony の ->getToken() メソッドを ->token() メソッドに変更する
- [ ] 全てのSymfony の $request->setSession() メソッドを setLaravelSession メソッドに変更する

# Testing

Laravel5.4で、これまでよりもシンプルで軽量なテスト機能が実装された。

- [ ] Laravel5.3 以前のテストを引き続き利用する場合は composer require laravel/browser-kit-testing laravel/browser-kit-testing を端末で実行して、パッケージをプロジェクトにインストールする
- [ ] テストのために putenv('APP_ENV=testing') を設定することはしなくなったので、 .env ファイルの APP_ENV をテストの時に設定すること
- [ ] Event の fake である assertFired メソッドは、 assertDispatched に変更になった
- [ ] Event の fake である assertNotFired メソッドは、 assertNotDispatched に変更になった

## Laravel5.3 と 5.4 のテストを併用する

- [ ] composer.json の autoload-dev ブロックに、以下のネームスペースを追加
 ```json
"psr-4": {
    "Tests\\": "tests/"
}
 ```
- [ ] composer require laravel/browser-kit-testing として、5.3用のパッケージをインストール
- [ ] tests/TestCase.php ファイルのコピーを作成して、 tests/BrowserKitTestCase.php にする
- [ ] コピーした BrowserKitTestCase.php をエディターで開いて、 Laravel\BrowserKitTesting\TestCase を継承するように変更する。TestCase.php が 5.4 のテスト用のベースクラスで、 BrowserKitTesting.php が 5.3 のテスト用のベースクラスになる
- [ ] composer.json を開いて、以下を追加
 ```json
"autoload-dev": {
    "classmap": [
        "tests/TestCase.php",
        "tests/BrowserKitTestCase.php"
    ]
},
 ```
- [ ] 以上が完了したら、 5.3 用のテストを全て BrowserKitTestCase を継承するように変更する

# Translation

- [ ] {Inf} プレースホルダーで複数の文字列を表現していた場合、 * 文字に置き換える
 ```
{0} First Message|{1,*} Second Message
 ```

# URL生成

- [ ] Illuminate\Routing\UrlGenerator クラスの forceSchema メソッドを forceScheme に変更する

# Validation

日付フォーマットのチェックがより厳密になり、PHP の date関数内に読み込めるようになった。

- [ ] これまではタイムゾーンのプレースホルダーとして P が、全てのタイムゾーンフォーマットを表していたが、5.4 では、タイムゾーンごとに、PHP のドキュメントにある個別のプレースホルダーを持つようになった。必要であれば対応する
- [ ] addError メソッドを addFailure に変更する(Validator クラスを継承した時に変更が必要になる可能性がある)
- [ ] doReplacements メソッドを makeReplacements に変更する(Validator クラスを継承した時に変更が必要になる可能性がある)

# その他

GitHub リポジトリhttps://github.com/laravel/laravel にある変更点の確認も推奨する。具体的な変更点は、 https://github.com/laravel/laravel/compare/5.3…master で確認できるので、必要に応じてチェックすると良い。


# 5.4 で使えるようになった機能や対応したライブラリ

## 依存関係

- [ ] 5.4から、 JavaScriptのライブラリーである Axios に対応したので、グローバルで axios からライブラリーを利用できる
- [ ] Laravel Scout のバージョンが 3.0.0 になった
- [ ] Laravel Socialite のバージョンが 3.0.0 になった
- [ ] bindメソッドでコンテナにクラスを登録する際に \ で指定する方法が非対応になった。以下のように変更する
 ```php
// 変更前
$container->bind('Class\Name', function () {
    //
});

// 変更後
$container->bind(ClassName::class, function () {
    //
});
 ```

## Eloquent

- [ ] where('key', ...) として主キーの値を検索句に設定していたら、 whereKey($id) を使うことができる

## Laravel Dusk を取り入れる

- [ ] 端末で composer require laravel/dusk を実行して、パッケージをインストールする
- [ ] tests/CreatesApplication.php を作成して、以下のコードを入力
 ```php
<?php

use Illuminate\Contracts\Console\Kernel;

trait CreatesApplication
{
    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();

        return $app;
    }
}
 ```

以上ができたら、続きは https://laravel.com/docs/5.4/dusk#installation の通りに進めれば良い。

## メールのテスト

assertSentTo メソッドは、より簡単な assertSent メソッドに置き換えることができ、コールバック内で hasTo や hasCc などのヘルパーを利用できる。

Mail::assertSent(MailableName::class, function ($mailable) {
    return $mailable->hasTo('email@example.com');
});

以上です。

Laravel5.4の新機能

Laravel5.4が出ていたので、公式ページの新しい機能の紹介部分を読みながらのざっくりメモです。

Release Notes - Laravel - The PHP Framework For Web Artisans

マークダウンでメールとNotificationsの文面を書けるようになった

マークダウンで書いたメールや通知の文面は、 Laravel でプリビルドされて、レスポンシブな HTML テンプレートと plain textの双方が生成されるとのことで、これはとてもありがたいです。

タグに該当するものは @component()〜@endcomponent で囲みます。

  • mail::message メール文
  • mail::button 第2引数に URL を渡して、ボタンを生成
  • {{}} で PHP が実行できるので、 {{ config(‘app.name’) }} などのようにすれば設定を読み取れる

マークダウンで生成されるスタイルをカスタマイズしたい場合は、artisan コマンドの vendor:publish を実行します。この設定だけ書き出したい場合は、 laravel-mail タグを追加します。

Laravel Dusk

Webブラウザー上での動きや、 API をテストするための新しい機能です。デフォルトで使う場合は、 JDKSelenium のインストールはせず、スタンドアロンの ChromeDriver を利用します。

Webブラウザー上でテストするので、 JavaScript を利用する機能のテストも可能です。

Selenium を利用することももちろんできます。

$this->browse(関数)でテスト開始します。

Browser Tests (Laravel Dusk) - Laravel - The PHP Framework For Web Artisans

Laravel Mix

これまでは、 Gulp ベースの Laravel Elixir がビルドツールとして提供されていましたが、その Webpack 版です。

Laravel Mix は、 Laravel アプリで使われる CSSJavaScript を処理するプリプロセッサーを Webpack の APIとして提供します。

Blade コンポーネントとスロット

Vue.js にある コンポーネントとスロットと同様の機能を Blade で使えるようになりました。

コンポーネントの定義内で、スロットの位置に {{ $slot }} を書きます。

Blade内で、上記で定義したコンポーネントを @component(コンポーネント名)〜@endcomponent で利用して、その間にスロットに差し込みます。

以下、公式サイトの例です。

以下、alert コンポーネントの定義例。

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    {{ $slot }}
</div>

以下で、alert コンポーネントのスロットに「Whoops! Something went wrong!」を渡します。

@component('alert')
    <strong>Whoops!</strong> Something went wrong!
@endcomponent

名前付きスロットを利用する場合は、 @slot(‘スロット名’)と@endslot の間に、スロットの中身を書きます。

Broadcast Model Binding

HTTPルートのように、 Broadcast の channel で、 Route Model Binding(RouteのURLセグメントに含まれるモデルのIDに該当するデータを、自動的にデータベースから取得して、ルート関数に渡す機能) と同様のルート機能を利用できるようになりました。

以下、公式サイトの例です。 Authorizing Channels の例を書き換えています。

use App\Order;

Broadcast::channel('order.{order}', function ($user, Order $order) {
    return $user->id === $order->user_id;
});

上記の元のコードは以下です。関数内で、データベースにアクセスしている部分が省略できています。

use App\Order;

Broadcast::channel('order.{orderId}', function ($user, $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});

Collection Higher Order Messages

Collections (データベースから取り出したデータのオブジェクト) が、コレクション上でよく利用する共通の操作を行うショートカットを実装しました。対応したのは以下のメソッドです。

contains, each, every, filter, first, map, partition, reject, sortBy, sortByDesc, and sum.

以下、公式サイトの例です。 User モデルから votes の値が 500 より大きいデータを $users に取り出して、取得したデータごとにmarkAsVip()関数を実行する例です。

$users = User::where('votes', '>', 500)->get();

$users->each->markAsVip();

以下は、 sum の例で、 Userモデルから group が Development のデータを $users に取り出して、 取り出したデータの votes 要素の合計を求めて、 return しています。

$users = User::where('group', 'Development')->get();

return $users->sum->votes;

Object ベースの Eloquent イベント

Eloquent のイベントハンドラーがイベントオブジェクトに対応づけられました。より直感的に、 Eloquent イベントを制御したり、テストできるようになります。Eloquent モデルに $events プロパティーを定義することで、様々なライフサイクルでイベントを呼び出すことができます。

対応するイベントは Eloquent: Getting Started - Laravel - The PHP Framework For Web Artisans

Job Level Retry & Timeout

これまでの Job の リトライやタイムアウトは、コマンドラインからすべてのジョブに対して共通設定となっていました。これを、 job クラス上で、ジョブごとに設定できるようになりました。

$tries プロパティーでリトライ数、$timeout プロパティーでタイムアウトまでの秒数を指定できます。

リクエスト文字列を整理するミドルウェア

デフォルトミドルウェアに、 TrimStrings と ConvertEmptyStringToNull ミドルウェアが追加されました。これにより、入力文字列の前後の空白は削除され、未入力の場合は null になります。

Realtime ファサード

これまでは Laravel のビルトインのサービスのみがファサードとして利用できたが、ユーザーのクラスを簡単に Facade として利用できるようになった。 use Facades\ {} のブラケット内にクラス名を登録すれば、ファサードとして機能します。これを Realtime Facades と言います。

このように定義したユーザーファサードも、 shouldReceive()などのモック化機能が使えるので、テストも容易になります。

カスタム Pivot Table モデル

Laravel5.3 では、 belongsToMany() のリレーションのための pivot テーブルはすべて共通のビルトインの Pivot モデルインスタンスを利用していました。Laravel5.4では、カスタムの Pivot テーブルを定義できるようになりました。

テーブル間を結ぶ中間テーブルに独自のテーブルを指定したい場合は、 using メソッドで指定します。

Redis Cluster サポートの改良

これまでは、同じアプリケーション内で、単体のホストとクラスターへの Redis の接続を定義できませんでしたが、 5.4 では複数のホストとクラスターを一つのアプリケーション内で接続できるようになりました。

Migration Default String Length

Laravel5.4 では、絵文字に対応できるように、デフォルトの文字セットとして utf8mb4 を使うようになりました。Laravel5.3からアップグレードする際には、キャラクターセットの変更は不要です。

手動でこの文字セットに変更したい場合や、 MySQL の Ver5.7.7 より古いもので動かしている場合は、 migration によってデフォルトの文字長を設定し直す必要があります。 AppServiceProvider クラスの boot メソッド内で Schema::defaultStringLength メソッドを呼び出して設定します。

以下、公式サイトの例です。

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

まとめ

メールや通知のマークダウン対応はすぐにでも取り入れたいです。Laravel Dusk は、 Codeception との位置付けがどうなっているか、まだ読んでいないのでわかりませんが、SeleniumJDKのインストールをせずに簡単なテストが可能になったのはありがたいです。PHPUnit のバージョンが変わって、メソッド名を変更しないと動かないことがあるようなので、その辺はアップグレードガイドの方で確認する必要があるようです。データベースの文字セットの変更もチェックが必要そうです。

すでに Elixir で環境を構築していたら不要とは思いますが、Webpack を採用する場合、 Laravel Mix へ移行すると良さそうです。

Bladeのコンポーネントとスロット機能や、データベースを操作するショートカット、入力値の自動トリミングや 空文字列の null 値への変更、カスタムファサード機能など、良い改良が施された印象でした。


以下、新しい機能ではありませんが、 Broadcast Model Binding を読む際にまとめてしまったので。

おまけ

Route Model Binding

モデルのIDをルートやコントローラーのアクションに渡す時に、渡された ID を持つモデルを検索する場合がしばしばあります。Laravel の Route Model Binding は、作成するルートに自動的に指定のモデルのインスタンスを渡す簡単な機能を提供します。例えば、ユーザーの ID をそのまま渡すのではなく、その ID が指定する ユーザーモデルのインスタンスを渡す方法です。

暗黙的なバインディング

Laravel は、ルートやコントロールアクション内のタイプヒントの文字列から、 Eloquentモデルのフィールド名を推測して、該当するモデルデータを自動的に取得します。

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

(公式ページから転載)

例えば上記の例では、引数である $user には、App\User の Eloquent モデルが渡されるように型指定(type hinted)されていて、変数名と URI セグメントの指定が一致する {user} の場所の ID がモデルの特定に利用されます。 Laravelは自動的にリクエスト URI で渡される値からユーザーのIDを検索して、そのモデルのインスタンスを自動的に引数として渡します。もしデータベースで指定のIDが見つからなかった場合は、 404 HTTP レスポンスが自動的に生成されます。

## キー名のカスタマイズ

id 以外のフィールドでマッチさせたい場合は、Eloquentモデルの getRouteKeyName メソッドをオーバーライドします。

/**
 * モデルを検索するルートのキーとして slug を利用したい場合
 */
public function getRouteKeyName() {
    return 'slug';
}
明示的なバインディング

Router の model メソッドを使って、明示的に指定のクラスを登録することができます。明示的なモデルのバインディングの登録は、RouteServiceProviderクラスの boot メソッドに書きます。

以下、公式ページの例です。

public function boot()
{
    parent::boot();

    Route::model('user', App\User::class);
}

次に、{user}パラメーターを含んだルートを定義します。

Route::get('profile/{user}', function (App\User $user) {
    //
});

全ての {user} パラメーターは App\User モデルにバインドされて、User インスタンスがルートで渡されます。例えば、 profile/1 でリクエストされたら、 ID が 1 のユーザーモデルのインスタンスがコールバックの引数の $user に渡されます。

ID が見つからなかった場合は、 404 HTTP レスポンスが自動的に生成されます。

## 解決方法のカスタマイズ

独自に渡されたパラメーターからモデルを取得するロジックを組みたい場合は、 Route::bind メソッドを使うと良いでしょう。bind メソッドに渡した Closure で URI セグメントの値を受け取って、ルートに渡すクラスのインスタンスを返すようにします。

以下、公式サイトの例です。

public function boot()
{
    parent::boot();

    Route::bind('user', function ($value) {
        return App\User::where('name', $value)->first();
    });
}