tanaka's Programming Memo

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

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

GitHubでみんなで開発2016年度版-管理者編

オリジナルリポジトリーを管理できるように、プルリクエストの対応方法をまとめます。

前提

準備

すでにプルリクエストされるリポジトリーがあれば、プルリクエストをダウンロードするへ進んでください。練習をしたい人は、二人以上のグループで、以下の作業をしてください。

Webブラウザーhttps://github.com を開いて、ログインしてから作業を開始しましょう。

リポジトリーを作成する

Unity の新規プロジェクトを作成して、プルリクエストを送りあってみましょう。

  • Unity を起動して、New で AdminRensyu などの名前でプロジェクトを作成

バージョン管理をしやすくするための設定をします。[Inspector]ビューで、以下を設定してください。

  • [Edit]メニューから[Project Settings]>[Editor]を選択
  • [Version Control]欄を[Visible Meta Files]に変更
  • [Asset Serialization]を[Force Text]に変更 f:id:am1tanaka:20170204234425p:plain

保存します。

  • [File]メニューから[Save Scene]を選択して、[Test]などのシーン名で保存
  • [File]メニューから[Save Project]を選択

以上で、雛形の状態ができました。これを GitHub Desktop に登録します。

GitHubへの登録

  • [Project]ビューの[Test]スクリプトを右クリックして、[Show in Explorer]を選択して、プロジェクトの場所をエクスプローラーで開く
  • Assets フォルダーが開くので、一つ上のフォルダーへ移動 f:id:am1tanaka:20170204234520p:plain
  • そのフォルダーのパスをコピーしておく
  • GitHub Desktop を起動
  • 左上の[+] > [Add] をクリック
  • [Local path]欄に、先ほどコピーした Unity のプロジェクトフォルダーのパスを貼り付ける f:id:am1tanaka:20170204234536p:plain
  • 下に!が表示されて、[create a repository]がクリックできるので、クリック(!のメッセージが表示されない場合は、Unityのプロジェクトを、Unity Projects フォルダーか、GitHub フォルダー内に移動してから、再度試してみてください)
  • [Create]に切り替わるので、[Git ignore]を[Unity]にして、[Create repository]をクリック f:id:am1tanaka:20170204234551p:plain
  • [Changes]をクリック
  • [Summary]欄に「プロジェクトを追加」などと入力して、[Commit to master]をクリック
  • Publishを押す
  • Description欄に「GitHubの管理者練習用リポジトリー。」などのように入力
  • [Publish <リポジトリー名>]をクリック

以上で、練習用のリポジトリーの作成が完了した。

練習用リポジトリーのフォークとクローン

作成した練習用リポジトリーの URL を、練習相手と教えあいましょう。自分が作成した練習用リポジトリーの URL の確認方法は以下の通りです。

練習相手のリポジトリーの URL を Webブラウザーのアドレスバーに入力して開きます。

GitHubでみんなで開発2016年度版 - tanaka's Programming Memo の手順に従って、練習相手のリポジトリーをフォークして、 GitHub Desktop でクローンをしてください。

Unity で変更を加える

クローンしたリポジトリーは、 AdminRensyu-1 のような名前になっていると思います。それを、 Unity で開いてください。

  • Unity に切り替える
  • [File]メニュー > [Open Project…] を選択
  • クローンしたリポジトリーのフォルダーを選択して開く

Unityが起動したら、以下の変更を加えましょう。

  • [Hierarchy]ビューの[Create]をクリックして、[3D Object]>[Cube]で立方体を作成する
  • 作成した[Cube]を選択して、[Inspector]ビューの[Add Component]をクリックして、[New Script]を選択
  • 名前を[Test]などにして、[Create and Add]を選択して、スクリプトを作成して、Cubeにアタッチする
  • [File]>[Save Scenes]でシーンを保存
  • [File]>[Save Project]>でプロジェクトを保存

以上で、プルリクエストする内容ができました。

プルリクエストの作成

プルリクエストを作成します。プルリクエストをする前に、コミットしておく必要があります。

  • GitHub Desktop に切り替える
  • [Changes]をクリック
  • [Summary]欄に「Cubeの追加」などと入力して、[Commit]

プルリクエストを実行します。

  • GitHub Desktop の[Pull request]をクリック f:id:am1tanaka:20170202234904p:plain
  • [from master into ・・・]の部分が[master]としか表示されていなかったら、[master]をクリックして、[Other branches]の下に表示されているリポジトリーを選択する
  • Title 欄と Description 欄に、相手に伝えたいコメントがあれば入力する。特になければそのままでよい
  • [Send pull request]をクリック

以上で、プルリクエストを発行することができました。Webブラウザーで自分の練習用リポジトリーを開いて、プルリクエストが届くのを待ってください。

プルリクエストをダウンロードする

