Laravel Archive
Laravel 5.1(LTS) を解説した「Laravelリファレンス」を執筆しました
- コメント (Close): 0
- トラックバック (Close): 0
「レイヤードアーキテクチャを意識したPHPアプリケーションの構築 ver2」を発表しました。 #DevKan
2015/09/14に行われたDevLove関西にて「レイヤードアーキテクチャを意識したPHPアプリケーションの構築 ver2」を発表してきました。
このセッションは、PHPカンファレンス福岡で発表したものですが、DevLove関西主催の @yohhatu さんからお声がけ頂いて、再演を行いました。ただ、同じ内容では面白くないので、Laravelアプリケーション構築時に意識した点を掘り下げて資料を改変しました。
発表資料
発表資料は以下です。
アプリケーションコードをレイヤ分けする際に、ただのグループとして分離するのではなく、レイヤの責務を明確にする、そしてレイヤ間の依存関係(処理の流れ)を一方向にするのがポイントです。
さいごに
今回は、3 人のスピーカーだったのですが、発表内容を事前に打ち合わせしたわけでもないのに、私、@s_kozake さん、@OkaHiromasa さんの順に抽象度があがって、広いテーマになっていくという流れが面白かったです:)
お二人の発表はもちろんのこと、イベント後の食事会も合わせて、楽しい時間でした。ありがとうございました!
- コメント (Close): 0
- トラックバック (Close): 0
「認証機能に学ぶ Laravel 5 アプリケーション」を発表しました #phpkansai
第21回関西PHP勉強会にて、「認証機能に学ぶ Laravel 5 アプリケーション」というタイトルで発表しました。
Laravel 5 アプリケーションの作り方を知る題材に
Laravel 5には、認証周りの機能がデフォルトプロジェクトに含まれています。そのまま利用できて便利というのはもちろんなのですが、はじめから存在する Laravel アプリケーションのサンプル実装という見方もできるので、これを題材に、アプリケーションの実装で活用できるノウハウをお話しました。
発表資料は、以下です。
勉強会では、これから Laravel を触るという方が多かったので、少しイメージしにくい部分があったかもしれません。今後、Laravel を使っていく中で、ヒントとなることもあると思うので、いつか思い出して頂けると嬉しいです。
これから Laravel を触るなら
ちょうど良い本が今日発売したので、よろしくお願いしますm(_ _)m
Laravel 4がベースですが、こちらで雰囲気掴んで貰えれば、Laravel 5の習得もスムーズですね。
- コメント (Close): 0
- トラックバック (Close): 0
一冊まるごと Laravel な「Laravelエキスパート養成読本」が出ます
「Laravelエキスパート養成読本」が、2015/04/21に出版されます。この本の執筆に参加しました。
昨今、話題のフレームワーク Laravel ですが、ようやく日本語での書籍が登場します。これまで、和訳された電子書籍の本はあったのですが、紙の書籍としては、国内初となります。
目次
目次は、下記のようになっています。バージョンは、Laravel 4 をベースにしており、新機能紹介として、Laravel 5 の内容を加えています。
Chapter1. Laravel をはじめよう Chapter2. MVC モデルが基礎からわかる Chapter3. IoC コンテナ、ファサード、サービスプロバイダ、Eloquent Chapter4. Laravel 5 新機能紹介! Special. PHP フレームワーク最新事情 Chapter5. 実践!REST API アプリケーション
Laravel 公式のドキュメントは、丁寧に書かれており、知りたい機能の解説が分かりやすく書かれています。
ただ、リファレンスとしては分かりやすいドキュメントなのですが、これから Laravel を始める人が網羅的に各機能を知っていくには、やや足りない部分があります。
本書では、Laravel とは、から始まり、Laravel を使って、Webアプリケーションを作る流れを見ていきます。それをベースに、より深いフレームワークの機能や最新版である Laravel 5 の新機能を学んでいきます。さらに、Laravel 以外のフレームワークを見て、Laravel の立ち位置を知ります。最後に、応用編として、REST API アプリケーションを題材に、現場での活用方法を知るという流れです。
この本で、Laravel でアプリケーションを作るという概念を理解していけば、より深い部分は、公式ドキュメントやフレームワークのソースから学んでいけるでしょう。
実践!REST API アプリケーション
私は、「Chapter5. 実践!REST API アプリケーション」を担当しました。
5-1. Laravel で作る REST API アプリケーション 5-2. ルーティング 5-3. コントローラ 5-4. サービス、モデル 5-5. テスト
Laravel の基本的な内容は、他の章で解説されているので、機能の紹介というよりは、実際のアプリケーション開発では、どのように機能を利用していくかという視点で書いています。私自身、Laravel 4で、AngularJS やスマートフォンアプリと連携する REST API を開発した経験を元に書いているので、現場で活用してもらえると嬉しいです。
以前、書いた自分流 Laravel 4 アプリケーションアーキテクチャをベースにしており、独自ディレクトリ構成や、レイヤードアーキテクチャを紹介しています。PHPUnit を使ったファンクショナルテストにも触れており、Laravel でテストを書く際は参考になると思います。
本章では、サンプルアプリケーションを元に解説しており、アプリケーションのコードは、Github 上で公開しています。
https://github.com/shin1x1/gihyo-laravel-book-reservation
Vagrantfile と Ansible によるプロビジョンファイルを同梱しているので、Virtualbox と Vagrant があれば、サンプルアプリケーションが動かすことができます。
予約お待ちしています!
すでに、Amazon でも予約受付が開始されています。
これから、Laravel を触ってみようかなという方はもちろんのこと、現在 Laravel を利用している方にも参考になる内容だと思いますので、ぜひ手に取って頂ければ嬉しいです!
Laravelエキスパート養成読本[モダンなPHP開発を実現するノウハウ満載!] (Software Design plus)
なお、共著者である @hirokws さんの呼びかけで、本書の印税の一部を Laravel プロジェクトへ寄付するつもりです。ありがとう、Laravel。
- コメント (Close): 0
- トラックバック (Close): 0
「Azure Websites で作るスケーラブルな PHP アプリケーション」を GoAzure 2015 で発表してきました
Azure コミュニティの一大イベント GoAzure 2015 にて、「Azure Websites で作るスケーラブルな PHP アプリケーション」という発表を行ってきました。
セッションでもお話したのですが、テーマは、もう一つあり、それは「LAMP(LAPP) ユーザが使う Azure Websites」でした。
Azure は、マイクロソフトのサービスなので、どうしても Windows に最適化されているイメージがあったのですが、普段 Mac で開発して、Linux にデプロイして、運用している人間でも、興味深いサービスであることを伝えようと考えました。
発表資料
発表資料は、こちらです。
発表冒頭で、Azure Websites を使っている方に挙手頂いたのですが、6-7 割の方から手が上がりました。Azure のイベントなので、当然といえば、そうなのですが、利用されているのが多いのだなと実感しました。
PHP で PaaS を使う
以前から、PHP を公式にサポートする PaaS はいくつかあったのですが、海外のサービスが多く、ドキュメントも英語版のみで、日本ではあまり使われていない印象でした。
PaaS の雄である Heroku が、2014 年に正式に PHP に対応したことで、今後、PHP でも PaaS を使うことが広がっていくでしょう。(Heroku も公式サイトは、英語ですが、日本語のブログ記事や書籍があります。)Heroku は、PaaS として非常によく出来ているのですが、残念ながら、日本国内にサーバがありません(2015/01/19現在)。
その点、Azure Websites は、日本国内(東日本と西日本)にサーバがあり、日本語のドキュメントもあるので、PHP で PaaS を使うなら、まずは試してみる価値はあります。
Azure Websites + PHP + New relic が利用できない
発表では、入れ忘れたのですが、困ったことを一つ。
Azure Websites は、Windows Server なので、Windows 版 PHP 用の DLL が無い拡張は利用することができません。主要な拡張は問題無いと思うのですが、私が触った範囲では、一つだけこの問題に当たりました。
それが、New Relic の PHP 拡張です。
Azure 自体は、New Relic と連携ができ、.NET 環境では利用できるようなのですが、New Relic の PHP 拡張は、Windows 版が無いため、利用することができませんでした。
New Relic for PHP の FAQ でも現在は対応されていないことが明示されています。New Relic は便利なので、ぜひ対応してもらいたいところです。
https://docs.newrelic.com/docs/agents/php-agent/getting-started/new-relic-php-faqs#windows
アーキテクチャを明示して欲しい
発表資料には入れていますが、一つの Websites 内にある各インスタンスでは、ストレージ(D ドライブ)が共有されているようです。
検証した結果では、おそらくそうであろうということは分かっていましたし、そうであるという情報も見聞きすることができました。
ただ、最後の裏取りとして、公式のドキュメントで、このことが明示されている箇所を探したのですが、残念ながら、見つけることができませんでした。
PaaS だから、裏側を知らなくても良いだろう、という考え方なのかもしれませんが、アプリケーションを作る上でも、構成を組むにしても重要な部分なので、はっきりと公式サイトで明示して欲しいと思いました。
実際、私自身も検証の段階で、このことを知らずに、想定したような結果が出ずに首を傾げるということを経験しました。
せっかく、共有ストレージのおかげで、スケールアウトが容易という特徴があるのですから、ちゃんと明示した方が双方にメリットがあるのではないでしょうか。
追記:2015/01/24
こちらの記事で共有ストレージであることが記載されているようです。https://msdn.microsoft.com/ja-jp/magazine/dn786914.aspx
さいごに
冒頭でも触れましたが、Azure は、以前は「Windows Azure」という名称だったため、どうしても「Windows ユーザのためのもの」という印象がありました。ただ、今回 Azure Websites を検証してみたところ、あくまでマイクロソフト社が運営しているというだけで、クラウドサービスの一つであるという認識に変わりました。
OSX や Linux 上でも動くコマンドラインツール(npm でインストール)があり、Azure Websites では、Git でデプロイができます。デプロイ時に任意のスクリプト(Bash)を実行することができるので、Composer やフレームワークでのマイグレーションなども自動化できます。
上手くやれば、わりと活用できるシーンはあると思うので、今後も使ってみたいと思います。
無料枠もあるので、まだの方は、ぜひ一度試してみてください。
- コメント (Close): 0
- トラックバック (Close): 0
2014 年に発表したセッションと資料まとめ
2014 年も残すは、あと 1 週間になりました。今年も様々なイベントで登壇しましたので、発表したセッションと資料をまとめてみます。
写真提供:久岡写真事務所
登壇イベント
2014/04/04 「わかってるフレームワーク Laravel」Laravel勉強会福岡
「わかってるフレームワーク Laravel」とうタイトルで発表しました。
Laravel で、とあるプロジェクトの開発が終わった後だったので、Laravel への良さを主観たっぷりでお話しました。
翌日の Laravel Meetup Tokyo と合わせて、一人 Laravel Japan ツアーでした:D
2014/04/05 「知っておくべき Auth オートログイン」 Laravel Meetup Tokyo vol.3
Laravel 4.1.25 以前にあった Auth フィルタ利用時のオートログインの問題点についてお話しました。
いくつかの前提条件は必要ですが、影響度が大きいので、「これはやばい」というのが伝わっていました。
なお、この問題は、4.1.26 にて修正されたので、現在は問題ありません。
Laravel ユーザなら知っておくべきAuthオートログインのこと
2014/04/12 「Vagrant ユーザのための Docker 入門」 第3回コンテナ型仮想化の情報交換会@大阪
Docker が盛り上がってきた時だったので、Vagrant ユーザを対象に Docker 入門をお話しました。
セッション途中でも活発に質問が飛び込んできたり、デモでコンテナ起動の速さに驚きの声があがったりで、盛り上がったのを覚えています。
「VagrantユーザのためのDocker入門」を発表してきました
2014/04/19 「最近なんだか、はてブがおかしい」俺聞け8 in Tokyo
資料未公開
当初は「Webエンジンアとしてご飯を食べていく」という内容を考えていたのですが、事前に、主催の @msng さんから「ブログに関する発表が多くて嬉しい」というコメントがあったので、ブロブに寄せようと内容を変えました:)
会場には、著名なブロガーの方が多く、みなさん同じようなことを感じているようで、発表後の情報交換が捗りました。
2014/04/24 「Vagrant 体験入門」DevLove関西
これから Vagrant を学ぶ方向けに、Vagrant 概要についての発表と体験ハンズオンを行いました。
Vagrant ハンズオンでは、みんなで同一拠点から一斉にプロビジョンを行うので、遅延やエラーが起こったり、環境の違い(Vagrant + VirtualBox が起動するまでの)でトラブルが発生したりで、毎回発見があります。
ハンズオンの資料は Qiita に公開しています。
Vagrant体験入門ハンズオン手順 – 2014/04/24 DevLove関西
2014/06/19 「Heroku で作るスケーラブルな PHP アプリケーション」第16回関西PHP勉強会
Heroku で PHP が正式サポートされたので、スケーラブルな構成をどう組むかという内容でお話しました。
その後、いくつかのプロジェクトで Heroku + PHP を使っているのですが、やはり PaaS として良くできていますね。まだ掴みきれていない部分もあるので、引き続き追いかけていきます。
Heroku で作るスケーラブルな PHP アプリケーション
2014/06/28 「PHPコードではなく PHPコードの「書き方」を知る」PHPカンファレンス関西2014
PHPカンファレンス関西の初心者向けセッションということで、FizzBuzz を題材に、関数化、クラス化、そして自動テストを書くという流れをお話しました。
「PHPコードではなくPHPコードの「書き方」を知る」を発表してきました
2014/07/05 「開発現場で活用する Vagrant」夏の JAWS-UG 三都物語 2014
関西での JAWS-UG イベント、三都物語でのセッションでした。JAWS-UG では久しぶりの発表になりました。
Vagrant を実際に使う例として、デモで実演しながらセッションを進めました。
会場がフランクな雰囲気で、話しやすかったのが印象的でした。あと Yo を使って、バーチャル拍手というかうなずきを送ってもらったりもしましたね。
2014/08/23 「Vagrant 心得 5 ヶ条」DevLove 甲子園 2014 西日本大会
資料未公開
DevLove 甲子園にて、Vagrant についてお話しました。ここでは、Vagrant を活用する上で、気をつけておくと良いことを 5 つにまとめました。
内容は、いずれ blog に書きたいと思います。
2014/10/11 「Ansible ではじめるサーバ作業の自動化」PHPカンファレンス 2014
PHP カンファレンスで、Ansible についてお話しました。発表を聴いた方からは、好意的なフィードバックが多く、「Chef を使っていましたが、Ansible 使ってみます!」という意見もあり、良かったです。
準備している時は、話したいことをどう上手くおさめるかを苦心したので、普段スピーカーをしているコミュニティの仲間から「うまくまとまっていましたね」と言ってもらえ、やはり見ている人には分かるんだなあと感じたりもしました。
このセッションを見た方から、別のイベントでの登壇についてお誘いがあったり、次につながったセッションでもありました。
「Ansibleではじめるサーバ作業の自動化」を発表してきました
2014/12/19 「ビルドサーバで使う Docker」DevLove 関西
年内最後の発表は、やはり Docker でした。今年は、ほんと Docker が躍進した一年でしたね。
Jenkins サーバでの活用例から、導入のポイントや設定方法などをお話しました。
「Jenkinsサーバで使う Docker」を発表してきました
ロクナナワークショップ 「Laravel で学ぶモダン PHP 開発講座」
11 月から、ロクナナワークショップさんにて「Laravel で学ぶモダン PHP 開発講座」という講座を行っています。
みっちり 1 日で、Vagrant や Composer の使い方、Laravel を使った REST API の実装、そして、その自動テストを書くという内容です。
すでに 2 回開催しているのですが、参加された方は熱心に課題に取り組まれていて、講師としても勉強になることが多いです。まとまった時間でじっくり課題をこなしていくので、これから学んでいこうという方にはおすすめです。
次回は 2015/02/17 に開催予定ですので、もし興味がある方は、ご参加下さい。
さいごに
今年を振り返ってみると、自分で名乗り出るよりも、お声がけ頂いて、登壇するという機会が増えました。お声がけ頂けるのは嬉しく、スケジュールやタイミングが許せば、できるだけお引き受けしたいです。
人前で話すというのは、準備も大変ですし、いつも緊張しますが、毎回色々な発見があり、また、終わった後は何ともいえない解放感というか充実感を感じることができます。聴いて頂いた方からのフィードバックも嬉しいものです。
今年も、セッションに参加して頂いた方、イベントにお声がけ頂いた方、本当にありがとうございました。
2015 年は、年始の 1/16 に GoAzure 2015 で登壇する予定です。Websites でスケーラブルな PHP アプリケーションを作るという内容ですので、ご参加お待ちしています!
- コメント (Close): 0
- トラックバック (Close): 0
自分流 Laravel 4 アプリケーションアーキテクチャ
Laravel Advent Calendar 2014 の 9 日目です。
今年の Advent Calendar では、Laravel 5 リリース目前ということで、Laravel 5 の話題が多いのですが、それは他の方にお任せして、ここでは、Laravel 4 でのアプリケーション実装について書いてみます。
Laravel は自由度の高いフレームワークですので、アプリケーションも自由な構成にすることができます。ただ、この「自由さ」が故に、どういう構成が良いのかというのが悩ましい点でもあります。
このエントリでは、私が実際に構築したプロダクトをベースに構成例をご紹介します。Laravel アプリケーションを構築する上での参考になれば嬉しいです。
1. ディレクトリ構成
まずは、大枠のディレクトリ構成から。アプリケーションや開発環境用の Vagrantfile やプロビジョンファイルなどは、Git リポジトリで管理しています。
ディレクトリ構成としては以下になります。
Dockerfile
は、CI サーバで Docker を使って、自動テストを行っているので、そのためです。
Vagrantfile
は、開発環境用の VM を管理するためのものです。アプリケーションディレクトリにルートに Vagrantfile を置いておくと、アプリケーション内のどのディレクトリからでも vagrant
コマンドできるので便利です。
provision/
は、開発環境、上記 CI サーバでの実行環境、ステージング環境用のプロビジョンファイルが入っています。プロビジョンには、Ansible を使っています。本番環境は、構成管理はこちらでは行わないので、デプロイ用の playbook が格納されています。
src/
が、Laravel アプリケーションのコードが入っているディレクトリになります。以下では、この src/ について見ていきます。
. ├── Dockerfile ├── README.md ├── Vagrantfile ├── docker/ ├── provision/ └── src/
1-1. src/ ディレクトリ
src/
の構成は以下です。
このアプリケーションは、Laravel で REST API を実装して、AngularJS で実装したクライアント側と連携して動作するアーキテクチャになっています。また、クライアント側のコンポーネントの管理に、bower を使っており、そのためのファイルやディレクトリがあります。
Laravel 自体は、ベーシックな構成ですが、アプリケーション独自のコンポーネントを格納するために、package
というディレクトリを作っています。これについては、後述します。
. ├── CONTRIBUTING.md ├── Gruntfile.js ├── _ide_helper.php ├── app/ ├── artisan ├── bootstrap/ ├── bower.json ├── bower_components/ ├── composer.json ├── composer.lock ├── karma.conf.js ├── package/ ├── package.json ├── phpunit.xml ├── public/ ├── readme.md ├── server.php ├── spec/ └── vendor/
2. Laravel アプリケーション の役割
Laravel アプリケーションでは、主に以下の役割を担っています。
- HTML の生成、出力
- JavaScript(AngularJS アプリケーション) / CSS などの生成、出力
- REST API の提供(AngularJS アプリケーションと連携)
初期のビューは、Laravel で生成、出力して、あとは、AngularJS + REST API で連携して動作する SPA(Single Page Application) の形です。このアプリケーションでは、特定ユーザのみが利用するものなので、認証を行い、認可されたユーザのみがアプリケーションを利用できるように、ビューの出力も Laravel で行っています。
ほとんどの機能は、REST API にて提供されるので、以降はこの部分について書いていきます。
3. 処理フロー
REST API への HTTP リクエストは、概ね、以下のフローで処理されます。
- Routing – リクエストされた URI から、処理すべきハンドラを決定します。通常は、コントローラのメソッド、簡単な処理ならネイティヴクロージャに処理を委ねます。
- Controller – 処理の起点となります。バリデーションを行い、正常値であれば、サービスクラスのメソッドに値を渡して、実行します。
- Service – 実処理を行う部分です。ビジネスロジックを実行し、Model(Eloquent)を使って、データベースへの操作などを行います。
- Model(Eloquent) – Eloquent を継承したクラスです。データベースへのアクセスを担うとともに、エンティティ固有の処理なども行います。
各フェーズ(レイヤ)では自身の責務に注力すればよく、上位のフェーズを関知する必要はありません。(必要な情報は受け渡されます。)
HTTP レスポンスボディは、JSON で返すので、blade などのビューテンプレートは、ここでは利用しません。
4. アプリケーションクラスの構成(namespace, autolaod)
ルーティング以外のクラスは、app/
以下ではなく、package/
以下に配置しています。また、namespace で、独立したパッケージとして分離しています。
アプリケーションをフレームワークの構成から独立したパッケージとすることで、フレームワークの一部としてアプリケーションを構成するのではなく、アプリケーションの一部としてフレームワークを利用することをイメージしています。
package/ └── Foo/ ├── DomainA │ ├── Command/ <--- CLI Command │ ├── Controller/ <--- Controller │ ├── Model/ <--- Model(Eloquent) │ ├── Service/ <--- Serivice │ ├── Test/ <--- Test │ └── Validation/ <--- Validation ├── DomainB │ ├── Command/ │ ├── Controller/ │ ├── Model/ │ ├── Service/ │ ├── Test/ │ └── Validation/ OneByOne/ └── Laravel ├── Controller/ ├── Exception/ ├── Service/ └── Test/
namespace のトップレベルには、アプリケーション名(Foo)を、次に、ドメインパッケージ名(DomainA / DomainB)が続きます。アプリケーション内でも業務などのドメイン毎にパッケージを分けています。さらに、それぞれのドメインごとに、Controller や Model など役割に応じた namespace を割り当てています。
例えば、Foo システムの DomainA の Controller にある SampleController であれば、Foo\DomainA\Controller\SampleController
となります。
ここでは、Foo システムの他に、汎用コンポーネントを集積した OnebyOne システムも同梱しています。
アプリケーションクラスは、composer.json
にて、PSR-4 を使って、オートロードで読み込めるようにしています。Laravel におけるアプリケーションは、オートローダで読めれば、どこに配置しても良いので、こうした柔軟な構成が可能です。
- composer.json
{ "autoload": { "psr-4": { "Foo\\": "package/Foo" "OneByOne\\": "package/OneByOne" } }, }
5. Routing
ルーティングでは、URI と処理を行うコントローラのメソッドを Route::verbs()
で連結するだけです。
一部、単純にデータベースから値を読み込んで、JSON として返す程度のものは、ネイティヴクロージャで実装しています。
認証が必要な API については、認証用のフィルタを実装しておいて、それを、Route::group()
で指定します。Route::group()
のネイティヴクロージャ内に認証が必要な API の定義を記載します。
Route::when()
では、POST
, PUT
, DELETE
リクエスト場合は、csrf フィルタを適用するようにしています。
Route::pattern()
では、/foo/{id}
の {id}
を受け入れるパターンを定義していまます。こうしておけば、各ルーティングで、正規表現を定義する必要がなく、便利です。
- app/config/routes.php
<?php use Foo\DomainA\HogeController; $apiPrefix = '/api/v1'; // csrf filter Route::when('*', 'csrf', ['POST', 'PUT', 'DELETE']); // patterns Route::pattern('id', '[0-9]+'); Route::group( ['before' => 'auth'], function () use ($apiPrefix) { $controller = HogeController::class; Route::get($apiPrefix . '/foo', $controller . '@read'); Route::post($apiPrefix . '/foo', $controller . '@create'); Route::put($apiPrefix . '/foo/{id}', $controller . '@update'); Route::delete($apiPrefix . '/foo/{id}', $controller . '@delete'); } );
6. Controller
コントローラでは、入力値のバリデーション、サービスクラスの実行、そして、HTTP レスポンスを構築します。
下記は、典型的なコントローラの例です。
コントローラクラスでは、フレームワークの Contoller クラスを継承しています。あと、API 共通処理(JSON レスポンス等)を ApiControllerTrait
というトレイトに実装しているので、これを use
しています。
- package/Foo/DomainA/Controller/SampleController.php
<?php namespace Foo\DomainA\Controller; use Foo\DomainA\Service\SampleService; use Foo\DomainA\Validation\SampleValidatorBuilder; use OneByOne\Laravel\Controller\ApiControllerTrait; class SampleController extends Controller { use ApiControllerTrait /** * @var SampleService */ protected $service; /** * @param SampleService $serivice */ public function __contruct(SampleService $service) { $this->service = $service; } public function create() { // validation $validator = (new SampleValidatorBuilder())->create(Input::all()); if ($validator->fails()) { return $this->validationError($validator->messages()); } $this->service->create(Input::all()); return $this->created(); } }
下記が、ApiControllerTrait の一部です。ここでは、JSON レスポンスを返すメソッドをまとめています。
- package/OneByOne/Laravel/Controller/ApiControllerTrait.php
<?php namespace OneByOne\Laravel\Controller; use Response; use Symfony\Component\HttpFoundation\Response as Res; trait ApiControllerTrait { /** * ok * * @param mixed $message * @return Illuminate\Http\JsonResponse */ public function ok($message = '') { return Response::json($message); } /** * validationError * * @param mixed $messages * @return Illuminate\Http\JsonResponse */ public function validationError($messages = []) { return $this->badRequest('validation', $messages); } /** * BadRequest * * @param string $error * @param array $messages * @return Illuminate\Http\JsonResponse */ public function badRequest($error = null, $messages = []) { $response = [ 'error' => $error, 'messages' => $messages, ]; return Response::json($response, Res::HTTP_BAD_REQUEST); } (snip) }
6-1. サービスクラスのインジェクト
SampleController に戻ります。コンストラクタでは、処理を担うサービスクラスを引数に取ります。コントローラは、フレームワークによって、インスタンス化されるので、Laravel の IoC コンテナにより、SampleService クラスのインスタンスが自動でインジェクトされます。
もちろん、テストなどの際は、自らインスタンス化して、モックオブジェクトを差し込むことも可能です。
6-2. バリデーション
ルーティングによりリクエスト URI に合致したメソッドが実行されます。
ここでは create
メソッドが実行されるとします。コントローラのメソッドでは、まず、入力値のバリデーションを行います。
SampleValidatorBuilder クラスにて、バリデーションクラスのインスタンスを生成します。
SampleValidatorBuilder の実装例は下記です。バリデーションクラスの生成(ルールの設定)をクラス化しておくことで、コントローラからバリデーションルールの設定を逃がすことができ、同じルールを異なる箇所で共有できます。当然、テストからも、バリデーションクラスが生成できるので、バリデーションのテストが書くのが容易です。
このバリデーションビルダのインターフェースとテスト用のトレイとをまとめて、packagist に公開しています。
shin1x1/laravel-validator-builder
- package/Foo/DomainA/Validation/SampleValidatorBuilder.php
<?php namespace Foo\DomainA\Validation; use Shin1x1\ValidatorBuilder\ValidatorBuilder; use Validator; /** * Class SampleValidatorBuilder * @package Foo\DomainA\Validation */ class SampleValidatorBuilder implements ValidatorBuilder { /** * @param array $inputs * @return IlluminateValidationValidator */ public function create(array $inputs) { return Validator::make( $inputs, [ 'name' => 'required', 'email' => 'required|email', ] ); } }
6-3. サービスクラスの実行
入力値が妥当なものであれば、サービスクラスのメソッドを実行します。
サービスクラスのインスタンスは、コントローラのコンストラクタでセットされているので、これを利用します。
処理が正常であれば、created
メソッド(ApiControllerTrait に実装)を呼び出して、201 Created
を返します。
現在は、コンストラクタインジェクションでサービスクラスをインジェクトしているので、1コントローラ=1サービスの形が多いです。(App::make() などで、メソッド内で、サービスクラスのインスタンスを取得する場合もあります。)
6-4. Laravel 5 でのメソッドインジェクション
今後の話ですが、Laravel 5 では、コントローラのメソッドについても、IoC コンテナによる DI が可能になります。これにより、各アクションメソッド毎にサービスやバリデーションビルダがインジェクトできるので、より使いやすくなります。
7. Service
サービスクラスでは、ビジネスロジックなどのドメイン固有の処理を実行します。フレームワークのクラスは継承せず、単なる POPO として実装しています。
ユースケースに対応して実装することが多いので、名称から内容が想起できるもにしています。例えば、予約を扱うアプリケーションなら、ReservationService をクラス名とし、各メソッド名は、予約業務のユースケースである「予約する(book)」「予約を更新する(update)」「予約を取り消す(cancel)」としています。
下記では、Bar クラスのインスタンスを作って、入力値をデータベースに保存しています。
入力値のバリデーションは、コントローラで終わっているので、このクラスで処理する場合は、引数は正当な値であるとみなします。ただ、値の整合性(一意制約などのアプリケーション制約)など、事前条件のチェックはここで行います。もし事前条件に違反している場合は例外を投げて処理を中断します。
- package/Foo/DomainA/Service/SampleService.php
<?php namespace Foo\DomainA\Service; use Foo\DomainA\Model\Bar; class SampleService { /** * @param array $inputs */ public function create(array $inputs) { $bar = new Bar(); $bar->name = array_get($inputs, 'name'); $bar->email = array_get($inputs, 'email'); $bar->save(); } }
8. Model(Eloquent)
モデルは、フレームワークの Eloquent クラスを継承しており(正確には、Eloqent を継承した AppModel クラスを継承)、通常の Laravel アプリケーションで利用するものと同じです。
エンティティ固有の処理などは、こちらに実装します。
- package/Foo/DomainA/Model/Bar.php
<?php namespace Foo\DomainA\Model; use OneByOne\Laravel\Model; class Bar extends AppModel { }
さいごに
Laravel 4 で構築したアプリケーションの構成について見てきました。
考え方の基本は、本文でも書いたとおり、アプリケーションが主で、フレームワークはそれを実現するためのものツールに過ぎないということです。そのため、アプリケーションはフレームワークとは、独立したパッケージとして構成しています。
この考え方をより進めるなら、package/ 以下のクラスについては、フレームワーククラスを利用する箇所はより抽象化していく(例えばリポジトリパターンを利用して、Eloquent と分離するなど)方法もあるのですが、抽象化を進めすぎて、かえって複雑になるのを避けるために、現在の状態に留めています。
構築するアプリケーションにもよるとは思いますが、これまでは、この形がしっくり来ています。(もちろん、今後変わる可能性もあります。)
こうしたアプリケーションを主体にした構成にしておけば、フレームワークのバージョンが変わっても、柔軟に対応できそうです。Laravel 5 では、アプリケーションディレクトリの構成が変わりますが、そもそも別構成にしているので、オートローダで読み込めれば問題ありません。
まだまだ改良していく余地はありますが、こうした柔軟な構成が取れるのも Laravel の面白さですね。
Laravel Advent Calendar 2014、明日は neronplex さんです。お楽しみに!
- コメント (Close): 0
- トラックバック (Close): 0
Laravel 4 データベースを使ったテストで Migration と Seeder を使う
Laravel 4 でデータベースを使ったテストを書く際の Tips です。
自動テストでデータベースにアクセステストを書く際に大切なのが、データベーステーブルのデータをテストで想定された状態にしておくということです。テーブルの内容がテストを実行される度に異なると、ある時はテストが通って、ある時は通らないという状態になります。
この「想定された状態」をセットアップするために、フレームワークで用意されている Migration と Seeder を利用しています。
テストケースでマイグレーション実行
開発を進めていると、データベーススキーマを変更する場合があります。マイグレーションファイルを作成して、php artisan migrate
コマンドで適用するのことになります。テスト用データベースについても適用する必要がありますが、php artisan migrate --env=testing
を実行するのは、少し手間なので、テストケースで実行するようにしています。
artisan コマンドは、PHP コードでは、Artisan::call()
で実行できるので、下記のようにすると、テストクラスでマイグレーションを実行することができます。
<?php public function setUp() { parent::setUp(); Artisan::call('migrate'); }
ただ、マイグレーションは、全てのテストケースで毎回実行する必要が無いので、基底クラスである TestCase
に下記のように実装して、初回のみ実行するようにしています。
<?php class TestCase extends IlluminateFoundationTestingTestCase { protected static $databaseSetup = false; /** * */ protected function setUpDatabase() { if (static::$databaseSetup) { return; } Artisan::call('migrate'); static::$databaseSetup = true; } /** * Creates the application. * * @return SymfonyComponentHttpKernelHttpKernelInterface */ public function createApplication() { $unitTesting = true; $testEnvironment = 'testing'; return require __DIR__ . '/../../bootstrap/start.php'; } }
データベースを使うテストクラスでは、下記のように setupDatabase
メソッドを実行して、マイグレーションを実行します。(実際にマイグレーションが実行されるのは初回のみ)
<?php class FooTest extends TestCase { public function setUp() { parent::setUp(); $this->setUpDatabase(); } }
フィクスチャとして Seeder を使う
Laravel には、テーブルのデータを一括登録する仕組みとして Seeder があります。テーブルへの登録処理を書いておくと、php artisan db:seed
コマンドでデータを登録することができます。主にアプリケーションで必要なマスタデータや初期データを投入するのに使われますが、これをテスト時のフィクスチャとして利用します。
Seeder クラスは、app/database/seeder
以下に配置するのが通常なのですが、フレームワークとしては、オートローダーで読み込むことができれば、どこに配置しても構いません。
テスト用の Seeder クラスは、テストケースと密接な関係にあり、テストに応じたレコードを用意する必要があるので、同じ PHP ファイルに定義しています。クラス名は、テストケースクラス名の後ろに Seeder
を付けています。こうすれば、どのテストケースでも、同じファイルにある Seeder クラスを __CLASS__ . 'Seeder'
で参照できます。
<?php class FooTest extends TestCase { public function setUp() { parent::setUp(); $this->setUpDatabase(); $this->seed(__CLASS__ . 'Seeder'); } } class FooTestSeeder extends Seeder { public function run() { Eloquent::unguard(); Item::truncateAll(); Item::create( [ 'id' => 1, 'name' => '商品1', 'price' => 100, ] ); } }
Item::truncateAll()
は、PostgreSQL 環境で、truncate を実行するために独自に実装したメソッドで、下記のような実装になっています。TRUNCATE
文に RESTART IDENTITY CASCADE
を付けることで、テーブルのシーケンス値のリセットと、このテーブルを外部参照しているテーブルを同時に削除することができます。
<?php class AppModel extends Eloquent { /** * for test */ public static function truncateAll() { $table = (new static)->getTable(); $sql = 'TRUNCATE ' . $table . ' RESTART IDENTITY CASCADE'; DB::table($table)->getConnection()->statement($sql); } }
複数のテストケースで共有する場合は、app/database/seeder
に配置して、$this->seeder('TestCommonSeeder')
などで実行します。
さいごに
冒頭に書きましたが、データベースを利用したテストでは、事前に想定した環境を作っておくことが肝になります。
Seeder をフィクスチャとして使うことで、アプリケーションの機能を使うことなく、テストに必要な状況を作り出すことができます。テストの中で、テスト対象以外のアプリケーションコードを実行すると、何をテストするためのものなのかが、ぶれてしまうので、環境構築はフレームワークやライブラリで用意された機能のみでシンプルに実現するのが良いでしょう。
- コメント (Close): 0
- トラックバック (Close): 0
Laravel 4 環境ごとの設定
Laravel には、アプリケーションの設定を環境によって切り替える機構があります。これを使うことで、開発環境、ステージング環境、本番環境、テスト環境で設定を切り替えることができます。
ここでは、Laravel 4.2 を対象とします。
環境設定の指定
環境設定の指定は、bootstrap/start.php
の以下の箇所で行ないます。デフォルトでは、ホスト名がhomestead
の場合はlocal
、それ以外はproduction
となります。
$env = $app->detectEnvironment(array( 'local' => array('homestead'), ));
このdetectEnvironment
メソッドでは、クロージャが引数の場合、その戻り値を環境設定として扱うことができます。
私は、環境変数での切替の方が扱いやすいので、LARAVEL_ENV
という環境変数の値を取得して、それを環境設定としています。環境変数に指定が無ければ、local
をデフォルトの設定としています。
$env = $app->detectEnvironment(function () { if (getenv('LARAVEL_ENV')) { return getenv('LARAVEL_ENV'); } return 'local'; });
環境変数であれば、Web サーバの設定なり、シェルの設定なり、アプリケーションの外から渡すことが容易なので、柔軟に設定を切り替えることができます。
例えば、あるプロジェクトでは、本番へのデプロイ時に.htaccess
を動的に生成して、その中でSetEnv LARAVEL_ENV production
を記述するタスクを自動実行するようにしています。また、Heroku 環境では、アプリケーションに環境変数が設定できるので、そこでLARAVEL_ENV=heroku
を設定しています。
環境ごとの設定
環境ごとの設定は、設定ファイルのディレクトリを作成することで指定することができます。
まず、メインとなるのが、app/config/
以下の設定です。ここに上記で指定した環境設定をディレクトリとして作成して、その下に設定ファイルを設置すると、それが読み込まれます。
app/config/ + local/ <--- local 用設定 + app.php ... + production/ <--- production 用設定 + app.php ... + heroku/ <--- heroku 用設定 + app.php ...
設定は、まず、デフォルト(app/config/
直下)の各ファイルが読み込まれ、環境ごとのディレクトリにある設定ファイルの内容がそれに上書かれるという動作になります。よって、環境ごとのディレクトリには、デフォルトから変更の必要があるファイルのみ設置します。また、設置したファイルでも全ての要素を記述する必要はなく、変更が必要なもののみ記述します。
例えば、app/config/app.php
はデフォルトのままの場合、app/config/local/app.php
では下記のように記述します。
この設定では、app.php
の debug
と provider
について変更を行っています。debug
は true
に変更しています。providers
では、デフォルトの値は全て有効にして、追加のみ行ないたいので、append_config
関数で追加する ServiceProvider のみ指定しています。
このように変更差分にのみ記述することで、最小限の記述で環境ごとに設定値を変えることができます。
<?php return [ 'debug' => true, 'providers' => append_config([ 'BarryvdhLaravelIdeHelperIdeHelperServiceProvider', 'WayGeneratorsGeneratorsServiceProvider', ]), ];
利用している環境設定
よく利用している環境設定は以下です。
- local = Vagrant VM 開発環境用。
debug=true
、IdeHelper や Generator など開発用 ServiceProvider を組み込む。 - production = 本番環境用。
debug=false
で、開発用 ServiceProvider は除外。暗号キーは、専用のものに。 - statging = ステージング環境用。ほぼ本番環境で、
url
などを変更。 - heroku = Heroku環境用。Heroku では、各種アドオンとの接続情報を環境変数から得るので、そのあたりを各設定ファイルに記述。
- testing = 自動テスト環境用。テスト用データベース設定など。これはフレームワークで予約されており、テスト実行時には自動で指定される。
artisan コマンド
artisan コマンドでも同じフローで環境が決定されるのですが、それとは別に--env
オプションで指定することができます。
下記のように local
環境においても、--env=production
を指定すると production
環境で実行することができます。
$ php artisan env Current application environment: local $ php artisan env --env=producion Current application environment: producion
さいごに
Laravel の環境設定について見てみました。
多様な環境について設定を切り替える機構は便利なもので、とても重宝しています。
いまは環境変数での指定に落ち着いていますが、staging などで、artisan コマンド実行時に--env
を指定する手間を省くために、.laravel_env
のような環境を指定するファイルを用意して、そこに環境設定を記述して、それを読み込むというようなことも考えています。(.laravel_env は .gitignore して、デプロイ時に自動生成する想定。)
.laravel_env
があればそれを使い、無ければ環境変数から読むという流れです。
どのように環境を決定するかということも、アプリケーションで柔軟に変更できるというのも良くできているところですね。
参考
- コメント (Close): 0
- トラックバック (Close): 0
PhpStorm から Vagrant VM の PHP アプリケーションをリモートデバッグする(Web & CLI)
PhpStorm から Vagrant で構築した VM の PHP アプリケーションをリモートデバッグする方法です。Web アプリケーションだけでなく、CLI アプリケーションでもリモートデバッグできるように設定していきます。
VM スペック
- 192.168.33.41 を private network で設定
- PHP + Xdebug がインストール済み
- ホストと VM は、synced folder でディレクトリを共有(/path/to/src -> /share)
0. Xdebug によるリモートデバッグの仕組み
リモートデバッグを設定する前に PhpStorm と Xdebug がどのように通信するかを見ておきます。これを理解しておくと設定がスムーズです。
下記は、Xdebug の公式サイトに掲載されている図です。ここでは、左の「IDE」が PhpStormが起動しているホスト、右の「PHP/Xdebug」が Vagrant で構築した VM と考えて下さい。
VM に HTTP リクエストが来て、PHP スクリプトの実行がはじまると、PHP/Xdebug が IDE(xdebug.remote_host
で設定したホスト)に DBGP connect の通信を行います。PhpStorm ではこの通信を受け取り、以後は DBGP で相互に通信してリモートデバッグを実現します。
ここで大切なのは、PHP/Xdebug(VM)から、PhpStorm へ DBGP connect の通信が来るという点です。これは Web でも CLI でも同じで、PHP スクリプトが VM で実行されると PhpStorm へ DBGP connect が送られてきて、リモートデバッグを開始することができます。(xdebug.remote_autostart= On
を設定した場合)
もし、うまく動かない場合などは、この点を意識して調査すると良いです。
では、実際に設定を行っていきましょう。
1. VM での設定
まず、VM にインストールされている PHP にリモートデバッグ用の設定を行います。通常は、VM を構築する際に実行するプロビジョニングに以下を含めておきます。
Xdebug が必要になるので、下記のコマンドなどで、インストールしておいて下さい。
$ yum -y install php-pecl-xdebug
1-1. php.ini(xdebug.ini)
Xdebug の設定を php.ini
等で以下のように設定します。
xdebug.remote_enable = On xdebug.remote_autostart = On xdebug.remote_host = 192.168.33.1
xdebug.remote_enable
で、リモートデバッグを有効にします。xdebug.remote_autostart
を On にすることで、リモートデバッグが常に開始されるように設定します。任意のタイミングだけ開始することもできるのですが、開発環境なので、VM側では常に開始されるようにしておき、実際にデバッグを行うかどうかは PhpStorm 側で操作します。xdebug.remote_host
で、デバッグクライアントの IP を指定します。Vagrant の private network で192.168.33.xxx
を設定しているので、ホスト側の IP として192.168.33.1
を設定しています。
1-2. 環境変数
CLI アプリケーション(phpunit
コマンドでのテストを含む)でのデバッグを行うために、環境変数PHP_IDE_CONFIG
を設定します。
CLI アプリケーションを実行するユーザでPHP_IDE_CONFIG
環境変数を定義したいので、ここでは、vagrant ユーザの ~/.bashrc
に設定しておきます。
192.168.33.41
の部分には、VM の IP を指定しておきます。
export PHP_IDE_CONFIG="serverName=192.168.33.41"
もし、apache ユーザで CLI アプリケーションを実行するなら、httpd.conf 等の SetEnv
などで設定すると良いでしょう。
2. PhpStorm での設定
PhpStorm でリモートデバッグクライアントの設定を行いましょう。
2-1. PHP Remote Debug
まず、メニューの [Run] – [Edit Configurations…] をクリックして、[Run/Debug Configurations] ダイアログを開きます。
次にダイアログ左上にある [+] をクリックして、[PHP Remote Debug] を選択します。すると、下記のように PHP Remote Debug の設定フォームが表示されます。ここでリモートデバッグの設定を入力していきます。
Name には、この設定の名称を指定します。ここではVagrant
としています。
Servers には、PHP サーバをプルダウンで選択するのですが、まだ設定が無いので、後ほど設定します。
Ide key は、今回は設定不要なのですが、何かしら値が必要なので、ダミー値を入力します。
2-2. Servers
Servers にサーバを追加するために、Servers のプルダウンメニュー横にある「…」ボタンをクリックします。クリックすると、[Servers] ダイアログが開きます。
[Servers] ダイアログでは、PHP アプリケーションが動作しているサーバの情報(ここでは Vagrant VM)を設定します。
ダイアログ左上にある [+] をクリックして、新規サーバを入力します。
Name には、名称を入力します。名称は何でも良いのですが、ここでは VM の IP を入力します。この値は、VM で設定した環境変数PHP_IDE_CONFIG
の中で記述するserverName=
の値と同じ内容にする必要があります。
Host には、VM の IP を入力します。
Use path mappings にチェックを入れます。ここでは、ローカルのファイルパスと VM でのファイルパスをマッピングを設定します。
この Vagrantfile では、ローカルの /path/to/src
を VM 上では /share
というディレクトリにマウントしているので、File/Directory
で /path/to/src
を選択し、その右にある Absolute path on server
に /share
と入力しておきます。
設定例は下記になります。
[OK] をクリックすると Servers ダイアログが閉じます。この時に [Run/Debug Configurations] では、Servers
には、現在設定したサーバが選択されています。
最後に [OK] をクリックすると、設定が保存され、ダイアログが閉じます。これで設定は完了です。
3. 動作確認
では、実際にリモートデバッグを試してみましょう。
PhpStorm でリモートデバッグを有効にするには、[Run] – [Start Listen for PHP Debug Connections] をクリックします。クリックすると [Stop Listen for PHP Debug Connections] という表示に切り替わります。この状態で、再度クリックするとリモートデバッグが停止します。
今回の設定では、VM 側は常にリモートデバッグ可能な状態になっているので、PhpStorm でのこの操作でリモートデバッグを行うかどうかを切り替えることができます。
リモートデバッグが動作しているか確認するのに、[Break at first line in PHP scripts] にもチェックを入れておきます。
3-1. Web アプリケーション
では、ブラウザから、VM にある PHP スクリプトにアクセスしてみましょう。(ここでは、Laravel アプリケーションを動かします。)
http://localhost/
にアクセスすると、処理が停止して、PhpStorm のデバッガが起動しました。
これは [Break at first line in PHP scripts] にチェックが入っているためで、一番はじめの行で処理が停止するようになっています。[Step Over] や [Step into] で、順にコードを実行して、PhpStorm 上で実行されている行が正しく遷移するか確認すると良いでしょう。
確認が終わったら、[Run…] でコードを実行する、もしくは [Stop] で停止させましょう。
3-2. CLI アプリケーション
CLI アプリケーションについてもリモートデバッグができるか確認しましょう。
vagrant ssh
で、VM にログインして、何か PHP アプリケーションをコマンドラインで起動します。ここでは php artisan
コマンドを実行します。
$ php artisan
すると、Web アプリケーションと同じく、はじめに実行される行で処理が停止し、PhpStorm のデバッガに制御が移ります。
PHPUnit なども実行して、同様になるか確認しておくと良いでしょう。
これで、Web でも CLI でも PHP アプリケーションでリモートデバッグができるようになりました。あとは順に実行するなり、任意のコードにブレイクポイントを仕掛けるなり、デバッグを行うことができます。
なお、動作確認用にチェックしておいた [Break at first line in PHP scripts] ですが、アプリケーション実行の度に停止するのは面倒なので、普段はチェックは外しておきましょう。
4. トラブルシューティング
4-1. デバッガが起動しない
おそらく基本的な設定ミスなので、手順を再確認します。
- xdebug 関連の設定変更後に Apache/php-fpm の再起動を行う
- PhpStorm で[Start Listen for PHP Debug Connections]を行う
4-2. デバッガは起動するのに、ステップ実行できない
PhpStorm の [Servers] 設定のパスマッピングの設定を見直します。
4-3. Cannot accept external Xdebug connection: Cannot parse the value of ‘$_SERVER[‘PHP_IDE_CONFIG’]’
CLI アプリケーションでリモートデバッグを行う際に発生しました。
環境変数PHP_IDE_CONFIG
が正しくセットされていなかったので、VM 側の設定を見直します。
さいごに
PhpStorm から Vagrant で構築した VM へのリモートデバッグ設定について見てきました。
はじめは面倒に見えますが、慣れてくればかなり楽に設定できます。VM 側の設定は、プロビジョニングに記述しておくと良いでしょう。
やはり、処理の流れはデバッガを使った方が掴みやすいので、ぜひ活用してみてください。
参考
http://www.jetbrains.com/phpstorm/webhelp/run-debug-configuration-php-remote-debug.html
http://www.karakaram.com/phpstorm-vagrant-remote-debug
http://blog.jetbrains.com/webide/2012/03/new-in-4-0-easier-debugging-of-remote-php-command-line-scripts/
- コメント (Close): 0
- トラックバック (Close): 0
- 検索
- フィード
- メタ情報