2021/03/08

Laravel では Auth や Jetstream で認証機能を実装できますが、マルチログインは結構面倒です。

例えば未認証のリダイレクト処理はミドルウェアの Authenticate->redirectTo() で処理していますが、シングルログイン(user)の記述です。

Authenticate のデフォルト設定

app/Http/Middleware/Authenticate.php


    protected function redirectTo($request)
    {
        if (!$request->expectsJson()) {
            return route('login');
        }
    }

ここで user、admin 2つのマルチドメイン認証で「/user/xxx」「/admin/xxx」にアクセスしたとき、上記のルーティングでは「/login」にリダイレクトされてしまいます。

また「/login」でなく「/user/login」「/admin/login」でルーティングすると当然ながら Routing エラーになります。


Symfony\Component\Routing\Exception\RouteNotFoundException
Route [login] not defined.

Authenticate の修正

2つの認証「user」「admin」が未承認時、「/user/login」「/admin/login」 にリダイレクトするよう修正します。今回は直接「user」「admin」と直接設定しましたが、ループ処理は guard の設定と連携してもよいかと思います。


    protected function redirectTo($request)
    {
        if (!$request->expectsJson()) {
            foreach (['user', 'admin'] as $user) {
                if ($request->routeIs("{$user}.*)) {
                    return route("{$user}.login");
                }
            }
        }
    }

また、認証処理を user、admin の各コントローラーのコンストラクタやサービスなどで認証する場合は、 Authenticate->redirectTo() は無効にする必要があります。

  2021/01/26

UNIQUE(重複)を含むデータの更新で、FormRequest や Validate で単純に unique を設定してしまうと、自分自身を更新できません。

code がユニークの場合

以下は、FormRequest の rulde() で items.code を UNIQUE 制約している例です。

配列の場合


'code' => ['required', 'string', 'unique:items'],

パイプの場合


'code' => 'required|string|unique:items',

この設定だと SQL の WHERE で更新しようとしてしまいます。


WHERE code = 'xxxx';

id を除外して code をユニークにする

よって items テーブルのプライマリーキー items.id を除外して更新するのがよいでしょう。

配列の場合


'code' => ['required', 'string', Rule::unique('items')->ignore($this->id)],

パイプの場合


'code' => "required|string|unique:items,code,{$this->id},id",

SQL の WHERE は以下のようになります。


WHERE code = 'xxxx' AND id <> 'xxxx'

  2021/01/15

Laravelでは、csrf フォーム画面で放置した場合、セッションが異なる Token エラーで Page Expired ページが表示されるようになっています。

App\Exceptions\Handler 

Laravel ではエラーが発生すると、App\Exceptions\Handler が実行され最終的に render() でエラー画面を表示します。ExceptionHandler の詳細に関しては Laravel 8.x エラー処理 を参考にしてください。

ただ、フォーム有効期限切れで Page Expired ページを表示するのは、UI/UX 的に好ましくないのでリダイレクトしてみます。

App\Exceptions\Handler の render() で処理を振り分けてダイレクトしますが、今回は Tokenエラー TokenMismatchException クラスを判別します。


    public function render($request, Throwable $exception)
    {
        $class = get_class($exception);
        if ($class == 'Illuminate\Session\TokenMismatchException') {
            return back()->withInput();
        }
        return parent::render($request, $exception);
    }

フォームリクエストの場合は、 back()->withInput() で前の画面にリダイレクトするとよいでしょう。

またログインセッションの場合は Exception で振り分けず、Authenticate ミドルウェアなどで処理した方がわかりやすいでしょう。

  2020/12/28

ログのクリア

Laravel のログファイルをクリアします。

デフォルトでは storage/logs/laravel.log に記載されています。

echo で削除

ターミナルで Laravel プロジェクトのホームに移動し、echo で空にします。


% echo "" > storage/logs/laravel.log

truncate で削除

Mac の場合 truncate が入っていないので、Homebrew でインストールします。


% brew install truncate

truncate でログをクリアします。


% truncate -s 0 storage/logs/laravel.log

ログを日付ごとローテーション

ログの設定は、.env ファイルで簡単に設定できます。 デフォルトでは stack (複数のログチャンネルを一つのログチャンネルへ集結)になっています。


LOG_CHANNEL=daily

config/logging.php でも設定が可能で、デフォルトの設定は stack になっています。


'default' => env('LOG_CHANNEL', 'stack'),

利用可能なチャンネルドライバ

Laravel のログ設定に関しては公式を参考にしてください

参考)Laravel 7.x ログ

  • stack: 「マルチチャンネル」チャンネルを作成するためのラッパー機能
  • single: シングルファイル/パスベースのロガーチャンネル(StreamHandler)
  • daily: RotatingFileHandlerベースの毎日ファイルを切り替えるMonologドライバ
  • slack: SlackWebhookHandlerベースのMonologドライバ
  • syslog: SyslogHandlerベースのMonologドライバ
  • errorlog: ErrorLogHandlerベースのMonologドライバ
  • monolog サポートしているMonologハンドラをどれでも使用できる、Monologファクトリドライバ
  • custom チャンネルを生成するため、指定したファクトリを呼び出すドライバ