自分が管理している GitHub リポジトリーにプルリクエストが届いたら、プルリクエストされたリポジトリーを手元のPCにダウンロードして、動作確認をしましょう。

  • WebブラウザーGitHub を開いてログイン
  • 管理しているリポジトリーを開く
  • プルリクエスト(Pull Requests)タブをクリック f:id:am1tanaka:20170204233414p:plain
  • リストが表示されるので、確かめたいプルリクエストを選択
  • [open this in GitHub Desktop]のリンクをクリック f:id:am1tanaka:20170204233437p:plain

クリックしてから、実際に実行されるまでしばらく時間がかかる場合があります。反応がなくても、1分程度は待ってください。

GitHub Desktop が起動して、ブランチが[pr/23]のように表示されれば成功です。プルリクエストされたプロジェクトを確認できます。

プルリクエストされた状態を確認

プルリクエストされた状態の動作を確認します。

  • 画面左のリポジトリーを右クリック
  • [Open in Explorer]を選択して、クローンしたフォルダーを確認
  • Unityを起動
  • [Open]を選択して、クローンしたフォルダーを選択して開く

プロジェクトが開いたら、実行して、動作を確認します。

変更されたファイルを確認する

何が変更されたかは把握しておく必要があります。GitHub Desktop で簡単に確認ができます。

  • [History]をクリック
  • コミットのリストが表示されるので、確認したいコミットをクリック
  • 画面右に、変更があったファイルの一覧が表示される
  • [+]をクリックすると、中身が確認できる。問題点がないかを確認する f:id:am1tanaka:20170204233634p:plain

問題点を報告

動作確認や、変更されたファイルをチェックして、不具合があったり、コードがよくなかったりした場合、修正して欲しい箇所をプルリクエストした人に知らせて修正をお願いします。

  • Webブラウザーでプルリクエストのタブを開く
  • マージ欄の下の [Leave a comment] 欄に、伝えたいコメントを書いて、[Comment]ボタンを押す f:id:am1tanaka:20170204233733p:plain

これを、受け入れができる状態になるまで繰り返します。

変更を受け入れる

プルリクエストの内容に問題がなくなったら、最新の master ブランチに結合(マージ)します。

マージする時にファイルに変更があってはいけません。自分で修正したことがあればコミットをします。

変更を取り消す操作

変更した覚えがないのに、変更があったら以下の操作で変更を取り消すことができます。

  • GitHub Desktop の[Changes]を選択 > 取り消したい変更を右クリック > [Discard changes]を選択 f:id:am1tanaka:20170204234049p:plain

以上で、前回コミットした状態に戻すことができます。

マージ

変更点がなくなったら、 master ブランチに、プルリクエストの内容を取り込みます。手順が逆にならないように注意してください。

  • GitHub Desktop のブランチをクリックして、[pr/??]ブランチを[master]に切り替える f:id:am1tanaka:20170204233857p:plain
  • [Compare]をクリックして、[pr/??]に切り替える
  • [Update from pr/??]をクリック

以上で完了です。ブランチの方向を間違えたり、失敗したら、一度クローンしたフォルダーを削除して、プルリクエストの内容をクローンするところからやり直すと楽です。

GitHubへ反映させる

何も起きなければ、GitHub Desktop で [Publish]、或いは[Sync]を押して、 GitHub へ反映させれば完了です。

Issues を閉じる

Pull Request が Issues で報告されている内容を解決するものであったら、その Issues を閉じましょう。

  • GitHub Desktop の左からリポジトリーを右クリックして、 [View on GitHub]を選択して、WebブラウザーGitHub を開く
  • [Issues]をクリック
  • 一覧表示の中から、処理した Issues をクリック
  • コメントがあれば [Leave a comment] 欄に入力する。なければ空欄でよい
  • [Close issue]を押す f:id:am1tanaka:20170204234149p:plain

以上で、Issue がクロースされて、リストから非表示になります。[Issues]タブをクリックして、Issue リストを表示すると、閉じた項目は表示されなくなります。 [Closed]をクリックすると、閉じた Issue を見ることができます。


コンフリクトさえ発生しなければ、ここまで OK です。ここからは、コンフリクトが発生した時に備えての演習を紹介します。

コンフリクト解決の練習

master ブランチに何事もなくマージできればよいのですが、同時に同じ場所を編集した場合、コンフリクト(Conflict=衝突)が発生します。これの解決が、共同開発する時の最大の難題です。コンフリクトが発生した時の対応方法を練習しましょう。プルリクエストの練習で利用したリポジトリーで引き続き作業をしましょう。

プロジェクトを開く

  • Unity に切り替える
  • [File]メニューから、[Open Project]を選択
  • 自分が作成した AdminRensyu プロジェクトフォルダーを選択して開く

コンフリクトを仕込む

