Laravel 5.6のインストール」でLaravel 5.6をインストールしましたが、ローカル環境でLaravel 5.6の制御をユーザのログイン機能も含めて解析します。

  • Windows 7 Professional SP1 32-bit
  • Xampp Version: 7.2.4
     PHP 7.2.4
  • Laravel 5.6.18
  • Composer 1.6.3

Laraveのエントリポイント

ブラウザからHTTPサーバに対してURLを用いてアクセスすると、HTTPサーバは全てのリクエストをLaraveのエントリポイント「public/index.php」 に渡します。「index.php」には次の6行の命令が記述されています。

  • 1行目:composerによるオートロードの仕組みを利用し、ファイル「vendor/autoload.php」を一度だけrequireすることで、vendor配下のライブラリをすべて自動的にロードします。また、プロジェクトの直下にあるcomposer.jsonでオートロードするファイルを追加できます。
  • 2行目:Laravelアプリケーションのインスタンスを作成し、singletonを用いてカーネルのインターフェース名を実際のクラス名に紐づけます。
  • 3行目:サービスコンテナ(DIコンテナ)を使用して、HTTPカーネルを作成します。
  • 4行目:HTTPカーネルに$requestを渡して、$responseを取得します。
  • 5行目:responseヘッダセットとレスポンス内容をブラウザに返します。
  • 6行目:Middlewareのterminateを実行し各種terminate時のコールバックを実行します。

vendor/autoload.php

require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle($request = Illuminate\Http\Request::capture());
$response->send();
$kernel->terminate($request, $response);

DIコンテナ(サービスコンテナ)を使ってインスタンス生成処理

サービスコンテナとはクラス(サービス)のインスタンス化を管理する仕組みで、次の手順になります。

1.サービスコンテナにクラスを登録します。

$this->app->bind(‘sender’,’MailSender’);

  • $this->app がサービスコンテナになります。
  • サービスコンテナ($this-app)に bind()メソッド でクラス(MailSender)を登録します。
  • 第一引数にキー名(sender)、第二引数にクラス名(MailSender)入れて紐付けして登録しています。

2.サービスコンテナに登録したクラスを呼び出してインスタンスを生成します。

$sender = $this->app->make(‘sender’);

  • サービスコンテナ($this->app)からキー名(sender)に対応するクラスを生成します。
    このケースでは MailSender のインスタンスが返ってきます。

3.作成したHTTPカーネルに$requestを渡して、$responseを取得します。

$response = $kernel->handle($request = Illuminate\Http\Request::capture());

Laravelのルーティングの書き方

「routes\web.php」によりrequestの処理が次のように行われます。

  • 1行目から3行目:ルーティングと同時に表示内容もクロージャで記載する方法で、トップページ「http://localhost/laravel/public/」が入力されると、viewメソッドによるテンプレートエンジン「welcome.blade.php」の呼び出しを、コールバック関数として登録します。
  • 4行目:Authファサードを通してIlluminate\Routing\Routerインスタンスのauthメソッドを呼び出します。この呼び出しによりAuthentication Routes「Auth\LoginController@showLoginForm」、Registration Routes「Auth\RegisterController@showRegistrationForm」、Password Reset Routes「Auth\ForgotPasswordController@sendResetLinkEmail」等が、コールバック関数として追加されます。
  • 5行目:login時に認証が正常に行われると、「http://localhost/laravel/public/home」にリダイレクトされます。このリダイレクトにより「\app\Http\Controllers\HomeController.php」のメソッド「index」の呼び出しを、コールバック関数として登録します。

routes\web.php