ログの保存日数を設定

ログファイルが増えた時にローテートしますが、config/logging.php でログの保存日数を指定できます。

cron などでログローテートする場合、パーミッションも設定しておきます。


'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 7,
            'permission' => 0666,
        ],

  2020/10/24

Laravel 6.x から Laravel 8.x にバージョンアップしますが、普通に composer update すると以下のエラーがでます。


> Illuminate\Foundation\ComposerScripts::postAutoloadDump

> @php artisan package:discover --ansi

PHP Fatal error:  Declaration of App\Exceptions\Handler::report(Exception $exception) must be compatible with Illuminate\Foundation\Exceptions\Handler::report(Throwable $e) in /Users/yoo/projects/ict-kids/app/Exceptions/Handler.php on line 35

Handler.php の修正

app/Exceptions/Handler.php の Exception の処理が 6.x から 7.x で変更されているため、手動で修正します。

修正前


namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    ...
    public function report(Exception $exception)
    {
        parent::report($exception);
    }
    ...
    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }

修正後


namespace App\Exceptions;

use Throwable; //追加
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    ...
    public function report(Throwable $exception)  //修正
    {
        parent::report($exception);
    }
    ...
    public function render($request, Throwable $exception)  //修正
    {
        return parent::render($request, $exception);
    }

composer.json の修正

Laravel 8.x アップグレードガイド 」を参考に composer.json を修正します。


    "require": {
        ...
        "laravel/framework": "^8.0",
        "guzzlehttp/guzzle": "^7.2",
        ...
    },

    "require-dev": {
        "facade/ignition": "^2.3.6",
        ...
        "laravel/ui": "^3.0",
        ...
        "nunomaduro/collision": "^5.0",
        "phpunit/phpunit": "^9.0
    },

Composer アップデート

Composer で Laravel8 へアップデートします


$ composer update

バージョンを確認します。


$ php artisan -V
Laravel Framework 8.11.2

  2020/10/24

Blade ではデフォルトでカスタムクラスを呼び出すことができないため、別途設定する必要があります。

app.php を修正

Laravel ではデフォルトでクラスをオートロードしていますが、その設定は app.php に記述されています。

'School' => App\School::class,


    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'Str' => Illuminate\Support\Str::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
    ],

Laravel で Facade でよく利用される名称に気づくでしょう。

カスタムクラスをアプリ全体で利用する場合は、 app.php の 「aliases」 に追加します。

Item.php を利用してみる

例えば、app/Item.php クラスファイルが以下のように税込計算の static 関数が定義してあるとします。


class Item {
    public static function taxPrice($price, $tax) {
        return $price * (1 + $tax);
    }
}

この Item.php を app.php にネームスペース記述で追加します。


    'aliases' => [
        ....
        'Item' => App\Item::class,
    ],

これで、アプリ全体で利用可能になり Blade ファイルからも利用することができます。


{{ Item::taxPrice(100, 0.1) }} 

app.php に設定する前に

アプリ全体で利用できるのは便利ですが毎回ローディングされるため、たくさんのカスタムファイルや大きなファイルはメモリ消費や負荷を念頭においた方がよいでしょう。

さほど利用しない機能のクラスは、コントローラーで都度呼び出したりミドルウェアなどで処理することが基本となります。 また、Blade でクラスを多用しすぎると MVC の分離ができなるなるのも注意が必要です。

  2020/08/14

Laravel プロジェクトを clone しても動作しない

Laravel のプロジェクトはコアライブラリの vender/ や環境設定ファイル .env など必要のないものは Git で管理しません。

当然 Laravel ライブラリがなければ Laravel の機能が利用できず、artisan コマンドでもエラーになります。


