20191009のlaravelに関する記事は5件です。

【Laravel】管理画面と一般サイトでログファイルを分けてみる

一般ユーザがアクセスする画面と、管理者がアクセスする画面があるサイトの場合、一つのログに出力していると、両方のログが混在して「これはどっちの処理のログ?」みたいになって分かりづらい。

  • 一般ユーザは、一般ユーザ用のログファイルに出力
  • 管理者は、管理者用のログファイルに出力

という風に完全に分けられれば見やすくなるはず。

さっそく分けてみた。

環境

  • laravel 5.8

前提

一般ユーザ用の画面

「https://example.com/admin」配下以外は全部、一般ユーザ用

管理画面

逆に「https://example.com/admin」配下は全部、管理画面

作ってみた

Larvael5.6からログの設定方法・出力方法が大きく変わった様で、今回は5.8で試しています。(検証はしてないけど、たぶん5.6〜5.7でも動くのではないかと。)

ざっくりとした手順

  1. 一般ユーザ用と管理者用のログチャネルを作成
  2. ログ出力用の自作ファサードを作成し、そこでログチャネルを指定する
  3. 自作ファサードの登録

一般ユーザ用と管理者用のログチャネルを作成

ログ設定用のコンフィグファイルに設定を追加します。
adminチャネルとuserチャネルを追加し、それぞれ出力先ファイルを指定する。

/config/logging.php
    'channels' => [
        /**
         * 
         * 元々書いてある設定は省略
         * 
         */


        //以降を追加
        'admin' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel_admin.log'),
            'level' => env('LOGGING_LEVEL', 'info'),
            'days' => env('LOG_ROTATE_DAYS', 14),
        ],

        'user' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel_user.log'),
            'level' => env('LOGGING_LEVEL', 'info'),
            'days' => env('LOG_ROTATE_DAYS', 14),
        ],
    ],

ログ出力用の自作ファサードを作成し、そこでログチャネルを指定する

ファサードクラス

公式の手順通りに作成

/app/Facades/CustomLogFacade.php
<?php

namespace App\Facades;


use App\Services\Support\CustomLogSupport;
use Illuminate\Support\Facades\Facade;

class CustomLogFacade extends Facade
{

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return CustomLogSupport::class;
    }
}

ロジッククラス

ファサードの本体を作成します。

/app/Service/Support/CustomLogSupport.php
<?php

namespace App\Services\Support;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;

class CustomLogSupport
{
    public function __call($name, $args)
    {
        $chanel = 'stack';
        try{
            $domain = config('app.url');
            $url = Request::url();
            if(Str::is($domain.'/admin/*', $url)){
                $chanel = 'admin';
            }else if(Str::is($domain.'/*', $url)){
                $chanel = 'user';
            }else{
                $chanel = 'batch';
            }
        }catch (\Exception $e){
            //握りつぶす
        }

        $collectArgs = collect($args);
        Log::channel($chanel)->{$name}($collectArgs->shift(), $collectArgs->toArray());
    }
}

マジックメソッドの__call()を使って、Logファサードをラップしてます。
その際にchannel($chanel)で使用するチャネルを指定しています。

このチャネル振り分けロジックを変えればサブドメイン毎にログを分ける事もできそうです。

自作ファサードの登録

これもお決まり通りに登録します。

サービスコンテナに登録

/app/Providers/AppServiceProvider.php
    public function register()
    {
        //ログ出力
        $this->app->singleton(CustomLogSupport::class, CustomLogSupport::class);
    }

ファサードの登録

/app/config/app.php
    'aliases' => [
        /**
         * 
         * 元々書いてある設定は省略
         * 
         */


        'CustomLog' =>  \App\Facades\CustomLogFacade::class,
    ],

結果

$ ls
laravel_admin-2019-10-09.log    laravel_user-2019-10-09.log

分割して出力された!

ちなみにファサードの実態クラス(今回でいうとCustomLogSupport)ってどういうクラス名で、どういうディレクトリに格納するのが一般的なんですかね?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】ログファイルを機能ごとに分けてみる

一般ユーザがアクセスする画面と、管理者がアクセスする画面があるサイトの場合、一つのログに出力していると、両方のログが混在して「これはどっちの処理のログ?」みたいになって分かりづらい。

  • 一般ユーザは、一般ユーザ用のログファイルに出力
  • 管理者は、管理者用のログファイルに出力

という風に完全に分けられれば見やすくなるはず。

さっそく分けてみた。

環境

  • laravel 5.8

前提

一般ユーザ用の画面

「https://example.com/admin」配下以外は全部、一般ユーザ用

管理画面

逆に「https://example.com/admin」配下は全部、管理画面

作ってみた

Larvael5.6からログの設定方法・出力方法が大きく変わった様で、今回は5.8で試しています。(検証はしてないけど、たぶん5.6〜5.7でも動くのではないかと。)

ざっくりとした手順

  1. 一般ユーザ用と管理者用のログチャネルを作成
  2. ログ出力用の自作ファサードを作成し、そこでログチャネルを指定する
  3. 自作ファサードの登録

一般ユーザ用と管理者用のログチャネルを作成

ログ設定用のコンフィグファイルに設定を追加します。
adminチャネルとuserチャネルを追加し、それぞれ出力先ファイルを指定する。

/config/logging.php
    'channels' => [
        /**
         * 
         * 元々書いてある設定は省略
         * 
         */


        //以降を追加
        'admin' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel_admin.log'),
            'level' => env('LOGGING_LEVEL', 'info'),
            'days' => env('LOG_ROTATE_DAYS', 14),
        ],

        'user' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel_user.log'),
            'level' => env('LOGGING_LEVEL', 'info'),
            'days' => env('LOG_ROTATE_DAYS', 14),
        ],
    ],

