ごえもん

2014.12.17

Laravel5でサンプルアプリケーションを作成する(Advent Calendar 17日目)

アライドアーキテクツ Advent Calendar 17日目 兼
Laravel Advent Calendar 2014 17日目
の記事です

ごあいさつ

Laravel AdventCalendarの総支配人のytakeさんにQiitaのアドベントカレンダーと会社のアドベントカレンダーを一緒くたにして書いてもいいっすか?って聞いたら快諾してくれたので二つのカレンダーを兼ねるというセコいスタイルでいきます。石川さんです。どうぞよろしくお願いします。

まず、この記事は12/09時点のcommitをベースとして書いています。Laravel5は現在開発中であり記事の内容と違う部分が出てくると思います。(ちなみに、これの記事を書くために前から暖めていたサンプルアプリケーションがあったのですが、12/09時点でだいぶ内容変更が行われたために全てゼロから書き直しました。泣ける話ですね。)なお、新機能っぽいところには「★」をつけてますので、新機能だけでいいんだよという方はその辺だけかっさらっていってください。

前回の記事でもLaravel5の新機能の一つであるLaravel Elixirについて触れましたが、今回は実際にサンプルアプリケーションを作ってみつつ、色々追加された新機能について見ていきたいと思います。ちなみに今回作るサンプルアプリケーションはTodoアプリです。太古の昔から、サンプルアプリケーションといえばTodoアプリ、サンプルデータベースといえば社員表と相場が決まっているのです。

事前準備

環境構築

前回の記事を参照で。

Database

mysqlにlaravel5という名前でDatabaseを作っておきます。

Databaseを作ったらプロジェクトルートでphp artisan migrateとして、テーブルの準備をします。

ディレクトリ構成の確認

Laravel4に比べてLaravel5では大きくディレクトリ構成が異なっています。Laravel5はpsr-4に準拠した構造になり、namespaceを使用する様になっています。まぁこの辺は他の記事でも色々書いてあるので割愛します。実際にインストールしてみてください。

★Environment Detection & Environment Variables

Larvel5では環境に依存する情報はプロジェクトルート配下の.envファイルで管理する様になっています。

とりあえずインストール時に一緒についてくる.env.exampleをリネームしましょう。

.env

configからこの値を参照する様に書き換えていきましょう。とりあえずDatabase部分だけ紹介します。

resources/config/database.php

phpdotenvというライブラリを使っています。プロジェクトのどこからでもgetenvメソッドで.envファイルに指定した値を取り出す事が出来ます。上記を参考にして他の箇所も書き換えていきましょう。

とりあえずアプリ画面を開いてみる

welcome

Laravel4に比べてずいぶんとスタイリッシュな画面がありがたいお言葉と共に表示されました。ロードする度に変化するこのありがたいお言葉はIlluminate\Foundation\Inspiringクラスで実装されています。中身を覗いてこれから一緒に”Smile, breathe, and go slowly”していきましょう。

あ、書き忘れてました。今回サンプルアプリは一旦開発環境に限定しますので、optimizeの結果は潰しておきましょう。

ユーザ認証まわり

★Spiffy Authentication

Laravel5にはデフォルトでメールアドレスとパスワードによるユーザ認証の仕組みがついています。もちろん自分で実装しても大丈夫ですよ!ちょっと中身を覗いてみます。

app/Http/Controllers/Auth/AuthController.php

少し前まではここにごちゃごちゃとコントローラの実装が書いてあったんですが、traitを使う形に変更されています。

コンストラクタインジェクションを使ってGuardとRegistrarが依存注入される仕組みになっています。早速Laravel5のContractsが使われていますね。

★Contracts

GuardにはフレームワークのデフォルトですでにIlluminate\Auth\Guardが関係付けられています。

Registrarは、validatorメソッドとcreateメソッドを持ったinterfaceです。Concrete ClassもApp\Services\Registrarに用意されており、App\Providers\AppServiceProviderで以下の様に紐付けられています。

従って、AuthControllerのコンストラクタで$authにはIlluminate\Auth\Guardが、$registrarにはApp\Services\Registrar がそれぞれ注入されます。

今回はこのままの形でいきますが、ユーザー認証について部分変更したい場合は、AuthControllerで必要なメソッドをオーバーライドし、必要なデータの登録方法をRegistrarクラスで実装してあげれば良いわけですね。

