Laravel
準備
セットアップ手順
- Composer をインストール
C:/Users/Shota/AppData/Roaming/Composer/vendor/bin
にパスを通すcomposer global require "laravel/installer"
基本
laravel new ${myProjectName}
php artisan serve # テスト専用コマンドである。本番環境では使うな。
本番環境のセットアップ(XAMPP の例)
例えばhtdocs
にmy-app
というプロジェクトを放り込んだとすると、https://some.com/my-app/public
というアドレスでアプリケーションにアクセスできる。
/my-app/public
を/
にマップしたい(エイリアスを作りたい)場合は、本書 P20 に記載の設定を Apache の httpd.conf
に入れること。
ファイル・フォルダ構成
ルートファイル
name | description |
---|---|
.env , .env.example | DB の認証情報など、動作に関する設定ファイル |
artisan | php artisan *** のようにして使う |
composer.json , composer.lock | composer がつかう |
phpunit.xml | ユニットテストに関する設定ファイル |
server.php | サーバ本体 |
webpack.min.js | webpack の設定ファイル |
ルートフォルダ
*
マークはよく使うフォルダ。
name | description |
---|---|
app | * アプリケーションの本体 |
bootstrap | 起動時の処理 |
config | 設定 |
database | * DB 関係 |
public | そのまま公開するファイル群。パスを取得したい ときはasset() ヘルパを使う |
resources | * テンプレートや、ビルドすべき JS/CSS などのリソース |
routes | * ルーティング情報 |
storage | ログなどのファイルの保存場所 |
tests | ユニットテスト関係 |
vendor | Laravel 本体のプログラム |
app フォルダ
name | description |
---|---|
Console | コンソールプログラム? |
Exceptions | 例外処理 |
Http | Web アプリケーションにアクセスしたときの処理。一番良く使う |
Providers | サービスプロバイダ アプリ開始時の処理などを記述する |
User.php | ユーザ認証に関するプログラム |
routes フォルダ
name | description |
---|---|
api.php | API の機能を特定のアドレスに割り当てたい時に使う |
channels.php | ブロードキャストチャンネルのためのルーティング? |
console.php | コンソールプログラムのためのルーティング? |
web.php | 一般的な Web ページとしてアクセスするときのルーティング。一番良く使う |
ルーティングとコントローラ
ルーティング
ルーティングの設定はroutes/web.php
に記載する。
生の HTML を返す
Route::get('/hello', function() {
return '<h1>Some HTML!</h1>';
});
// GET以外のメソッドの場合
Route::post();
Route::put();
Route::delete();
テンプレートを指定する
(実際はview()
は Response オブジェクトを返す)
// routes/web.php
Route::get('/', function() {
return view('welcome');
}); // => `resources/views/welcome.blade.php`
Route::get('/hello', function() {
return view('hello.index');
}); // => `resources/views/hello/index.blade.php`
コントローラを指定する
Route::get('/hello', 'HelloController@index');
Route::get('/hello', 'HelloController'); // シングルアクションコントローラの場合
params を受け取る
任意の param には?
をつける。任意の項目にはデフォルト値をセットしておくと良い。
Route::get('/hello/{msg}/{id}', function($msg, $id){ // 順に渡されるので名前は違ってもOK
return "<h1>Hello! $msg2 $id</h1>";
});
Route::get('/hello/{msg?}/{id?}', function($msg='a', $id='b'){
return "<h1>Hello! $msg $id</h1>";
});
ルートの一覧を表示する
php artisan route:list
コントローラ
MVC
User <-> Controller <-┬-> View <-> Templates
│
└-> Model <-> Database
コントローラの作成
# 空のコントローラを作成する
php artisan make:controller HelloController
# リソースフル(典型的なメソッドをあらかじめ持っている)なコントローラを作成する
php artisan make:controller HelloController --resource
// app/Http/Controllers/HelloController.php
namespace App\Http\Controllers; // 名前空間の指定
use Illuminate\Http\Request; // Requestオブジェクトを使えるよう設定
class HelloController extends Controller {}; // コントローラ本体
アクションの追加
- アクション=コントローラに用意される処理のこと
- 名前を変えることで、複数設定できる
- インスタンスメソッドとして実装する
- アクションは、HTML もしくはリクエストオブジェクトを Return する
// controller
class HelloController extends Controller
{
public function index() {
return <<<EOF
<h1>ID: $id</h1>
<h1>Pass: $pass</h1>
EOF;
}
}
コントローラをルーティング設定に記載する。
// routes/web.php
Route::get('/hello', 'HelloController@index');
シングルアクションコントローラ
一つしかアクションを持たないクラスの場合、__invoke()
メソッドを実装することで記載を簡略化できる。
// controller
class HelloController extends Controller
{
public function __invoke() {
return '<h1>something</h1>';
}
}
ルーティング設定ではメソッド名を省略する。
// routes/web.php
Route::get('/hello', 'HelloController');
リソースフル
- Resourceful = RESTful に加え、追加・編集・削除用フォーム等、リソースを扱うために必要なすべての機能を備えていること
- 下記の手順でリソースフルなコントローラを作成し、作成したコントローラを
Route::resource
に渡してやることで、アクションを個別に作成することなく、簡単にリソースフルなコントローラを使い始めることができる。
php artisan make:controller RestappController --resource
Route::resource('/rest', 'RestappController');
http method | route | action | RESTful | Resourceful |
---|---|---|---|---|
GET | /route | index() | * | * |
GET | /route/create | create() | * | |
POST | /route | store() | * | * |
GET | /route/1 | show() | * | * |
GET | /route/1/edit | edit() | * | |
PUT/PATCH | /route/1 | update() | * | * |
DELETE | /route/1 | destroy() | * | * |
フォームから PUT や DELETE を送るには
- リソースフルなルートを設定した場合は、更新や削除の処理を
PUT
やDELETE
といったメソッドで行う必要がある。 - しかし、フォームから遅れるのは
POST
メソッドだけである。 - このため、
PUT
やDELETE
を使う際は、_method
という隠し属性にメソッドを記述しておく必要がある。
<form action="/posts/1234/delete" method="POST">
<input type="hidden" name="_method" value="PUT" />
</form>
アクションで params を受け取る
// routes/web.php
Route::get('/hello/{id?}/{pass?}', 'HelloController@index');
// controller
class HelloController extends Controller
{
public function index($id='defualtId', $pass='defaultPass') { /* do something */}
}
Request, Response の利用
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class HelloController extends Controller
{
public function index(Request $request, Response $response) {
$html = <<<EOF
<h1>Request</h1>
<pre>$request</pre>
<h1>Response</h1>
<pre>$response</pre>
EOF;
$response->setContent($html);
return $response;
}
}
主なメソッド
$request->url()
クエリを含まない URL を返す$request->fullUrl()
クエリを含む URL を返す$request->path()
ドメインより下のパス部分だけを返す$request->QUERY_NAME
クエリを取得する(クエリ名が id なら、$request->id
)$response->status()
ステータスコードを返す$response->content()
コンテンツを取得$response->setContent()
コンテンツを設定
なお、Laravel では、下記のデータが全てリクエストオブジェクトにぶっこまれる(Express のように、req.params や req.query などはなく、いきなり req.propertyName の形で追加される)。
- params
- query string
- form data (input の name 属性)
- ミドルウェアから渡された値(
$request->merge(配列)
など)
ビューとテンプレート
PHP テンプレートの利用
PHP テンプレートを使うには、view(フォルダ名.ファイル名)
を呼ぶことで、テンプレートから Response インスタンスを作成する。
Route::get('/hello', function(){
// resources/views/hello/index.phpというテンプレートを基にする
// view()はResponseインスタンスを生成する
return view('hello.index');
});
上記は、ルーティング設定にテンプレートを指定している。 ルーティング設定にコントローラを指定した場合は、次にようにする。
class HelloController extends Controller
{
public function index() {
return view('hello.index');
}
}
テンプレートにデータを渡したいときは、view の第二引数に Array を渡す。
// controller
class HelloController extends Controller
{
public function index() {
// compact等を使って、渡すデータを一つづつ指定する方法
$title = 'my title';
$msg = 'my msg';
return view('hello.index', compact('title', 'msg'));
// 配列を使って、まるごとデータを渡す方法
$data = [
'msg1' => 'msg1です',
'msg2' => 'msg2です',
];
return view('hello.index2', $data);
}
}
// template
<h1>{{ $title . $msg }}</h1>
<h1>{{ $msg1 . $msg2 }}</h1>
Blade テンプレートの利用
blade テンプレートを利用するには、FILENAME.blade.php
の形式でテンプレートを作成する。
PHP テンプレートと Blade テンプレートが両方存在する場合は blade が優先される。
Form を実装してみる
input 要素の name 属性が、そのまま$request
のプロパティとして取り出せるようになる。
// template
<form method="POST" action="/hello">
@csrf // 外部サイトからのフォーム送信を防ぐため、認証データを挿入
<input type="text" name="myname">
<input type="submit">
</form>
// routing
Route::post('/hello', 'HelloController@post');
// controller
class HelloController extends Controller
{
public function post(Request $request) {
// $request->myname に入力した値が入っている
}
}
Blade の構文
値の表示
{{ 値など }}
{!! 値など !!} // HTMLエスケープしたくない場合
条件分岐
@if()
@elseif ()
@else
@endif
@unless()
@else
@endunless
@empty()
@else
@endempty
@isset()
@else
@endisset
繰り返し
@for (i=1; i<10; i++)
@endfor
@foreach ($array as $value)
@endforeach
// foreach-else
@forelse ($array as $value)
// 配列がある場合の処理
@empty
// 配列が空の場合の処理
@endforelse
@while ()
@endwhile
@break // 繰り返しを終了
@continue // 次のループへ
繰り返しの中では$loop
という特殊なオブジェクトを使える。
$loop->index
インデックス(0 スタート)$loop->iteration
繰り返し数(1 スタート)$loop->remaining
残り回数(このループを含まず)$loop->count
繰り返しの元配列の要素数$loop->first
最初のループかどうか$loop->last
最後のループかどうか$loop->depth
繰り返しのネスト数(1 スタート)$loop->parent
ネストしている場合に、親のループ変数を返す
@foreach ([1,2,3] as $value)
{{$loop->index}}
@endforeach
// => 0,1,2
php ディレクティブ
@php
を使うと 、blade テンプレートの中に php を記載できる。
基本的にテンプレートの中にロジックを書くのはバッドプラクティスなので、
あくまでビューに関する利用にとどめること。
@php
$counter = 0;
@endphp
@while($counter < 3);
{{ $counter }}
@php
$counter += 1;
@endphp
@endwhile
レイアウトの作成
ベースレイアウトと継承レイアウト
ベース側において、@yield()
, @section() - @show
を使って場所を用意しておき、
継承側で@section()
, @section()-@endsection
を使うことで内容を埋めていく方法。
Nuxt.js の Layouts と同じような使い方をすればいいんだと思う。
ベースレイアウト
// resourses/views/layouts/helloapp.blade.php (layoutsというフォルダ名は変えてもいい)
<body>
<h1>@yield('title')</h1>
@yield('content')
@section('menubar')
<p>メニュー</p>
@show
@yield('footer')
</body>
継承レイアウト
// resourses/views/hello.blade.php
@extends('layouts.helloapp')
@section('title', 'My Title')
@section('content')
<p>ここが本文です。</p>
@endsection
@section('menubar')
@parent // ベースレイアウトの中身を継承したい時に使う
メニュー項目など
@endsection
@section('footer')
<p>copyright 2018</p>
@endsection
コンポーネントの作成
- ヘッダ、フッタなど、パーツごとに作成する方法
- コンポーネントの作成方法は通常のテンプレートと全く同じ
// resources/views/components/message.blade.php (componentsというフォルダ名は変えてもいい)
<p>これはコンポーネントです</p>
<p>{{ $msg_title }}</p>
<p>{{ $msg_content }}</p>
コンポーネントの利用その 1 (@component
)
- 値は
@slot()
で渡す - 親テンプレートの変数スコープは、コンポーネントに引き継がれない。
// resources/views/hello/index.blade.php
@component('components.message')
@slot('msg_title','タイトルやで')
@slot('msg_content')
コンテンツです
@endslot
@endcomponent
コンポーネントの利用その 2(@include
=サブビュー)
- 値を渡すときは Array で渡す
- 親テンプレートの変数スコープは、コンポーネントに引き継がれる。親テンプレートで利用できる変数は、何もせずに読み込んだコンポーネント内で利用できる。まさに、そこにテンプレートを継ぎ足したような挙動 をするということ。
@include('components.message',[
'msg_title' => 'タイトルです',
'msg_content' => '本文です'
])