コマンドライン上でのphp実行時に追加php.iniを読み込ませる

さくらレンタルサーバーではwebからのアクセス時に /home/[username]/www/php.ini が読み込まれるようになっています。

help.sakura.ad.jp

しかし、デプロイやバッチ処理などコマンドラインからの実行では読み込まれないため、手動でロードさせる必要があるようです。

https://www.php.net/manual/ja/features.commandline.options.php

php -c /home/[username]/www/php.ini filename.php

Laravelのキャッシュ生成・削除系コマンドの違い一覧

キャッシュ生成や削除コマンドはいくつか用意されているがコマンドによっては複数種のキャッシュを操作したりしなかったりするのでまとめておく。

command config route view event cache compiled description
config:cache C C Create a cache file for faster configuration loading
config:clear D C Remove the configuration cache file
route:cache C C Create a route cache file for faster route registration
route:clear D C Remove the route cache file
view:cache C C Compile all of the application's Blade templates
view:clear D C Clear all compiled view files
event:cache C C Discover and cache the application's events and listeners
event:clear D C Clear all cached events and listeners
cache:clear D C Flush the application cache
cache:forget D*1 C Remove an item from the cache
optimize C C C Cache the framework bootstrap files
optimize:clear D D D D D Remove the cached bootstrap files
clear-compiled D Remove the compiled class file

C: キャッシュ作成、 D: キャッシュ削除、 *1 指定されたキーのキャッシュのみを削除

基本的に xxx:cache ⇔ xxx:clear が対になっており、作成コマンドは削除→作成の順番で実行される。 optimize のみ操作が非対称な点に注意。 compiled キャッシュはLaravelアクセス時に自動生成されるため、compiledキャッシュ削除コマンド以外では生成される。

デプロイ時は以下のコマンド実行で一通りのキャッシュを葬り去ることができる。

php artisan optimize:clear 
php artisan optimize
php artisan view:cache
php artisan event:cache
// ジョブ機能を利用している場合のみ
php artisan queue:flush

各キャッシュの生成されるファイル一覧

config

/bootstrap/cache/config.php に各configがマージされた配列として保存される。

route

/bootstrap/cache/route.php に各routeがマージされ、シリアライズされたデータとして保存される。

view:cache

\storage\framework\views ディレクトリ内に各bladeファイルがphpにパースされたものが保存される。 また、ファイル名はsha1でハッシュ化される。 https://github.com/laravel/framework/blob/master/src/Illuminate/View/Compilers/Compiler.php#L51

event:cache

/bootstrap/cache/event.php に各イベントがマージされた配列として保存される。

compiled

依存パッケージのパス、サービスプロバイダが配列として保存される。 /bootstrap/cache/packages.php , /bootstrap/cache/services.php

Ruleクラスからドットを含むキー名のattributeを取得する

まずカスタムルールクラスでは任意のバリデーションエラーメッセージを返せます。

class ImageRule implements Rule
{
    public function passes($attribute, $value)
    {
        // do something
    }

    public function message()
    {
        return 'The :attribute must be image';
    }
}

この時、resources/lang/{locale}/validation.phpの共通エラーメッセージを引用して共通化する場合、少々手間がかかります。 方針としてはメッセージ生成にattribute名が必要なため、passesメソッド内でメッセージを生成し、messageメソッドではそれを返すようにします。

class ImageRule implements Rule
{
    private $message;

    public function passes($attribute, $value)
    {
        // do something

        $this->message = 'message';
    }

    public function message()
    {
        return $this->message;
    }
}
// image: 'message.'

次に翻訳されたメッセージを取得します。今回は既存のimageルールのメッセージ形式を利用します。

class ImageRule implements Rule
{
    private $message;

    public function passes($attribute, $value)
    {
        // do something

        $this->message =  __('validation.image');
    }

    public function message()
    {
        return $this->message;
    }
}
// image: 'The :attribute must be an image.'

最後にattribute名も同様に取得します。 この時、キー名がネストしていない(ドットを含まない)場合はそのままキー名で取得できます。

// validation.php
'attributes' => [
    'user.image' => 'Image',
],

class ImageRule implements Rule
{
    private $message;

    public function passes($attribute, $value)
    {
        // do something

        $this->message =  __('validation.image', ['attribute' => __('validation.attributes.'.$attribute)]);
    }

    public function message()
    {
        return $this->message;
    }
}
// image: 'The Image must be an image.'