コンフリクトは、同じ場所に変更を加えることで発生します。ブランチを2つ作成して、それぞれで Test スクリプトの同じ場所に違う変更を加えることでコンフリクトさせましょう。

  • GitHub Desktop で [Create new branch] を押す
  • [conflict1]などの名前を入力して、[Create new branch]で新しいブランチを作成
  • ブランチを[master]に戻す
  • 同様に、[conflict2]というブランチを作成
conflict2の作業

まずは、conflict2 ブランチに変更を加えます。以下、Unityで作業します。

  • [Cube]の X 座標を -1 にする
  • [Project]ビューの[Test]スクリプトをダブルクリックして、エディターで開く
  • 以下のコードにする
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

    // Update is called once per frame
    void Update () {
        Vector3 next = transform.position;
        next.x+=1f*Time.deltaTime;
        transform.position = next;
    }
}
  • 上書き保存して、Unityに切り替える
  • [File]メニューから[Save Scene]を選択
  • [File]メニューから[Save Project]を選択

実行すると、キューブが右に移動します。これをコミットします。

  • GitHub Desktop に切り替える
  • [Summary]欄に、「座標の変更と右へ移動」と入力
  • [Commit to conflict2]をクリック
conflict1の作業

コミットが完了したら、conflict1 に切り替えて、同じ場所に別の変更を加えます。

  • GitHub Desktop で、ブランチを[conflict1]に切り替える
  • Unityに切り替える
  • リロードの確認ウィンドウが表示されるので、[Reload]を押す
  • [Project]ビューから[Test]シーンをダブルクリック

これで、master からブランチを作成した時点に戻ります。別の変更を加えます。

  • [Hierarchy]ビューから[Cube]を選択
  • X座標を 1 に変更
  • [Project]ビューの[Test]スクリプトをダブルクリックする
  • 起動したら、スクリプトを以下のようにする
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

    // Update is called once per frame
    void Update () {
        Quaternion now = transform.rotation;
        Quaternion rot = Quaternion.AngleAxis(90f*Time.deltaTime, Vector3.up);
        rot = rot*now;
        transform.rotation = rot;
    }
}
  • 上書き保存して、Unityに切り替える
  • [File]メニューから[Save Scene]を選択
  • [File]メニューから[Save Project]を選択

実行すると、キューブが回転します。これをコミットします。

  • GitHub Desktop に切り替える
  • [Summary]欄に、「座標の変更と回転」と入力
  • [Commit to conflict1]をクリック

コンフリクトを発生させる

conflict1 ブランチと conflict2 ブランチを master ブランチにマージして、コンフリクトを発生させます。

  • GitHub Desktop に切り替え
  • [master] ブランチに切り替える
  • [Unity]に切り替えて、ビルドされるのを待ち、ウィンドウが表示されたら[Reload]ボタンを押す
  • GitHub Desktop に戻る
  • [Compare]をクリックして、[conflict1]を選択
  • [Update from comflict1]ボタンを押す
  • [Unity]に切り替えて、ビルドされるのを待ち、ウィンドウが表示されたら[Reload]ボタンを押す

これで、 master ブランチに conflict1 ブランチがマージされます。master は conflict1 を実装開始する時から変更されていないので、コンフリクトは起きません。実行すると conflict1 の内容である Cube の回転が見られます。

次に、 conflict2 ブランチをマージします。

  • GitHub Desktop に切り替える
  • [conflict1]をクリックして、[conflict2]に切り替える f:id:am1tanaka:20170204234752p:plain
  • [Update from conflict2]をクリック
ここでコンフリクトが発生します(Unable to merge=マージできません)!

[View conflicts]を選択して、コンフリクトを表示します。 f:id:am1tanaka:20170204234822p:plain

コンフリクトが発生した一覧が表示されて、右に[!]マークが表示されます。今回は2つのファイルが該当します。これを全て解決します。 f:id:am1tanaka:20170204234833p:plain

コンフリクトを解決する

衝突している部分は、「<<<<<<< HEAD」「=======」「>>>>>>> <ブランチ名>」の3つの記号の行で示されます。

  • 「<<<<<<< HEAD」から「=======」の間は、現在のコード
  • 「=======」から「>>>>>>> <ブランチ名>」の間は、マージしようとしているコード

いずれか一方を残すか、あるいは両方残して、3つの記号の行を削除することで、コンフリクトを解決することができます。まずは、Test.csから解決します。

Test.csを解決

Test.cs には、移動と回転のコードが追加されています。これは、両方とも採用することにします。その場合は、区切りの記号行を削除するだけで解決します。

  • Unity の [Project]ビューで[Test]スクリプトをダブルクリックして、エディターで開く
  • 記号の行を3つとも削除して、以下のようにする
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

    // Update is called once per frame
    void Update () {
        Quaternion now = transform.rotation;
        Quaternion rot = Quaternion.AngleAxis(90f*Time.deltaTime, Vector3.up);
        rot = rot*now;
        transform.rotation = rot;

        Vector3 next = transform.position;
        next.x+=1f*Time.deltaTime;
        transform.position = next;
    }
}
  • 上書き保存する