Viewの作成

デフォルトではViewは用意されないのですが、ここについての詳細は主題と逸れるため今回は内容を省きます。viewについてはresources/templates配下に作ることになっていますので、AuthControllerの期待するviewを追加していけば良いです。こんな感じで。

Laravel5 Applications

Laravel5 Applications Login

良い感じに適当になってきました(笑)

Todoリストの実装をする

Modelを作る

ここは大してnewが無いのでさらっと。とりあえずテーブル構成は以下の様にしておき、Todoモデルをappに配置します。

todosテーブル

field type null key default extra
id int NO PRI NULL auto_increment
title varchar NO NULL
limit datetime NO NULL
done tinyint NO NULL
user_id tinyint NO MUL NULL
created_at timestamp NO 0000-00-00 00:00:00
updated_at timestamp NO 0000-00-00 00:00:00

app/Todo.php

Controllerを作る

必要そうなメソッドを考える

Laravel5 Applications Todo

Laravel5 Applications create

こんな感じの画面を作るので以下のメソッドを用意することにします。

  • index => 一覧画面表示処理
  • create => 新規作成画面表示処理
  • store => 新規作成処理
  • edit => 更新画面表示処理
  • update => 更新処理
  • delete => 削除処理
  • check => TODOをチェックする処理

TodoController

Controllerを作ります。ここから新機能を多く使っていきます。

app/Http/Controllers/TodoController.php

リソースコントローラに毛が生えた様なもんですが、とりあえずアクセスパスはこんな感じで良いでしょう。

★Route Annotations

Laravel5はRoutingをAnnotationで指定する事が出来ます。詳細はytakeさんの記事で詳しく解説してくれています。

やってみよう

「TodoControllerに関するルーティングをAnnotationで指定するよ、スキャンしてね」って事をApp\Providers\RouteServiceProviderに書きます。

それではTodoControllerにRoute Annotationを書いていきます。

ここまで書いたら一度ルーティングを確認します。

console

かいつまんで解説

クラスに指定したAnnotation

@Controller(prefix="todo")

アクセスパスのprefixにtodoをつけます。

@Middleware("auth")

Laravel4でいうFilterです。authミドルウェアが適用されます。

メソッドに指定したAnnotation

@Get("{id}/edit", as="todo.edit")

GETメソッドの指定です。Controllerアノテーションでtodoプレフィックスを指定しているので、実際のurlは”todo/11/edit”の様になります。

ここで{id}と指定したルートパラメータはメソッドの引数に指定した変数$idに渡されます。(上の例でいうと11が渡されます)

@Post("{id}/update", as="todo.update")

POSTメソッドの指定です。urlは”todo/12/update”の様になります。id部分についてはGetと同様です。

実装する

アクセスパスの準備が終わったので、中身を実装していきます。

ログイン後に使う事が前提なので、Guardをメンバーに定義することにします。

Todoを扱うコントローラーですから、Todoも定義します。

説明を省きましたが、疎結合にする為にModelを直接使用せず、いわゆるリポジトリパターンの形にしています。eloquentをラップしてそこにちょろちょろと処理を生やしたものです。(機会があれば、別記事で書こうと思います)各リポジトリはinterfaceを用いているため、Concrete Classとの紐付けはAppServiceProviderで行っています。

では、indexの実装をしていきます。

★Method Injection

indexではUserに紐づくTodo一覧を表示します。ページングがしたいので、ペジネーションオブジェクトを取得することにします。この処理はUserRepositoryクラスに実装しました。

TodoControllerはUserRepositoryをコンストラクタ引数で受けていません。indexメソッド以外ではUserRepositoryを使う機会が無いからです。Laravel4の場合、この様なケースではコンストラクタで受ける様にするか、App::make('App\Repositories\UserRepositoryInterface')の様にするしかありませんでしたが、Laravel5ではControllerにおけるメソッドインジェクションをサポートした為、以下の様な記述が可能です。

記述がとてもシンプルになります。また、単体テストをする時にもAppにmockオブジェクトをバインドせず、単純に引数に渡せば良いだけになるので良いですね。

ちょっと脇道に逸れてみる