ログ出力用の自作ファサードを作成し、そこでログチャネルを指定する

ファサードクラス

公式の手順通りに作成

/app/Facades/CustomLogFacade.php
<?php

namespace App\Facades;


use App\Services\Support\CustomLogSupport;
use Illuminate\Support\Facades\Facade;

class CustomLogFacade extends Facade
{

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return CustomLogSupport::class;
    }
}

ロジッククラス

ファサードの本体を作成します。

/app/Service/Support/CustomLogSupport.php
<?php

namespace App\Services\Support;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;

class CustomLogSupport
{
    public function __call($name, $args)
    {
        $chanel = 'stack';
        try{
            $domain = config('app.url');
            $url = Request::url();
            if(Str::is($domain.'/admin/*', $url)){
                $chanel = 'admin';
            }else if(Str::is($domain.'/*', $url)){
                $chanel = 'user';
            }else{
                $chanel = 'batch';
            }
        }catch (\Exception $e){
            //握りつぶす
        }

        $collectArgs = collect($args);
        Log::channel($chanel)->{$name}($collectArgs->shift(), $collectArgs->toArray());
    }
}

マジックメソッドの__call()を使って、Logファサードをラップしてます。
その際にchannel($chanel)で使用するチャネルを指定しています。

このチャネル振り分けロジックを変えればサブドメイン毎にログを分ける事もできそうです。

自作ファサードの登録

これもお決まり通りに登録します。

サービスコンテナに登録

/app/Providers/AppServiceProvider.php
    public function register()
    {
        //ログ出力
        $this->app->singleton(CustomLogSupport::class, CustomLogSupport::class);
    }

ファサードの登録

/app/config/app.php
    'aliases' => [
        /**
         * 
         * 元々書いてある設定は省略
         * 
         */


        'CustomLog' =>  \App\Facades\CustomLogFacade::class,
    ],

結果

$ ls
laravel_admin-2019-10-09.log    laravel_user-2019-10-09.log

分割して出力された!

ちなみにファサードの実態クラス(今回でいうとCustomLogSupport)ってどういうクラス名で、どういうディレクトリに格納するのが一般的なんですかね?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel bladeから静的ページを生成して表示速度を改善してみたい

概要

  • bladeから静的ページを生成しそのページを表示する
  • データの更新時には一緒に更新する

という運用をやってみようという記事

手順例

HTMLファイル生成するイベントを作る

こんな感じのことをするイベントを作成する。
記事ページなどの単一のモデルのデータしか使わない場合は、Modelに定義するとよさそうです。

public function __construct(User $user)
{
     $html = view('home.home')->with('user', $user)->render();

    // htmlファイルの保存場所は任意
    file_put_contents(storage_path("app/public/home.html"), $html);
}

イベントを発火

作ったイベントをModelの$dispatchesEventsに定義したりなどして、更新時に動くようにする。
後はコマンドにしたり。

ルーティング

例えば

Route::get('/', function () {
    // \Illuminate\Support\Facades\File
    return \File::get('storage/home.html');
});

備考

  • 必要ならばファイルを削除するイベントも作って、削除時に発火させる
  • HTMLファイルが無かったら通常通りbladeを表示するようにすると、安心する
  • ビューにControllerやMiddlewareからデータを渡しているとレンダーされる時に読み込まれないので、ViewComposerで定義すると嬉しい

おわり

記事ページ等はbladeの更新の際に全HTMLファイルを更新する必要が出てくるので、向かないかもしれません。
運用には注意が必要ですが、bladeの更新頻度が低いかつ表示速度が遅いページの改善法として有効だと思います。TOPページなど。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのミューテタはfillableに設定できるか

タイトル通り。

結論としては使えます。

※Laravel:6.0.3

サンプル

class User extends Model
{
    protected $fillable = [
        'name',
        'age'
    ]
}
>>> App\User::create(["name" => "hoge", "age" => 99])
=> App\User {
     id: 1,
     name: "hoge",
     age: 99,
     updated_at: "2019-10-09 10:20:33",
     created_at: "2019-10-09 10:20:33",
   }

ミューテタを追加

class User extends Model
{
    protected $fillable = [
        'name',
        'age',
        'birthday'
    ]

    public function setBirthdayAttribute($value)                                                                                      
    {                                                                                                                                 
        $this->attributes['age'] = CarbonImmutable::parse($value)->age;                                                      
    } 
}

birthdayの方で作ってみる

>>> App\User::create(["name" => "fuga", "birthday" => "2000-04-01"])
=> App\User {
     id: 2,
     name: "fuga",
     age: 19,
     updated_at: "2019-10-09 10:35:48",
     created_at: "2019-10-09 10:35:48",
   }

fillableに残っているのでageもそのまま使える

>>> App\User::create(["name" => "piyo", "age" => 50])
=> App\User {
     id: 3,
     name: "piyo",
     age: 50,
     updated_at: "2019-10-09 10:36:01",
     created_at: "2019-10-09 10:36:01",
   }

birthdayで必ず作りたいならfillableからageを外してしまえばokです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Telescopeをアンインストールする

config/app.phpからTelescopeServiceProviderを削除

app.php
App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,//←これ
App\Providers\RouteServiceProvider::class,

composerの依存関係からも削除する場合
composer remove laravel/telescope を実行する

削除せずに無効にしたい場合

composer.json

"extra": {
        "laravel": {
            "dont-discover": ["laravel/telescope"]
       }
},

composer dumpで再ロード

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む