以上で、 Test.cs の衝突は解決しました。まだ、衝突が残っているので、 Unity に切り替えてもエラーになります。衝突は、全て解決する必要があります。

Test.unityを解決

Unityでバージョン管理をする時の最大の困難は、[.unity]ファイルのような Unity の設定ファイルが衝突した時です。今回は、 Cube オブジェクトの座標に関する設定がコンフリクトしました。プレハブなどでも同じように発生します。

設定ファイルの場合、項目ごとに1つのパラメータになるはずなので、 Test.cs でやったように両方残すことは有り得ません。衝突した変更をした担当者に何を変更したかを聞き取り、どちらか一方の変更を採用するようにします。

今回は、 conflict2 の方を採用することにします。

  • [Unity]に切り替える
  • リロードのダイアログが表示されたら、[Reload]をクリック
  • [Project]ビューから[Test.cs]などを右クリックして、[Show in Explorer]でプロジェクトフォルダーを開く
  • 該当ファイル(ここでは Test.unity )を右クリックして、Atom などのテキストエディターで開く
  • GitHub Desktop で Test.unity を選択すると、変更箇所が表示されるので、行番号を確認する
  • 変更点を、以下のように修正する
    • 変更前
<<<<<<< HEAD
  m_LocalPosition: {x: 1, y: 0, z: 0}
=======
  m_LocalPosition: {x: -1, y: 0, z: 0}
>>>>>>> refs/heads/conflict2
  • 変更後
  m_LocalPosition: {x: -1, y: 0, z: 0}
  • 上書き保存して、 Unity に切り替える
  • ダイアログが表示されたら[Reload]をクリック

以上で全ての衝突が解決しました。 Unity が実行できるようになるので実行してください。座標はやや左から(conflict2の座標)、回転しながら右に移動します。

解決した内容をコミットする

衝突を解決したら、コミットします。

  • Unityで[File]から[Save Scene]、[File]から[Save Project]を実行して、保存する
  • GitHub Desktop に切り替える
  • 衝突しているファイルはチェックが外れているので、チェックを入れる f:id:am1tanaka:20170204235127p:plain
  • 必要であれば、 Summary や Description を書き換える。そのままでよければそのままでよい
  • [Commit to master]をクリック

以上で解決です。

まとめ

簡単なプルリクエストへの最小限の対処方法をまとめました。コンフリクトが発生すると、面倒になることが確認できたと思います。適切にファイルを分割して、作業担当を割り振れば、コンフリクトは減らすことができます。色々と試してみてください。

コンフリクトが発生したら、衝突場所を示す記号の行がテキストファイルに挿入されます。そのままではプログラムは動かなくなるので、残したいコードを残し、不要なコードを削除しながら、記号の行を削除します。

コンフリクトで厄介なのは、 Unity が管理している設定ファイルが衝突した時でした。その場合は、どちらか一方を採用することにして、一方の変更を削除するようにするとよいでしょう。

ここで紹介したことに加えて、書式をチェックする Linter ツールや、自動的テストを導入すると、さらに開発がしやすくなります。手順が飲み込めたら、そのような自動化ツールも調べてみましょう。

色々とややこしいですし、ここに書いてあるのはごく初歩的な部分だけです。実際にやってみると、様々なことが発生することでしょう。それらを沢山体験しておくと、今後に活きてきます。早速、自分たちでプロジェクトを立ち上げて、共同開発に挑戦してみてください。

参考URL

GitHubでみんなで開発2016年度版

(リポジトリー管理者向け記事はこちら)

複数メンバーでの開発は、コードの更新タイミングなどで様々なトラブルが発生しますし、完全な自動化はできません。慣れるまでは失敗はつきものですし、面倒に感じる部分もありますが、避けて通ることはできません。基本的な流れを覚えて、失敗しながら使い始めてみましょう。




利用するもの

基本的には、GitHubリポジトリーを操作する公式アプリのGitHub Desktop(f:id:am1tanaka:20170125215602p:plain)を利用します。

最初のプロジェクトをクローンする段階で、インターネット上の GitHub ページを利用します。


Gitはどうしてややこしいのか

「状態の異なるバージョンのファイルががあちこちにあるから」

図1は、GitHubで開発する時のリポジトリーの様子です。
f:id:am1tanaka:20170202134153p:plain
図1 GitHubリポジトリ
(パソコンのイラスト:かわいいフリー素材集 いらすとやより)

①オリジナルリポジトリ

プログラムの本家本元となるリポジトリーです。管理権限があるメンバーが管理していて、管理権限がない人が勝手に内容を書き換えることはできません。

②フォークされたリポジトリ