キー名がネストしている場合(user.imageなど)一旦翻訳データ一覧を取得する必要があります。 $attribues['user.image'] ではなく、$attribues['user']['image'] へアクセスしてしまうドット記法の弊害です。

// validation.php
'attributes' => [
    'user.image' => 'Avatar Image',
],

class ImageRule implements Rule
{
    private $message;

    public function passes($attribute, $value)
    {
        // do something

        // validation.attributes配列のuser.imageキーの値を取得。
        $tranlated_attribute = app('translator')->get('validation.attributes')[$attribute];
        $this->message = __('validation.image', ['attribute' => $tranlated_attribute]);
    }

    public function message()
    {
        return $this->message;
    }
}
// user.image: 'The Avatar Image must be an image.'

'validation.attributes."user.image", 'validation.attributes.[user.image] などでもダメでした。

エラーをメールで送信する

LaravelではエラーログをファイルやSlackに設定一つで出力できる。 しかし管理者宛などにメールに出力する設定は用意されていないので作成してみた。 monologがいろいろ用意してくれているのでそれを継承するだけで実装可能。

  • 手順
  • メール送信用のハンドラを作成する
  • config/logging.php でメール送信用のチャンネルを追加する。

メール送信用のハンドラを作成する

適当なディレクトリに Monolog\Handler\MailHandler を継承したハンドラを作成する。 送信メソッドのみ定義すればOK。 https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/MailHandler.php#L49

namespace App\Handlers;

use Monolog\Handler\MailHandler as BaseHandler;

class MailHandler extends BaseHandler
{
    protected function send($content, array $records): void
    {
        // 送信処理
    }
}

config/logging.php でメール送信用のチャンネルを追加する。

先ほど作成したハンドラを使用するように設定。 通常のファイル出力とエラー時のみメール送信するように設定してみた。

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily', 'mail'],
            'ignore_exceptions' => false,
        ],
        'mail' => [
            'driver'  => 'monolog',
            'level' => 'error',
            'handler' => MailHandler::class,
        ],

ログインに条件を追加する

ログイン可能なユーザーを制限するときにどこいじると楽かの試行錯誤と結果。

やりたいこと

  • 有効なユーザかつ有効な所属企業の場合ログイン可能
  • Authの標準機能PWリセットが上記ユーザーの場合のみ利用可能

試したこと

  1. ログインコントローラーを改造する ⇒ PWリセットは別途対応が必要に(めんどい)
  2. ログイン可能ユーザーのEloquentモデルを別に定義する ⇒ Auth全般が適用範囲になるので楽
続きを読む

Docker for Windows で "driver failed programming external connectivity on endpoint" になるのを解決する

悲しみ

Docker for Windows を入れるためにわざわざ Windows10 を Home から Pro に変えたのに konozama.

docker-compose up -d
Creating network "app_name_default" with the default driver
Creating app_name_db_1 ... error

ERROR: for app_name_db_1  Cannot start service db: driver failed programming external connectivity on endpoint app_name_db_1 (xxxx): Error starting userland proxy: mkdir /port/tcp:0.0.0.0:13360:tcp:172.21.0.2:3306: input/output error

ERROR: for db  Cannot start service db: driver failed programming external connectivity on endpoint app_name_db_1 (xxxx): Error starting userland proxy: mkdir /port/tcp:0.0.0.0:13360:tcp:172.21.0.2:3306: input/output error
ERROR: Encountered errors while bringing up the project.

解決策

その場対応

win起動時に自動で立ち上がるdockerを再起動すれば直ります。

タスクバーで座礁しているクジラ型コンテナ船を Restart して大海原へ戻してあげればいいです。

f:id:ichi_404:20190112111252p:plain
restart docker

恒久的対応

Windowsご自慢の素敵機能「高速スタートアップ」を無効にすることで解消できます。

参考記事:https://github.com/docker/for-win/issues/1038#issuecomment-373231436

起動が遅くなる可能性がありますが、M.2のSSDを使っているので体感では分からず。

続きを読む

Hello World

今までは Qiita に記事を書載せていました。

https://qiita.com/ichi_404

が、Qiitaの圧倒的ドメインパワーでびみょい記事が伸びたりしてしまうので、びみょい記事はこちらに書くことに。

f:id:ichi_404:20190112113438p:plain
kuso記事が4位に出る不具合
なんかでてくる マークダウンが使えるので楽ですね!