indexメソッドの実装は上記でおしまいですが、viewについては触れる気はなかったのですが、Laravel5になって若干bladeの仕様が変更されていたので、ついでに紹介しておきます。

★bladeで{{$hoge}}がサニタイジングされる様になった

以前までは{{ $hoge }}は直接出力、{{{ $hoge }}}はHTMLエスケープを行う仕様だったはずですが、{{ $hoge }}もエスケープされる様になりました。代わりに直接出力する場合には{!! $hoge !!}となります。

これ、あんま語られてないけど地味にキツい変更じゃないかと思ってますw

まぁ確かにごっちゃになることがあったしわかりやすくはなったけど、下位バージョンを使っている人たちでバージョンアップする際の障壁になりそうです。「エスケープを気にしなくて良いのは小学生までだよねー」という意識が徹底されたプロダクトにおいては単純に置換すりゃいいんでしょうけども。

★FormRequest

本題に戻ります。storeメソッド(新規作成処理)はformから値を受け付けて、Todoを保存する処理を担います。ここではValidatorとRequestが一緒くたになった新機能のFormRequestを使います。

引数で指定しているStoreRequestが今回追加されたFormRequestです。どんな実装になっているかというと

特に説明しなくても雰囲気が掴めると思いますが、バリデートルールの設定をしています。storeメソッドが呼び出されると、このStoreRequestがフィルタの役割を果たします。自動でリクエスト項目にバリデートを行い、エラーが無ければそのままstoreメソッドを呼び出し、エラーがあった場合にはフラッシュデータにメッセージをセットして呼び出し元のurlにリダイレクトします。(リダイレクト先については$redirectもしくは$redirectRoute$redirectActionで指定できます)

ちなみにauthorizeメソッドについては、ここでfalseを返すと403ページへ遷移する様になっている(デフォルトの挙動はfalseなのでオーバーライドする必要がある)のですが、イマイチ活用方法が見出せませんでした。。。誰か知っていたら教えてください。

POSTの場合にはほとんどのケースでバリデートをすることになるので、FormRequestでバリデートするのは良いアイデアだと思います。また、副次的な効果としてコントローラとバリデーターを切り離す事が出来る為、テストも容易になります。

Controller最終形

あらかた新機能に触れました。最終的にコントローラーはこんな感じになります。

Done!非常にシンプルにコントローラを書く事が出来ました。Getメソッドでdeleteしてんじゃねーよ!という言葉が聞こえてきそうですが、一旦聞こえなかったフリをすることにします(^▽^)

★Middleware

さて、TodoControllerのRoute Annotationに@Middleware("todo.owner", only={"check", "edit", "update", "delete"})をシレっと追加しています。

MiddlewareはLaravel4でいうところのfilterに代わるものです。todo.ownerという名前の通り、対象となるTodoレコードが認証を通過したユーザーの所有物であるかどうかをチェックします。

★New File Generators

僕はあまり使わないのですが、せっかくなので新たに追加された雛形作成機能を使ってみます。

こんな感じの雛形が生成されました。あとはこのhandleメソッドを実装していけば良いだけです。説明するよりもコードを見てもらった方が速いと思うので、以下をご覧ください。

handleメソッド内でTodoレコードの所有者IDと認証済ユーザーのIDが一致するかを判定しています。問題が無ければ、クロージャを呼び出して処理を終了します。

実装完了

なんとか実装が完了しました!良い感じに新機能に触れながらサンプルアプリケーションを作ることが出来ました。開発版といえど、Core部分はほとんど固まっている感じですので、特に大きな問題も無く開発することが出来ました。

おわりに

前回の記事でLaravel Elixirにも触れましたので、あとはMultiple Filesystems(Webストレージ)、Socialite(ソーシャルログイン)、Event Annotationに触れられれば一通りLaravel5の新機能巡り完了なんですけど、まぁそのへんは他の方に任せるとしましょう(オイ

いやーLaravel5、楽しみですね!リリースされたらまたいじくり倒してやろうと思います!!長文お読みいただき、ありがとうございました!

さてさて、明日のアライドアーキテクツ Advent Calendarは弊社新進気鋭のandroidエンジニア、ちっくりーんの番で、Laravel Advent Calendar 2014monaye@githubさんの番です!お楽しみに!