オリジナルリポジトリーをコピーしたリポジトリーです。あるリポジトリーを、自分のアカウントのGitHubにコピーすることをフォーク(Fork)といいます。フォークしたリポジトリーは、各ユーザーのアカウントのGitHubに複製されたものなので、自由に内容を変更することができます。

プルリクエスト(Pull Request)をすることで、このリポジトリーで行った開発内容を、オリジナルリポジトリーに反映する提案が行えます。

③ローカルのリポジトリ

開発をGitHub上で行うのは不便なので、手元のPCにリポジトリーをダウンロードして操作します。GitHubから手元のPCにリポジトリーをダウンロードすることをクローン(Clone)といいます。

ローカルで変更を加えたら、コミット(Commit)をして、ローカルPCのリポジトリーを更新します。その上で、プッシュ(Push)、GitHub Desktopではシンクロ(Sync)操作をすることで、フォークされたリポジトリーにその変更内容がアップロードされます。

リポジトリーのまとめ

リポジトリーは、オリジナルのもの、各ユーザーのGitHubアカウントにフォークされたもの、ローカルPCにクローンされたものがあります。それぞれが個別に存在するので、混乱のもとになりやすいです。自分が今操作しているリポジトリーがどれなのかを考えながら操作しましょう。

リポジトリーが密接に同期されないことは混乱の元なのですが、そのメリットは絶大です。管理者でなければ、オリジナルのリポジトリーを変更することはできません。フォークしたものは失敗を恐れずに自由に変更してよいということです。失敗したら、自分のリポジトリーを削除して、オリジナルからフォークをし直せばやり直せるのです。この気軽さが Git の素晴らしさです。


リポジトリーのフォーク

みんなで開発する手始めに、オリジナルのリポジトリーを自分のアカウントにフォークしましょう。

  • http://github.com を新しいタブで開いて、自分のアカウントでログインする
  • ログインが完了したWebブラウザーで新しいタブを開いて、開発に参加したいアカウントのリポジトリーを開く
  • 右上の方にある [Fork] ボタンを押す

f:id:am1tanaka:20170125230237p:plain

フォークが完了したら、リポジトリーページの左上を確認してください。[自分のアカウント / リポジトリー名]となっています。その下に小さい文字で[forked from]とあり、続けてオリジナルのリポジトリーへのリンクが記載されています。
f:id:am1tanaka:20170125230641p:plain

自分のアカウントにフォークしたリポジトリーができました。これをローカルPCにクローンして開発をしていきます。


フォークしたリポジトリーをクローンする

