Laravel5 を試したメモ
他のフレームワークを利用している人が、Webアプリを作成するにあたって抑えておくべきポイントだけピックアップしてみた
インストール
ローカル開発環境の準備
Laravel5は、PHPやNginx、MySQLなど必要なパッケージをインストールずみのVagrantローカル開発環境 Homestead 提供している
Homesteadのセットアップ手順については、Laravel 5 ローカル開発環境 homestead 構築手順にまとめている
Laravel プロジェクトの作成
すでにPHP実行環境がある場合は、Composerでプロジェクトを生成して開発を始める
Laravelインストール手順は、DocumentationのInstallationを参照
$ composer create-project laravel/laravel --prefer-dist <project name>
Laravel 5のディレクトリ構成は以下の通り
$ tree -L 2
.
├── app
│ ├── Commands
│ ├── Console
│ ├── Events
│ ├── Exceptions
│ ├── Handlers
│ ├── Http
│ ├── Providers
│ └── User.php
├── artisan
├── bootstrap
│ ├── app.php
│ └── autoload.php
├── composer.json
├── composer.lock
├── config
│ ├── app.php
│ ...
│ ├── database.php
│ ...
│ ├── session.php
│ └── view.php
├── database
│ ├── migrations
│ └── seeds
├── gulpfile.js
├── package.json
├── phpspec.yml
├── phpunit.xml
├── public
│ ├── favicon.ico
│ ├── index.php
│ └── robots.txt
├── readme.md
├── resources
│ ├── assets
│ ├── lang
│ └── views
├── server.php
├── storage
│ ├── app
│ ├── framework
│ └── logs
├── tests
│ ├── ExampleTest.php
│ └── TestCase.php
└── vendor
├── autoload.php
├── bin
...
├── symfony
└── vlucas
48 directories, 31 files
Laravelは、ApacheやNginxなしでも組み込みの開発用サーバーで動作確認できる
artisanコマンドで開発用サーバーを起動
$ php artisan serve
Laravel development server started on http://localhost:8000/
artisanコマンドは、RailsのRake的なコマンド
使い方は、Documentation Artisan CLI Usage を参照
または、artisan listで使用可能なコマンド一覧を参照できる
$ php artisan list
ルーティング
ルーティングは app/Http/routes.php
に記述する
// app/Http/routes.php
<?php
Route::get('/', 'WelcomeController@index');
上記は、プロジェクトの作成後のデフォルト、’/’をWelcomeControllerのindexメソッドにマッピングしている
以下のように、無名関数を指定することもできる
// app/Http/routes.php
Route::get('/', function()
{
return 'Hello World';
});
また、コントローラー全体をパスにマッピングすることも可能
以下のようにRoute::controller
メソッドを使用する
Implicit Controllers – HTTP Controllers
// app/Http/routes.php
<?php
Route::controller('/', 'WelcomeController');
暗黙的なマッピングを利用する場合、コントローラーのアクションメソッドの名前の先頭にHTTPメソッド名をつける必要がある
GETメソッドであれば、get<アクション名>のような形式で記述する
上記の設定で、WelcomeController#indexをgetIndexに変更すると初期表示の画面を確認できる
// app/Controller/WelcomeController.php
class WelcomeController extends Controller {
public function getIndex()
{
return view('welcome');
}
}
ミドルウェア (Http フィルター)
Laravelは、Httpリクエストをフィルタする機能としてHttp ミドルウェアという仕組みを用意している
(4.xまではフィルターだった)
デフォルトでは、CSRFや認証などのミドルウェアが用意されている
ミドルウェアの設定は、コントローラではなく、ルーティングに記述する
CSRF対策
Laravelは、ミドルウェアを明示的に設定しなくても、デフォルトでCSRFプロテクション機能が有効になっている
そのため、POST、PUTおよびDELTEメソッド アクションを含むビューでは、CSRFトークンを含める必要がある
Bladeテンプレートの場合
<?php echo csrf_field(); ?>
Bladeテンプレートの場合
{!! csrf_field() !!}
コントローラー
コントローラーは、app/Http/Controllers
に、App\Http\Controllers\Controller
を継承するクラスを置く
artisanコマンドでもコントローラーを生成可能
$ php artisan make:controller ArticleController
ところでこのmake:controller
コマンドは、アクション名などを引数に取る機能は無いのだが、生成されるコントローラーはRestfullなリソースアクセスを提供する
RESTful Resource Controllers
以下生成されたコード(コメントは割愛)ようにRESTリソースのCRUDのアクションを含むコントローラーが生成されている
// app/Http/Controllers/ArticleController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class ArticleController extends Controller
{
public function index()
{
//
}
public function create()
{
//
}
public function store()
{
//
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update($id)
{
//
}
public function destroy($id)
{
//
}
}
ルーティングは追加されないので、app/Http/routes.php
に手動で追加する必要がある
RSETFullリソース用のルーティングのためのメソッドRoute::resource
が用意されているので利用する
// app/Http/routes.php
Route::resource('article', 'ArticleController');
リクエストパラメータは、Request
ファサードで取得
Requestはuseでインポートする必要あり
// app/Controller/UserController.php
<?php namespace App\Http\Controllers;
use Request;
class UserController extends Controller {
public function postLogin()
{
$username = Request::input('username');
$password = Request::input('password');
// Login process..
}
}
ビュー
基本的なビューの呼び出し方
概要は、The BasicsのViews を参照
ビューのファイルは、resources/views
に置く
ビューへ渡すデータは、view関数の第二引数に渡す
return view('greeting', ['name' => 'James']);
ビュー側は以下のように、渡されたマップのキーで値を参照できる
// resources/views/greeting.php
<html>
<body>
<h1>Hello, <?php echo $name; ?></h1>
</body>
</html>
resources/views
のサブディレクトリに配置したビューの呼び出しは、以下のようにドットで連結して呼び出す(‘/’でも呼び出せる)
return view('article.create');
Bladeテンプレート
Laravelで、共通のヘッダーやサイドバーなどレイアウトを定義する場合、組み込みのテンプレートエンジン Bladeを使う
Bladeの場合、RailsやFuelphpなどの他のフレームワークのように、コントローラーでレイアウトテンプレートをしていするのではなく、子テンプレート側でレイアウトが定義されている親テンプレードを@extends
アノテーションに指定する形で使う
また、ビューのファイルがbladeテンプレートである場合、.blade.php
のように接頭辞に.blade
をつける
以下、Documentations Blade Templatesの例
// resources/views/layouts/master.blade.php
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
このレイアウトを使うビュー
// resources/views/child.blade.php
@extends('layouts.master')
@section('title', 'Page Title')
@section('sidebar')
@parent
<p>This is appended to the master sidebar.</p>;
@stop
@section('content')
<p>This is my body content.</p>;
@stop
JsやCSSなどの読み込みについても柔軟に子供のビューから操作でき便利
補足
4.2のドキュメントのViews Passing A Sub-View To A View では、.php
のテンプレートで子ビューをセットするような形でレイアウトを組む説明もあるが、このようにレイアウトを記述することはなさそう
Asset
Laravel5 では、CSS、JavascriptをビルドするGulp タスク Laravel Elixir が標準で提供されている
この辺りが標準で提供されているあたりは素晴らしい
プロジェクト直下のgulpfile.jsを見てみると、resources/assets/less/app.less
をビルドするタスクがはじめから設定されている
// gulpfile.js
var elixir = require('laravel-elixir');
elixir(function(mix) {
mix.less('app.less');
});
npm実行環境とgulpをインストールして、プロジェクト直下にて以下のコマンドを実行する
$ npm install
開発中はgulp watchしておけば、lessの修正が自動で反映される
$ gulp watch
データベース操作
Basic Database Usage の Configuration によると対応データベースは、
MySQL, Postgres, SQLite, SQL Server と豊富
接続設定
データベースへの接続設定は、config/database.php
に記述する
Laravelのルートディレクトリ.env
があり、環境ごとの設定はこちらに記述
Environmentの設定については、LaravelはDotEnv PHPを利用する
MySQLを使用し Read/Write接続を分けない場合は、config/database.php
ではなく.env
に接続情報を記述する
デフォルトは以下の.env.example
がインストール時に.env
にコピーされる
(homesteadは、MySQLが.env.example
の内容に合わせてセットアップ済み)
// .env
APP_ENV=local
APP_DEBUG=true
APP_KEY=SomeRandomString
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
参考: Laravel 5.0 – Environment Detection & Environment Variables
モデル (ORM)
Laravelには、Eloquent ORMというActiveRecord実装がある
モデル生成の artisan コマンドが用意されている
$ php artisan make:model Article
app直下に以下のBlog.phpが生成される
// app/Blog.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
//
}
$tableプロパティに明示的にテーブル名を指定していないので、このArticleクラスの場合は、articlesテーブルにアクセスする
マイグレーション
上記のArticle
モデルを保存するarticles
テーブルを追加するマイグレーションを作成する場合、以下のようにartisan mke:migration
コマンドを実行する
$ php artisan make:migration create_articles_table
Created Migration: 2015_06_09_164737_create_articles_table
マイグレーションファイルはdatabase/migrations
に作成される
(モデル作成時、artisan make:model
コマンドにオプション-m
を付けると、モデルと同時にマイグレーションも生成される)
マイグレーションの書き方はWriting Migrationを参照
オートインクリメントのレコードIDと、文字列のtitleとtextをフィールドに持つarticlesテーブルを作成するマイグレーションは以下のようになる
// database/migrations/2015_06_09_164737_create_articles_table
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateArticlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('articles', function($table)
{
$table->increments('id');
$table->string('title');
$table->text('text');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('articles');
}
}
timestamps
は、インスタンスのdateTime型のupdated_at
およびcreated_at
列を追加するメソッド
Eloquentモデルは、デフォルトではタイムスタンプ機能が有効になっているので、明示的に無効にし無い場合は必ず追加する
Defining Models Timestamps
ところで、Laravelは、複合主キーに対応してい無いので、基本はRailsと同じようにオートインクリメントのレコードIDを使う前提と考えて良さそうな印象を受ける
マイグレーションはmigrate
コマンドで適用
$ php artisan migrate
モデルの利用
コントローラーでモデルを利用するには、まずは明示的にインポートする
モデル操作は、Modelクラスのファサードおよびインスタンスメソッドで行う
Illuminate/Database/Eloquent/Model – Laravel API
RESTFullコントローラーの実装例
// app/Http/Controllers/ArticleController" highlight="7, 15, 21
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Article;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class ArticleController extends Controller
{
public function index()
{
$articles = Article::all();
return view('article.index', ['articles' => $articles];
}
...
public function destroy($id)
{
$article = Article::find($id);
$article->delete();
}
}
テスト
簡単にテストも見ておく、ドキュメントではTestingに説明されている
Laravel5では、プロジェクトを作成するとphpunitがすぐに使えるようになっている
Homesteadはphpunitはグローバルインストールされていないので、Composerでインストールされたphpunitコマンドを使う
プロジェクトのディレクトリで、以下のようにphpunitコマンドを実行する
$ ./vendor/bin/phpunit
PHPUnit 4.7.3 by Sebastian Bergmann and contributors.
.
Time: 9.4 seconds, Memory: 12.75Mb
OK (1 test, 2 assertions)
デフォルトで含まれるExampleTest
が実行される
ドキュメントでは、主にApplication Testing(統合テスト)について説明されているので、そこだけ見ていく
テストの作成については、artisanコマンドは用意されていないので、tests
ディレクトリにTestCase
を継承するクラスを作成する
例えば、ExampleTestと同様に、Httpリクエストの結果を検証するコードは以下のようになる
// tests/ArticleTest
<?php
class ArticleTest extends TestCase
{
public function testSomethingIsTrue()
{
$this->visit('/article')
->see('Listing articles');
}
}
visit
はHttp GETリクエストを実行し、see
で、指定した文字列がレスポンスに含まれているかを検証している
click
やpress
メソッドで、リンクやボタンをクリックできたりと非常に軽く統合テストが可能
データベースを利用するテスト
次にデータベースアクセスを含むテストを記述してみる
Laravel5では、テスト時にデータベースを切り替える仕組みを標準で用意していない
必要な環境変数はphpunit.xmlに記述する
データベースだけ切り替られれば良いのでDB_DATABASE
のみ追加した
// phpunit.xml
<env name=DB_DATABASE" value="homestead_testing"/>
テストデータベースのマイグレーション
マイグレーションは、DatabaseMigrationsトレイトを利用して、テストごとにMigrationを実行する(重そうだ)
// tests/ArticleTest
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ArticleTest extends TestCase
{
use DatabaseMigrations;
...
}
Fixtureの導入
Fixtureはdatabase/factories/ModelFactory.php
に記述する
ArticleModelを1つ生成するファクトリを定義してみた
// database/factories/ModelFactory.php
$factory->define(App\Article::class, function ($faker) {
return [
'title' => $faker->title,
'text' => $faker->text,
];
});
ファクトリは、factory
グローバル関数で呼び出せる
/article
にアクセスすると、データベースから取得したArticleのリストが表示されることを検証するテストを記述した
// tests/ArticleTest
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ArticleTest extends TestCase
{
use DatabaseMigrations;
public function testDisplayArticles()
{
$article = factory(App\Article::class)->create();
$this->visit('/article')
->see($article->title)
->see($article->text);
}
}
基本的な使い方はこんなところ、モックも豊富なので、標準機能でそこそこのカバレッジを保てそう
また、実際には、統合テストの前に、プロバイダーやモデルの単体テストも書く必要があるが、ディレクトリの構成などは別途検討する必要がある
“Laravel5 入門 インストールからMVCの基本機能をさっと眺める” への1件のコメント
[…] Laravel5 入門 インストールからMVCの基本機能をさっと眺める […]