Route::get('/', function () {
    return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');

メソッド「view」でテンプレートエンジン「blade」の呼び出し

1.トップページ「http://localhost/laravel/public/」を開くと、「routes\web.php」により次のスクリプトが実行されます。

routes\web.php

    ...
Route::get('/', function () {
    return view('welcome');
});
    ...

テンプレートエンジン「welcome.blade.php」が呼び出されます。右上に「LOGIN」「REGISTER」のメニューがあり、REGISTERを押してユーザー登録をするとトップページのメニューが「HOME」に変わります。

welcome.blade.php

    ...
@if (Route::has('login'))
    <div class="top-right links">
        @auth
            <a href="{{ url('/home') }}">Home</a>
        @else
            <a href="{{ route('login') }}">Login</a>
            <a href="{{ route('register') }}">Register</a>
        @endauth
    </div>
    ...
@endif

2.Web上でユーザを登録すると「\app\Http\Controllers\Auth\LoginController.php __construct」に制御が移り、「\vendor\symfony\http-foundation\RedirectResponse.php」の setTargetUrlメソッドにより、「/public/home」にリダイレクトされ、これを受けて「\app\Http\Controllers\HomeController.php」のメソッド「index」から、次のテンプレートエンジン「home.blade.php」が呼ばれます。

\app\Http\Controllers\HomeController.phpのメソッドindex

    ...
public function index()
{
  return view('home');
}
    ...

テンプレートエンジン「home.blade.php」を次に示します。「@extends(‘layouts.app’)」は親のテンプレートを指定します。実際のフォルダは、「layouts\app.blade.php」となります。親のテンプレートの「@yield」は、親のテンプレートを利用している子のテンプレートの「@section~@endsection」で埋められます。親のテンプレートエンジン「\resources\views\layouts\app.blade.php」を次に示します。子のテンプレートエンジン「home.blade.php」の「@section(‘content’)~@endsection」が、親の「@yield(‘content’)」に置き換わり、親のテンプレートエンジン「\resources\views\layouts\app.blade.php」の内容がresponseとして出力されます。

layouts\app.blade.php

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    ......
    <title>{{ config('app.name', 'Laravel') }}</title>
    ......

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                ......
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>
    </div>
</body>
</html>

子のテンプレートエンジン「\resources\views\auth\home.blade.php」を次に示します。

home.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Dashboard</div>
                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success">
                            {{ session('status') }}
                        </div>
                    @endif

                    TomoSoft Login!!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

3.Web画面で「REGISTER」をクリックすると、request「/public/login」がLaraveに転送され、ルーティング(Auth::routes)により、「App\Http\Controllers\Auth\LoginController@showLoginForm 」が呼ばれ、viewメソッドによりlogin.blade.phpが呼ばれます。

showLoginForm

public function showLoginForm()
{
   return view('auth.login');
}

テンプレートエンジン「\resources\views\auth\login.blade.php」を次に示します。

@extends('layouts.app')

@section('content')
<div class="container">
  ...
(ユーザ登録のためのメールアドレス/パスワードの入力フォーマット)
  ...
</div>
@endsection

ローディング規約

Laravelは、クラスの自動ローディング規約「PSR-4」に従っています。です。名前空間を含めたクラス名と、ファイルパスを対応付けます。Laravelの場合、ベンダー名はlaravel、パッケージ名はframeworkになっており、その中のcomposer.jsonを調べます。

composer.json

…
"autoload": {
    "classmap": [
        "src/Illuminate/Queue/IlluminateQueueClosure.php"
    ],
    "files": [
        "src/Illuminate/Foundation/helpers.php",
        "src/Illuminate/Support/helpers.php"
    ],
    "psr-4": {
        "Illuminate\\": "src/Illuminate/"
    }
},
…

名前空間Illuminateをsrc/Illuminateディレクトリーへ結びつけています。ここから「LaravelのパッケージはIlluminate名前空間下にある」こと、そして「Illuminate名前空間下のPHPファイルはsrc/Illuminateディレクトリー下に存在している」ことが把握できます。このファイルの置いてある相対ディレクトリーは「vendor/laravel/framework/」なので、実際のIlluminate名前空間下のファイルは、「プロジェクトディレクトリー/vendor/laravel/framework/src/Illuminate」ディレクトリー下ということになります。

Laravel 5.6を解析するためのログの取り方

Laravel 5.6はログ機能を持っていますが、エントリポイント「public/index.php」からログを取るため、今回の解析には使用しませんでした。このため、次の関数をスクリプトに埋め込むことにより、「public/」の直下にログファイル「laravel.log」を作成しました。ログは追記され、形式は「ログ時刻 ファイル名 (メソッド名) (任意文字列)」のようになります。

file_put_contents(‘laravel.log’, date(“Y-m-d H:i:s”) .” “.pathinfo(__FILE__,PATHINFO_BASENAME) .”2″.”\n”, FILE_APPEND);

  • 日本時間の設定のために、「public/index.php」の最初で「date_default_timezone_set(‘Asia/Tokyo’)」を呼び出し、「\config\app.php」で「’timezone’ => ‘Asia/Tokyo’,」を設定します。
  • 「\resources\views」に設定されたbladeファイルでは、「<?php ~ ?>」で囲みます。

今回解析のために取得したログファイル「ログファイル」を示します。