手元のPCで開発できるように、フォークしたリポジトリーをクローンします。

  • GitHub Desktop(f:id:am1tanaka:20170125215602p:plain)を起動
  • ログインしていなければ、ログインする(右上の歯車アイコンをクリックして、[Options...]を選択。Accounts にアカウントが表示されていなければ、アカウント名とパスワードを入力してログインする)
  • 左上の[+]をクリック > [Clone]をクリック > [Filter repositories]欄に、クローンしたいリポジトリー名を入力 > 表示されるリポジトリーを選択 > [Clone <プロジェクト名>をクリック

f:id:am1tanaka:20170125231054p:plain

  • 作業したい場所を指定する。特別なことがなければ、そのままの場所で[OK]でよい

以上で、手元のPCにリポジトリーがダウンロードされました。これで開発を行います。


開発作業

開発の流れを体験してみます。README.md ファイルに、自分の学籍番号と名前を追加する作業をしてみます。

ブランチ(Branch)とは

Gitなどのバージョン管理システムは、様々な状態のリポジトリーを扱うためのブランチ(Branch)という機能を持っています。詳しくは専門書やインターネット上の記事に譲りまして、ここでは基本的な方針を述べます。

  • master ブランチは、常に動作する状態を維持する
  • 開発は、一言で書き表せる程度の目標に分割して、そのためのブランチを作成して、そこで行う
  • 開発が完了したら、オリジナルリポジトリーの master ブランチ(dev ブランチなどの他のブランチにプルリクエストするようなルールがあればそれに従う)に、プルリクエストを発行する
  • プルリクエストは、完成しない状態で送ってもよい。開発者とディスカッションをしながら機能の完成をしていくことができる
  • 機能の実装が完了して、プルリクエストがオリジナルに組み込まれた開発用のブランチは、そのまま放置でよい

master ブランチは、いつでもそこから別の開発が始められるように、バグが無い状態を保ちます。そのためには、 master ブランチ上で開発することは得策ではありません。開発用のブランチを作成して、そこで開発をすることで、 master ブランチは常に動作する状態を保てます。

ブランチを作成する

ブランチは、 GitHub Desktop で簡単に作成できます。それでは名前を追加するためのブランチということで[add-name]というブランチを作成します。

  • GitHub Desktopの[Create new branch]ボタンを押す

f:id:am1tanaka:20170202231537p:plain

  • Name欄に[add-name]と入力して、[Create new branch]を押す
  • ブランチ名が[add-name]に切り替わっていればOK

f:id:am1tanaka:20170202231852p:plain

これで作業用フォルダーの中身が add-name ブランチに切り替わりました。

プロジェクトを変更する

開発用のブランチ[add-name]に切り替わりましたので、作業を行います。

  • GitHub Desktop で、作業したいリポジトリーをクリックして選択
  • 右上の[Atom]ボタンを押す(Atom以外のエディターを利用する場合は、クローンしたフォルダーの README.md をファイルから開く)

f:id:am1tanaka:20170202235007p:plain

  • 適当な場所に、学籍番号と氏名を入力
# yoketoru-unity-2016
2016年度版よけとるUnity for Unity5.5

# メンバーリスト
- 00 たなかゆう
  • 書き込みが終わったら、上書き保存する

以上でこの作業は完了です。次の手順に進みます。

コミット(Commit)とプッシュ(Push/Publish/Sync)

ファイルなどを変更したら、コミットをしてリポジトリーに変更内容を記録します。

  • GitHub Desktop に切り替える
  • (1)[Changes]を押す > (2)[Summary]欄に変更内容を書く(「学籍番号と名前を追加」など) > (3)[Commit to add-name]を押す > (4)[Publish]を押す(2回目以降は[Sync])

f:id:am1tanaka:20170202233113p:plain

以上で、ローカルPCのリポジトリーに変更が記録され、その内容がフォークしたリポジトリーに反映されます。ここまでをワンセットで操作するとよいでしょう。

コミットをすると、その後、いつでもその状態に戻すことができます。コミットは小まめに行うようにしましょう。

ブランチの動作を確認する

コミットが完了したら、ブランチを切り替えることができます。 master ブランチに切り替えて、 README.md がどうなるか確認してみましょう。

  • GitHub Desktop の [add-name]の部分をクリックして、[Default branch]の[master]に切り替える

f:id:am1tanaka:20170202231852p:plain

  • Atom エディターなどで、 README.md を確認する

以下のように、先ほどの変更が消えています。

# yoketoru-unity-2016
2016年度版よけとるUnity for Unity5.5

# メンバーリスト

同様の操作で add-name ブランチに戻してから README.md を確認してください。学籍番号と名前が復活します。ブランチごとに、違う状態が保持されているのです。

ブランチの下に表示される[Other branches]欄には、オリジナルのリポジトリーが表示されています。これを選べば、オリジナルの状態を参照することもできます。
f:id:am1tanaka:20170202234203p:plain

コミットしていない変更があるとブランチは切り替えられません。ブランチを切り替える前にはコミットするようにしてください。

プルリクエスト(Pull Request)

変更が完了したら、オリジナルのリポジトリーに反映してもらうためにプルリクエストをします。

  • GitHub Desktop の右上の[Pull request]を押す

f:id:am1tanaka:20170202234904p:plain

  • 必要であればタイトルを変更。Descriptionに簡単な修正内容を記載。テストや確認点があれば追記して、[Send pull request]を押す

f:id:am1tanaka:20170202235406p:plain

完了したら、[Pull request created]と表示されます。その下の[View it on GitHub]をクリックすると、Webブラウザーが開いて、オリジナルリポジトリーに送られたプルリクエストを見ることができます。

f:id:am1tanaka:20170202235839p:plain

このページで管理者と相談をしたり、駄目な場所があれば指摘されるので、それを持ち帰って改変します。

変更した内容をコミットしてSyncすると、プルリクエストにも自動的に反映します。一度プルリクエストを発行したら、それ以降は、普通に開発をして、コミットしてSyncして開発を進めればよいのです。

完了

管理者がプルリクエストをオリジナルのリポジトリーにマージ(Merge)して組み込まれれば作業完了です。これを繰り返していくことで、複数人数で、一つのプロジェクトを開発していくことができます。


次の開発をする

作業者が自分だけであればよいのですが、複数いる場合は、オリジナルのリポジトリーには他の人の変更も加わっていきます。その変更をローカルのリポジトリーに反映させる方法です。

  • ローカルブランチを[Default branch]の[master]に切り替える
  • [Compere]をクリックして、[Other branches]のオリジナルリポジトリーを選択

f:id:am1tanaka:20170203000918p:plain

  • [Update from <オリジナルのアカウント>/master]をクリック

f:id:am1tanaka:20170203001047p:plain

以上で、オリジナルのリポジトリーの master ブランチの状態を、ローカルリポジトリーの master に反映させました。 README.md を見れば、自分が行っていない変更があれば、それが加わっていることが確認できます。

あとは、また開発用のブランチを新しく作成して、そこで開発→コミット→Sync→プルリクエスト のサイクルで開発してください。


まとめ

以上で、開発者として開発に参加する流れは最低限押さえました。簡単なプロジェクトで作成をしてみましょう。

管理者を引き受ける場合は、ここでやったものの他に、プルリクエストの受け入れと、別々の人たちが同じ場所を変更した時に発生する衝突=コンフリクト(Conflict)の解決が必要になりますが、それはまた別の機会に。

以下、開発時のTipsをおさらいしておきます。

  • オリジナルのリポジトリーから、自分のアカウントにリポジトリーをフォークして開発を開始
  • 自分のアカウントから、開発するPC上にリポジトリをクローンする
  • master ブランチ上では直接開発しない
  • 開発時には、一言で表せる程度の規模の目標を立てて、ブランチを作成
  • コミットとSyncは小まめに
  • プルリクエストは早めに行ってよい
  • 完了したら、オリジナルリポジトリーの管理者によって、プルリクエストがオリジナルリポジトリーにマージされる
  • 最新状態は、 Compare からオリジナルのリポジトリーを選んで、 Update する

困った時は

手元のリポジトリーを削除して、フォークやクローンし直そう。

ブランチの単位は

以下のように、一言で書き表せる程度にしましょう。

  • 得点アイテムを追加する
  • 敵の弾を追加する
  • プレイヤーのバグを直す

コミットはもっと小まめにしましょう。

リポジトリー管理者向けの記事を、こちらにアップしました。


GitHub Pagesのマークダウンにテーマを設定する

はじめに

GitHubの機能の一つである GitHub Pages を使えば、無料で自分のWebサイトや作品のWebサイトをインターネット上で公開することができます。マークダウンで書かれたファイルは自動的にHTMLに変換して表示します。とても便利ですが、デフォルトのスタイルはものすごく質素です(図1)。

f:id:am1tanaka:20170201180641p:plain:h200
(図1)デフォルトのGitHub Pages

GitHub Pages は Jekyll というツールを使ってマークダウンファイルをHTMLに変換していて、あらかじめいくつかのテーマが組み込まれています。それを適用すれば見た目を改善することができます。




方針

方針は以下の2点です。

  • 作品を作成しているリポジトリーとWebページを共存させる(Webページ専用のリポジトリーは作らない)
  • GitHub Page用のデータは master ブランチの docs フォルダーに入れる



前提

以下の環境を前提とします。



GitHub Pages用のフォルダーの作成

プロジェクトフォルダーに docs フォルダーを作成して、GitHubにプッシュします。

  • GitHub Desktop(f:id:am1tanaka:20170125215602p:plain) を起動
  • 作業したいリポジトリーを右クリックして、[Show in Explorer]を選択してエクスプローラーで開く
    • 作業手順を確認したいだけで、作品がない場合は、GitHub Desktop で新しいプロジェクトを作成して、上記の作業をしてください
  • 開いたフォルダーに docs という名前のフォルダーを新規に作成
  • README.md をコピーして、 docs フォルダー内に貼り付ける
  • GitHub Desktop に切り替える
  • 表示を[Changes]に変更
  • [Summary]欄に[docsフォルダーを追加]などのように入力
  • [Commit to master]を押す
  • 右上の[Sync]を押す

以上で、 GitHub Pages 用のフォルダーができました。


GitHubでページの設定

フォルダーができたので、GitHub Pagesをそのフォルダーに割り当てます。

f:id:am1tanaka:20170201182344p:plain
図3 Settings

  • 画面を下にスクロールさせて [GitHub Pages]の欄を表示
  • Source 欄のコンボボックスをクリック > [master branch /docs folder]を選択 > [Save]ボタンを押す(図4)

f:id:am1tanaka:20170201182552p:plain
図4 GitHub Pagesを docs フォルダーに設定

GitHub Pages の設定をした欄の下に表示するための URL が表示される(図5)ので、そこをクリックしてください。ビルドが完了し次第(1分程度かかる可能性があります)、 README.md が成形されて表示されます(図6)。
f:id:am1tanaka:20170201183804p:plain
図5 作品ページのURL

f:id:am1tanaka:20170201211851p:plain
図6 最初のGitHub Pages


テーマを適用

簡素な画面に、組み込みテーマを適用します。

f:id:am1tanaka:20170201212255p:plain
図7 Change Themeボタン

  • 採用したテーマをクリックする
    • クリックすると、そのテーマでの描画イメージがページの下に表示されるので、確認してください
  • 画面右の[Select Theme]をクリックする(図8)

f:id:am1tanaka:20170201213024p:plain
図8 Select Theme

  • デフォルトのマークダウンが表示されるので、ひとまず画面下の[Commit Changes]をクリック(図9)

f:id:am1tanaka:20170201213239p:plain
図9 Commit Changes

以上で適用完了です。作品の GitHub Pages を再読み込みしてください。マークダウンの使い方が記されたページが、選択したテーマで表示されます(図10)。
f:id:am1tanaka:20170201213449p:plain
図10 テーマが適用されたページ


ページ内容を構築する

テーマの設定ができたので、あとはページの内容を作品のものに書き換えます。

ページに必要な画像や素材の準備

作品の紹介に使う画像ファイルや、UnityのWebGLをビルドしたフォルダーを、 docs フォルダーにコピーします。たとえば、以下のような構成にします。

  • docs/images フォルダー内に img0.png と img1.png
  • docs/webgl フォルダー内に Unity でビルドした WebGL のプロジェクト

ページを作成

作品ページをマークダウンで作成します。

  • GitHub Desktop に切り替える
  • 画面右上の[Sync]を押して、GitHub の更新を取得
  • Atom などのエディターで、作品フォルダー内の docs/README.md を開く
  • あらかじめ入力されているマークダウンの例は不要なので削除
  • 作品の紹介マークダウンを入力する。以下、例
# 正月休み課題「鶏Bomb2017」
ver 170108
<p>
<a href="webgl/index.html" target="_blank">
<img src="images/img0.png" height="240px" alt="タイトル画面">
<img src="images/img1.png" height="240px" alt="ゲーム画面">
<p>ゲームで遊ぶ</p>
</a>
</p>

# ルール
画面の上から卵が降ってきます。これを爆風で孵化させてください。

卵が下に落ちて割れたらゲームオーバーです。

# 操作方法
- 画面をタップした場所に爆弾が置かれます
- 爆弾は一定時間が経過すると爆発します
- 爆風で卵を孵してください
- 爆風に触れた爆弾も、爆発します

# 高得点のヒント
- 卵は画面下で孵化させるほど高得点です
- 一つの爆風で、複数の卵を孵すと得点が増えます
- 誘爆させた爆風で孵化させると、得点が増えます

# 既知のバグ
まだ開発中のため、バグがあります。

バグの確認や報告は[こちら](https://github.com/tanakaedu/ToriBomb2017/issues)へどうぞ。

---
Copyright(C)2017 YuTanaka
  • 上書き保存する
  • GitHub Desktop に切り替える
  • [Changes]に切り替えて、 [Summary]に「ドキュメントの作成」などと入力して[Commit to master]を押す
  • 右上の[Sync]を押す

以上で完了です。作品ページを再読み込みしてください。適用したテーマで、作品ページが表示されるようになります。変更が反映するまでに1分程度かかる可能性がありますので、変更が確認できない場合は、しばらく待ってから再読み込みをしてみてください。


ページの上段の変更

一度設定したレイアウトは、 [Settings]メニューから別のテーマを選択すれば切り替えることができます。切り替わるのに1分程度かかる場合があるので、設定したらしばらく待ってください。

ページの先頭は、リポジトリー名とリポジトリーの Description が自動的に挿入されます(図11)。
f:id:am1tanaka:20170201220508p:plain
図11 ページの先頭部分

Description を変更したい場合は、以下のようにします。

  • リポジトリーページを開いて、 Description の右の [Edit]をクリック

f:id:am1tanaka:20170201220955p:plain

  • テキストボックスの内容を変更して、右の[Save]を押す

以上だけでは、ページは更新されないようです。再構築をするには、Settingsから一度別のテーマを設定してから、元のテーマに設定しなおしてください。


まとめ

以上で、デフォルトの状態よりも見た目がよいページにすることができます。似合うテーマを色々と試してみてください。

以下、作例です。


ここでのやり方は、GitHubに予め用意された定型のテーマやレイアウトでの利用にとどまります。自由に見た目を変更したい場合は、 Jekyll というWebサイト生成ツールを利用します。英語ですが、手順が紹介されているページがこちらにあります。興味があれば、調べてみてください。


Hexo3について私見

ある程度、使い方を把握しました。結論としては、肌に合わないので利用は見合わせることにします。

以下、問題に感じた点です。

アセットフォルダーの仕様が整理されていない

アセットデータへのパスの指定方法が整理されていません。結果的に、Markdownで普通に画像を表示させることができません。{% %}を使った特殊な表記で解決することは可能ですが、基本中の基本の機能なだけに、他にやり方はなかったのかと思います。


加工しないページの指定方法が不明

source フォルダーに入っているマークダウンや HTML は、強制的にテーマの形式に変更されます。そのため、Unity で出力した WebGL 用のページをそのまま表示するなどができません。実行もできません。これは最初の問題と関連していて、 JavaScript などへのリンクが切れてしまっているためと思われます。

デプロイを個別にやるとか、あるいは何らかの書き方があるかもしれませんが、そもそも強制的にすべてのページをビルドするという仕様が乱暴に感じました。


まとめ

いったんHexoはあきらめて、Jekyll を改めて調査します。Jekyll も同様な場合は戻ってくるかも知れませんが、ひとまず現段階では Hexo の採用は見送ります。