PHP Warning:  require(/Users/yoo/projects/techboost/sample_laravel/vendor/autoload.php): failed to open stream: No such file or directory in /Users/yoo/projects/techboost/sample_laravel/artisan on line 18

Laravel ライブラリをインストール

Laravel のライブラリ(vender/) をインストールします。


$ composer install

※Laravel 用の composer.json が存在しないと、実行できません。

インストールが完了したら、artisan の動作を確認します。


$ cd プロジェクトフォルダ
$ php artisan --version

設定ファイルの作成

.env を作成します。


$ cp .env.example .env

DB の設定などがあれば修正しておきます。

アプリケーションキーを生成

Laravel のアプリケーションキーを再生成します。


$ php artisan key:generate

アクセス権の変更

Web サーバが書き込みエラーにならないようにアクセス権限を変更します。


$ chmod 777 storage
$ chmod 777 bootstrap/cache/

DB のマイグレーション

DB を利用している場合は、マイグレーションもしておきましょう。


$ php artisan migrate

Laravel の動作確認

Laravel の動作確認をしましょう。 Web サーバ経由の場合はそのままブラウザで、Laravel のサーバを利用する場合は Laravel サーバを起動して確認します。


$ php artisan serve

  2020/08/08

どの環境にするか

Mac で Laravel の環境を構築するのに以下の例が挙げられます。

  • Mac ネイティブ
  • Virtualbox + Vagrant 
  • Docker (Docker for Mac)
  • Virtualbox + Docker

最近の主流は「Docker」や「Vagrant」を利用した「Homestead」といった仮想環境で環境構築することが多いかもしれません。

ただ、Laravel の基本環境に関しては Mac ネイティブでも構築可能でき、仮想環境と比べて比較的高速で動作するのがメリットです。

  • Docker:「Docker For Mac」が一般的だが、ハードディスクのアクセス速度が遅い傾向
  • Virtualbox + Vagrant:Docker に比べるとメモリや速度の面でやや劣るかもしれません。
  • Virtualbox + Docker:構築が比較的大変

Xampp も利用できるが・・・

Mac のネイティブ環境構築の方法として「Xampp」のような統合インストールツールがあり、Windows でプログラミング初心者の人が利用するのに便利です。

ただMac の場合、将来的なことを考えると Xampp は個人的にはあまりおすすめしません。

macOS は BSD系の Unix ベースで開発されており、Linux のような環境(Linux とは別物)で利用することができます。

Homebrew の準備

Mac で環境構築する場合、まずパッケージ管理ツール Homebrew のインストールが必要です。

Homebrew のインストールは以下を参考にインストールしてください。

Homebrewインストール-2020年版

PHP のインストール

Laravel は PHP 7系が必要になります。

Mac には既に PHP はインストールされていますが、バージョンが古いため最新にアップデートします。

PHPの最新バージョンをアップグレードする場合


$ brew update
$ brew upgrade php
$ php --version
PHP 7.4.9 (cli) (built: Aug  7 2020 19:21:48) ( NTS )

パッケージを指定してインストールする場合

パッケージを指定してインストールすることもできます。

まず、PHP7 のパッケージを検索してみます。


$ brew search php@7
==> Formulae
php@7.2                     php@7.3                   php@7.4

PHP 7.4 をインストールします。


$ brew install php@7.4

Composer のインストール

Laravel を利用するには composer という PHP パッケージ管理ツールが必要です。 今回は、brew を利用して composer をインストールしてみます。


$ brew install composer

composer コマンドを利用できるようにのリンクを設定します。


$ brew link composer

Composer のバージョンを確認してみましょう。


$ composer --version

既に composer をインストールしている場合

既に composer をインストールしている場合は強制的にリンクを上書きします。


$ brew link --overwrite composer

環境変数の設定

composer コマンドを利用するにあたり、以下のコマンドで Mac に環境変数を設定しておきます。


$ export PATH=$HOME/.composer/vendor/bin:$PATH
$ source ~/.bash_profile

Laravel インストーラのインストール

これは必須ではありませんが、Laravel 独自の laravel コマンドを利用することもできます。

composer コマンドを利用して Laravel インストーラーをインストールしてみます。


$ composer global require "laravel/installer

インストールできたら、バージョンを確認します。


$ laravel --version
Laravel Installer 3.2.0

Laravel プロジェクト作成

