Laravel5で開発を始める前に行っていることをまとめました。各設定ファイルのディレクトリ構成のカスタマイズや、Laravelを拡張するためのコードの配置場所を設定しています。
この方法がスタンダードということはありませんが、開発チームで予め標準化しておくと、保守性も向上するのではないでしょうか。
データベースのマイグレーションやカスタムミドルウェアの設定、Javascript/CSSのビルドなどは割愛しています。
環境
- OS: osx10.11.4
- PHP: PHP5.6.x
- Laravel: 5.2.31
Laravelインストール
現時点では、5.2.31がリリースされているようです。
$ composer create-project --prefer-dist laravel/laravel $ cd laravel $ ./artisan --version Laravel Framework version 5.2.31
gitリポジトリ作成
gitリポジトリを作成します。
$ git init $ git add . $ git commit -m 'initial commit'
動作確認
簡単に動作を確認します。
実際の開発時も、PHPビルトインサーバを利用することが多いです。なんといっても手軽です。
もちろん、Vagrantでステージングサーバを構築して、試験することも併用しています。
また、プロダクションサーバへのデプロイメントもVagrantで作成したステージングサーバで調整・検証しています。プロビジョニングには、Ansibleを利用しています。
今後は、LaravelアプリもDockerコンテナ化して、瞬時にデプロイできるように考えています。
$ php -S 0.0.0.0:8080 -t public/
プロジェクトネームスペースの定義
プロジェクトの固有のソースコードの配置先を変更し、ネームスペースを分離しています。
まず、プロジェクトのソースコードディレクトリを作成します。
ここではHttpディレクトリだけ作成していますが、概ねLaravelのapp/のディレクトリ構成をそのまま、プロジェクトのネームスペースで作成しています。
editorはお好きなものに置き換えてください。筆者は、atomエディタで開発しています。
ディレクトリを作成したらpsr4でオートロードできるようにcomposer.jsonに追加します。
$ mkdir -p srcs/app/Http $ vi composer.json "autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/", "Project\\": "srcs/app/" } },
その後、オートロードファイルを再生成します。
$ composer dump-autoload Generating autoload files
autoload_classmap.phpを参照すれば、追加されていることが確認できます。
$ vi ./vendor/composer/autoload_classmap.php 'Project\\' => array($baseDir . '/srcs/app'),
routes.phpの移動
通常、app/Http/routes.phpに配置されていますが、よく参照・変更するファイルなので、プロジェクトのHttpへ移動します。
好みの問題でもありますから、必須というわけではありません。
$ cp app/Http/routes.php srcs/app/Http $ vi app/Providers/RouteServiceProvider.php
protected function mapWebRoutes(Router $router) { $router->group([ 'namespace' => $this->namespace, 'middleware' => 'web', ], function ($router) { // require app_path('Http/routes.php'); routes.phpのロケーションを変更します。 require base_path('srcs/app/Http/routes.php'); }); }
コンフィグレーションの設定
日本語ファイルを英語のものから作成しておきます。多国語対応する必要がなくても、メッセージの保守性を向上するために言語ファイルに全てのメッセージを定義しています。
$ cp -a resources/lang/en resources/lang/ja
次に、アプリケーションのコンフィグレーションを設定します。
url、タイムゾーン、ロケールの設定とプロジェクト固有のサービスプロバイダを一つ以上設定しています。
$ vi config/app.php
'url' => 'http://www.project.com', 'timezone' => 'Asia/Tokyo', 'locale' => 'ja', 'fallback_locale' => 'ja', 'providers' => [ ... Project\Providers\AppServiceProvider::class, ]
サービスプロバイダの定義
先ほど定義したサービスプロバイダを作成します。プロジェクト固有のサービスプロバイダには、ストレージパスの設定や、bladeで利用するカスタムなディレクティブ、フォームバリデーションで利用する共通のバリデータなどを定義しています。
まず、bootメソッドでストレージパスを変更しています。いままではシンボリックリンクでデプロイごとのストレージが変わらないようしていましたが、今後Dockerコンテナ化も考慮して、任意のパスに変更するようにしました。
その後、Bladeのカスタムディレクティブやカスタムバリデータを定義しています。数が多くなれば、それぞれ別のプライベートメソッドへ移動したり、別のサービスプロバイダを作成します。
サンプルとして、日付をフォーマットするディレクティブ、電話番号をバリデートするものを用意しました。
registerメソッドでは、サービスインタフェースに対して、DI(Dependency Injection)したいクラスを設定しています。コントローラの引数にインタフェースをタイプヒンティングしておけば、ここでbindされたクラスインスタンスが自動的にインジェクションされます(コンストラクタインジェクション)。
$ mkdir srcs/app/Providers
<?php namespace Project\Providers; use Blade; use Validator; use Log; use Input; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { app()->useStoragePath('/tmp/storage'); Blade::directive('date', function($expression) { return "$expression ? (new DateTime{$expression})->format('Y/m/d') : trans('app.none')"; }); Validator::extend('tel', function($attribute, $value, $parameters, $validator) { $value = mb_convert_kana($value, 'n', 'utf-8'); return preg_match("/^[0-9]+$/u", $value); }); } /** * Register any application services. * * This service provider is a great spot to register your various container * bindings with the application. As you can see, we are registering our * "Registrar" implementation here. You can add your own bindings too! * * @return void */ public function register() { $this->app->bind( \Project\Services\ServiceContract::class, \Projet\Services\Service::class ); } }
public function __construct(ServiceContract $service) // Serviceクラスのインスタンスがインジェクトされる。 { $this->service = $service; }
ストレージパスが変更できているかtinkerで確認します。
tinkerはREPL(Read-Eval-Print Loop)と呼ばれるインタラクティブシェルのようなものです。Laravel環境で、小さなコードをインタラクティブに動作させることができます。ちょっとしたデバッグやテストに最適で便利です。
追記:このタイミングでstorage_path()を変更しても、storage/framework/{cache,sessions,views},storage/logsのパスには反映されないことがわかりました。
適切な位置かどうか不明ですが、bootstrap/app.php
で$appを返す前に、$app->useStoragePath('/tmp/storage')
してやると有効になりました。
$ ./artisan tinker Psy Shell v0.7.2 (PHP 5.6.19 — cli) by Justin Hileman >>> storage_path() => "/tmp/storage" >>>
個人的な小さなプロジェクトなら、直接app/にファイルを追加していってもよいのですが、チームで継続して開発するなら、予めこのようなプラクティスを決めておくと、開発効率や保守性が向上するのではないでしょうか。何かの参考になれば、幸いです。