PHP 初学者による Laravel 基礎入門
上記で作成した Docker 開発環境を用いて、Laravel に入門してみる。ちなみに筆者は PHP どころか Web 開発の経験がほぼないため、初歩の初歩からとなる。
基本的には上記書籍を参考にしながら手を動かしている段階。
ルーティング機能を理解する
Webサービスを作るのにあたって、最初に理解すべきなのが URL パターンと起動処理の対応定義であろう。 Laravel では routes/web.php
に、作成されているとのこと。
<?php Route::get('/', function () { return view('welcome'); });
一般的にこの手の定義は XML や JSON で作られると思われるが、web.php
の中身はプログラムそのもの。この例では /
に GET メソッドでアクセスしたら view('welcome') の結果を返却する。routes/channels.php
などもあるが、まずは web.php
を使えばよさそう
テンプレートエンジン blade を使ってみる
welcome
を引数に view 関数を利用すると blade という Laravel 組み込みのテンプレートエンジンが起動され、 laravelapp/resources/views/welcome.blade.php
をレンダリングした結果を返す。ディレクトリやファイル名は規約的に決まっているようだ。 welcome.blade.php
の中身の一部は以下の通り。
@if (Route::has('login')) <div class="top-right links"> @auth <a href="{{ url('/home') }}">Home</a> @else
html を中心としながら if 文や変数展開がある感じ。Webアプリケーションは html を出力する際の print 文地獄を回避するために、テンプレートエンジンが整備される必然性があるのだろう。
ルーティングとテンプレートエンジンを組み合わせる
上記を踏まえて hello.blade.php
というテンプレートを追加してみる。
<!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <style> .flex-center { align-items: center; display: flex; justify-content: center; } </style> </head> <body> <div class="flex-center">Hello World !!</div> </body> </html>
このテンプレートエンジンの起動と /hello
というパスを web.php
で紐付ける。
<?php Route::get('/hello', function() { return view('hello'); });
ファイルをサーバーに反映して http://localhost:50000/hello
にアクセス。
でてきた。こういうのって素直に嬉しい。view
関数の結果はあくまで文字列なので、 web.php
内で定義する関数の戻り値に直接 <html>〜
とやってもよいが地獄なので試さない。
ルートパラメータの利用
ルートを定義する際には {パラメータ名}
でにはURL文字列の一部をパラメータとして利用することができる。 {パラメータ名?}
とすることで必須項目ではなくなり、関数側でデフォルト値が定義可能。パラメータは view の第二引数に連想配列として渡すことで、テンプレートエンジンから利用できる。
<?php Route::get('/hello/{target?}', function($target='world') { return view('hello', ['target' => $target]); });
<body> <div class="flex-center">Hello {{ $target }} !!</div> </body>
URL文字列を変数としてスムーズに扱えると、いわゆる RESTful API が作りやすくなるので、なかなかよさそう。
コントローラーを作成する
model: アプリケーションデータ、ビジネスルール、ロジック、関数
view: グラフや図などの任意の情報表現
controller: 入力を受け取りmodelとviewへの命令に変換する
Model View Controller - Wikipedia
自分の知ってるMVCモデルではビジネスロジックはモデルの責務だと考えているが、Laravel における MVC モデルにおいてはモデルはあくまでDBアクセスに特化してコントローラー側に処理を書いていくのが一般的rしい。php artisan make:controller
コマンドでコントローラーの雛形が作成可能。バックグラウンド起動している Docker コンテナに命令するには docker exec
を利用する。
$ docker exec phpapp php artisan make:controller HelloController
$ docker cp phpapp:/var/www/laravelapp/app laravelapp/
上記のコマンドで、HelloController
というコントローラークラスを生成してをローカルに取得。 確認するとapp/Http/Controllers/HelloController.php
が作成されている。大したファイルではないので、手動で作った方が早いか。
コントローラーをルーティングに割り当てる
HelloController.php
を以下のように編集。追加した関数の責務も html の返却なので、 view
を使って blade を起動させる。ついでに、現在日付を表示させてみる。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class HelloController extends Controller { public function hello($target='world') { return view('hello', ['target' => $target, 'date' => date("Y/m/d")]); } }
web.php
に クラス名@関数名
形式で URLに対応して起動するアクションを定義。
<?php Route::get('/hello/{target?}', 'HelloController@hello');
URLに定義したパラメータは対応する関数を実行する際の引数となる。
シングルアクション定義
クラスに定義される関数が一種類の場合には __invoke
関数として定義することで、ルーティング定義をクラス名だけに省略できる。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class HelloController extends Controller { public function __invoke($target='world') { return view('hello', ['target' => $target, 'date' => date("Y/m/d")]); } }
<?php Route::get('/hello/{target?}', 'HelloController@hello');
Laravel で HTTP リクエストと HTTP レスポンスを利用する
ブラウザとサーバーの間でやりとりされるリクエストとレスポンスは、引数の型指定でそれぞれ、Request
と Response
を追加しておくことで、 web.php
で特に引数定義しなくても利用可能となる。ちょっとキモい。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Http\Response; class HelloController extends Controller { public function __invoke(Request $req, Response $res, $target='world') { return view('hello', ['target' => $target, 'url' => $req->url(), 'status' => $res->status()]); } }
<!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <style> .flex-center { align-items: center; display: flex; justify-content: center; } </style> </head> <body> <div class="flex-center">{{ $status }} Hello {{ $target }} !!</div> <div class="flex-center">{{ $url }}</div> </body> </html>
View が返しているのも厳密には html ではなく、レンダリング結果が格納されたResponse オブジェクトだそう。ここまでの開発でブラウザからのリクエストを受け取り、それに応じて処理を切り分けることが可能となった。次回はさらに踏み込んだ機能を使ってみる。