Laravel5.5LTS、AtoZ#7、エラー箇所を開く

タグ: Laravel5.5  

シリーズ第7弾は、エラー表示ページです。Laravel5.5では、エラー発生時の表示ライブラリーのWhoopsが復活しました。バージョン4のときに採用されましたが、依存パッケージを含めてLaravel全体の容量が大きすぎると言う理由で外されました。

数年間で、ファイル容量についての考えも変わりました。Laravelのコードが多少容量を喰おうとも、便利であれば問題ないとする考えが今では主流です。そうして、今回のLTSで復活したわけです。

エラー表示

Whoopsの画面を出さなくてはなりません。適当にエラーを起こしましょう。

senyouルートを追加したときに使用した、routes/web.phpを開きましょう。適当にエラーを発生するようにしてください。

Route::get('/senyou', function() {return '<h1>専用ページ</h1>';})
    ->middleware('auth'); aaaa

aaaaを付けました。当方のIDEは既にエラーだと指摘しています。しかし、このまま保存して、ブラウザでアクセスしてみましょう。Whoopsのエラーページが表示されます。

左上部はエラーの内容、左下部は実行スタックです。実行スタックはクリックすることで、右側のコード部分の表示が切り替わります。

右側の一番上部に、ソースのパスが表示されています。これからの仕込みで、ここが"Open: パス名"になり、リンクにかわります。これをクリックすると、好きなエディターやIDEが開くようにしようと言うわけです。

作業方針

Whoopsはエラー発生箇所を独自のプロトコル(スキーム)を利用しリンクとして用意してくれる機能があります。この機能は、Laravelのデフォルトで有効になっていません。

独自のプロトコルは、たとえばSublimeエディターで開く場合は、sublです。HTTPの場合はURLはhttp://...ですが、プロトコルの部分をsubl://...と指定したリンクが用意されます。

一応、Whoopsが対応しているブラウザは、Whoopsのドキュメントを見てください。

ただし、Whoopsは独自のプロトコルでURLを作成するだけです。それをブラウザが処理できると決まっているわけでありません。

こうしたプロトコルは、ブラウザごとに無視するのか、どのプログラムで使用するのか設定されています。

バージョン4のときに、対応する方法は既に記事にしています。

今回は、多少方針を変更します。whpsというオリジナルプロトコルを利用します。このプロトコルを処理するシェルプログラムを用意し、ブラウザでwhpsプロトコルのリンクがクリックされたら、このシェルを動作するようにします。

シェルプログラムはLinux環境で動作します。URLが引数で渡されるので、それを解析し、起動したいIDEやエディターへ渡すだけです。他のOSでも、同じ動作をするものは簡単に作成できるでしょう。(PHPだけでも、実装できます。)

例外ハンドラ

例外ハンドラで、Whoopsへの処理を行っている関数をオーバーライドします。app/Exceptions/Handler.phpを開いてください。use文とwhoopsHandler関数を追加します。

// use文部分

use Exception;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Support\Arr;
use Whoops\Handler\PrettyPageHandler;

// 追加する関数部分
    /**
     * 内部でnewしているため、オーバーライド
     */
    protected function whoopsHandler()
    {
        return tap(new PrettyPageHandler(), function ($handler) {
            // 以下のコードを親のコードに追加
            // whpsというオリジナルなプロトコルでリンクさせる
            $handler->setEditor(function ($file, $line) {
                return "whps://open?file=$file&line=$line";
            });

            // これ以下のコードは親と同じ

            $files = new Filesystem();

            $handler->handleUnconditionally(true);

            foreach (config('app.debug_blacklist', []) as $key => $secrets) {
                foreach ($secrets as $secret) {
                    $handler->blacklist($key, $secret);
                }
            }

            $handler->setApplicationPaths(
                array_flip(Arr::except(
                        array_flip($files->directories(base_path())), [base_path('vendor')]
                ))
            );
        });
    }

このクラスは、Illuminate\Foundation\Exceptions\Handlerを拡張していますが、whoopsHandler関数の動作を変更するにはオーバーライドするしかありません。親のコードをコピーし、プロトコルを含んだリンクURLを定義しました。

このURLはシェル側で処理するため、どのような形式でもよいのですが、"whps://open?file=ファイルパス&line=行番号"の形式にしています。

保存したら、Whoopsのエラーページを再読込してください。右上部のファイルパスが、リンクになっています。

まだクリックしないでください。

シェルプログラム

適当な場所に作成し、実行権限を付けます。私は名前をopen-whpsにしました。

#!/bin/bash

f=`echo $1 | cut -d \\& -f 1 | sed 's/whps:\/\/open?file=//'| php -r 'echo urldecode(fgets(STDIN));'`

l=`echo $1 | cut -d \\& -f 2 | sed 's/line=//'`

# Homesteadを使用している場合、ファイルはHomestead内のパスです。
# ホスト側から編集している場合、ホストの共有フォルダー名へ変換しましょう。
# たとえば、PHPで変換するなら、以下のようにします。
f=`echo ${f} | php -r 'echo str_replace("/home/vagrant/install/", "/home/皆さんのログイン名/install/", fgets(STDIN));'`

# コマンドライン引数を合わせ、お好きなIDEやエディターを起動してください。
# $fがファイル名、$lが行数です。
# 以下の例では、NetBeansを起動しています。
/home/皆さんのログイン名/netbeans-8.2/bin/netbeans --open ${f}:${l}

Firefoxのプロトコルハンドリング設定

Firefoxでの設定は簡単です。

  1. 上部のロケーションバーに"about:config"と入力し、Enterを叩いてください。警告ダイアログがでますが、OKボタンをクリックし、進めてください。
  2. 設定名と値の一覧が表示されます。どこでも良いので右クリックし、メニューの中から「新規作成」→「真偽値」を選びます。
  3. 設定名に"network.protocol-handler.expose.whps"と入力し、値は"false"を選択します。最後の"whps"がプロトコル名です。

これで、Whoops上のリンクをクリックしてください。どのプログラムを起動するか聞かれますので、作成したシェルスクリプトをフルパスで指定します。

Chromeのプロトコルハンドリング設定

Google Chromeは、OSのデフォルトを使用しているようです。

LinuxのChromeは未知のプロトコルをxdg-openを使用し開きます。これは、プロトコルや拡張子に対応するデフォルトアプリケーションで指定ファイルを開くLinuxのコマンドラインツールです。

まず、アプリケーションを登録するためのdesktopファイルを作成します。~/.local/share/applicationsに、whps.desktopを以下の内容で作成してください。EXECに皆さんの作成したシェルスクリプトのファイルパスを指定します。

[Desktop Entry]
Comment[ja_JP]=
Comment=
Categories=Application
Exec=/home/皆さんのログイン名/open-whps
GenericName[ja_JP]=
GenericName=
MimeType=
Name[ja_JP]=whpsプロトコル起動
Name=Open whps protocol
Path=
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=

同じディレクトリのdefaults.listを開き、最後に次の一行を追加します。(本来xdgのツールを使って設定するのが良いのですが、当方の環境では環境変数が正しく設定されていないらしく、動作しませんでした。間違えなければ、直接編集しても問題ありません。)

x-scheme-handler/whps=whps.desktop

これで、Whoopsのリンクをクリックすれば、指定のアプリケーションで問題のあるソースの行頭にカーソルが移動します。