Laravel プロジェクトは、以下の2種類のコマンドで作成することができます。

  • composer コマンド
  • laravel コマンド

Laravel のプロジェクトを作成してみましょう。

Composer で作成する場合


$ composer create-project laravel/laravel laravel_app

laravel コマンドで作成する場合


$ laravel new laravel-mac

プロジェクを作成したらプロジェクトディレクトリに移動し、各フォルダのパーミッションを変更します。


$ cd laravel-mac/
$ chmod 777 storage
$ chmod 777 bootstrap/cache/

Laravel サーバを起動します。


$ php artisan serve

さいごに

Homebrew と Composer で Laravel をインストール・プロジェクトの作成・サーバ起動をしました。

データベースをはじめとした機能は、別途 Homebrew などでインストールしなければいけませんが、この記事ではここまでとします。

  2020/05/25

プロジェクト作成

composer でプロジェクト名「laravel_app」を作成します。


$ composer create-project laravel/laravel laravel_app

Laravel のバージョンを確認しておきます。


Laravel Framework 7.12.0

UIパッケージをインストール

laravel_app に移動して、ComposerでLaravelのUIパッケージ laravel/ui をインストールします。


$ cd laravel_app
$ composer require laravel/ui

Reactをインストール

Reactを利用できるようにスカフォールドをインストールします。


$ php artisan ui react
//Authを利用する場合
$ php artisan ui react --auth

npmでインストール&ビルド(開発)

package.jsonに記述された内容で依存パッケージをインストールとLaravel Mixでビルドします。


$ npm install
$ npm run dev

関連ファイルの監視

関連ファイルの変更を監視しておきます。


$ npm run watch

これでReactがインストールされたLaravelプロジェクト作成が完了しました。

ここで Laravelサーバを起動して確認してみましょう。

おなじみの Laravel の画面は表示されましたが、この画面ではReact の動作実装されていません。

Reactを確認する

Laravel で React をインストールするとあらかじめサンプルファイルが作成されています。

app.js

resources/js/app.js には Bootstrap と Reactコンポーネント「Example」が読み込まれています。


require('./bootstrap');
require('./components/Example');

Example.js

resources/js/components/Example.js には、Reactコンポーネント「Example」の中身です。
Reactでは、HTMLレンダリングにJSXを利用しますが、JavaScriptに直接HTMLタグを記述できる点で便利です。


import React from 'react';
import ReactDOM from 'react-dom';

function Example() {
    return (
        ...JSX...
    );
}

export default Example;
...

レイアウトファイルの修正

現状だと Reactコンポーネントは表示できないため、Laravelのレイアウトファイル「resources/views/welcom.blade.php」を修正します。

Laravelのmix()関数で app.jsを読み込んでいます。


<script src="{{ mix('js/app.js') }}"></script>

また、Exampleコンポーネントを表示する場合、HTMLタグにidを指定して呼び出します。


<div id="example"></div>

動作確認

もういちど、サーバを確認してみると今度は、Exampleコンポーネントを読み込んだ状態で表示されました。

  2020/03/30

ペジネーションビューの書き出し

artisan コマンドで、ペジネーションビューをプロジェクト内に書き出します。


$ php artisan vendor:publish --tag=laravel-pagination

resources/views/vendor/pagination/ にページネーションのBladeファイルが作成されます。

あとで説明しますが、デフォルトは「bootstrap-4」で書き出されますが、ページネーションメソッドで他のBladeファイルを指定することができます。
よって、利用したいBladeファイルをカスタマイズしてください。

Eloquent モデルで取得

Eloquent モデルには、paginate()、simplePaginate() メソッドを利用できます。


$limit = 10;
$offset = 0;
$user = User::paginate($limit, '[*]', 'page', $offset);

AppServiceProvider に追加

AppServiceProvider::boot() でページネーションのBlade ファイル名を指定します。


    public function boot()
    {
        Paginator::defaultView('pagination::bootstrap-4');
        Paginator::defaultSimpleView('pagination::simple-bootstrap-4');
    }

Blade にページネーションを実装

Blade ファイルでは、Eloquent モデルデータの links() メソッドでページネーション表示できます。


{!! $user->links() !!}

また、Blade 側で明示的に指定することもできます。


{{ $paginator->links('pagination::bootstrap-4', ['key' => 'value']) }}

Eloquent のページネーションメソッドは以下を参照してください。

https://readouble.com/laravel/7.x/ja/pagination.html

<< Top < Prev Next > Last >>