Laravelの共通処理はtraitにまとめると便利【Laravel】

公開日:

最終更新日:

Laravelの共通処理はtraitにまとめると便利【Laravel】

traitについてはLaravel固有の機能ではなく、PHPの話になります。
私はエンジニアやプログラマー方ほど常に勉強しながらプログラムを書いている訳ではなく、traitを調べて利用したのはLaravelがきっかけでした。

実際に調べてみると、今までPHPで記述していたプログラムの中でもtraitを利用することによって、同様の記述をしていた部分を省略できて簡素化できた部分が多くあったので、この際にtraitについてもぜひ調べてみてください。

今回のテーマとしてはLaravelでtraitを利用する際の書き方や私が実際に書いた処理について書きます。

どういったときにtraitを使えばいいのか

本筋とは少し違った話題になるかもしれませんが、いったんこういう話もしておいたほうがいいかなと思ったので書きます。

私自身コード修正や追加機能の実装時によくあることなのですが、機能の実装が重なることと納期の優先をするあまり、特に設計も何も考えずにその場しのぎのコードを書いてしまうことが多いです。

掘り返していくと、実際にはある程度使い回しできるコードが何度も書いてあったり、記述量が多くなりすぎて編集した本人ですら時間を空けると分からなくなってしまうという惨状がおきます。(最初から気を配ってやればいい話ではあるのですが・・・。)

親クラスをextendsで継承していく手もあるのですが、その場合は親クラスは1つしか継承できないため汎用クラスを作成してさらに継承させて・・・といったことになり、どこでどの処理を行っているのかがわかりにくくなると思います。

そこでtraitを利用してクラス自体の処理系統の細分化を行い、同様の記述を共通処理としておくことで、コードの見やすさも確保でき、かつ簡単に処理を追加できるといった感じです。

Laravelでtraitを利用する

Laravelをインストールする際にcomposerを使っていると思うので、本来ならばrequireでファイルを読み込まなければいけないところをautoloadで読み込んでくれるので、難しい設定をする必要はありません。

traitファイルを作成する

今回は私がたずさわった案件で「ブラウザの戻るボタンがわからない人もいるので、画面内に戻るボタンを実装してほしい」と何をいってるかわからない要望があったので、いつものごとくjsでhistory.back()でいいかと思っていたのですが、よく考えると編集画面→更新処理→編集画面にリダイレクトとなっているので「編集画面から抜けられない」という問題に直面しました。

Laravelではsession()->flash()とすることで次のリクエストまでsessionにデータを保存することができるので、それを利用して編集画面に遷移する前のページを判断することにしました。

<?php
namespace App\Http\Trait;

trait BackToUrlTrait{
  private function backToUrl($useRequest, $getPrevious = false)
  {
    //編集前URLをflashに保存
    if($useRequest->session()->has('previous_url')){
      $useRequest->session()->keep(['previous_url']);
    }else{
      if($getPrevious === true){
        if($useRequest->session('previous_url') && url()->previous() === session('previous_url')){
          $useRequest->session()->keep(['previous_url']);
        }else{
          $useRequest->session()->flash('previous_url', url()->previous());
        }
      }
    }
    //前の画面がログイン画面の場合はトップページへのリンクにする
    if(session('previous_url') && strpos(url()->previous(), 'login') !== false){
      $useRequest->session()->flash('previous_url', url('/'));
    }
  }
}
?>

今考えてみるとLaravelでごちゃごちゃせずともjsのsessionStrageでなんとかできた気もしますが、おおむね想定通りに動いていたので自分の中では良しとします。

例えばHomeControllerで利用するのであれば、namespaceと書かれている下に該当ファイルまでのパスをuseで追加します。
ちなみにautoloadの規約としてはファイル名とクラス名は対になる必要があるので、そこさえ注意すれば問題ありません。

後はautoloadでよしなにやってくれているので、クラス内でまたuseしてやれば利用できるようになります。

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Trait\BackToUrlTrait; // 追加
class HomeController extends Controller{
  use BackToUrlTrait; // 追加
  index(Request $request){
    // 一覧画面
    return view('home.index');
  }
  create(Request $request, $id){
    // 作成画面
    // 新規作成の場合はsession('previous_url')の存在と値を確認して、条件に当てはまらなければflashにURLを保存
    $this->backToUrl($request, true);
    return view('home.create');
  }
  store(Request $request){
    // 作成処理
    // session('previous_url')の存在を確認して、keep()で値を保持する
    $this->backToUrl($request);
    return redirect('/'.$id);
  }
  show(Request $request, $id){
    // 詳細画面
    $this->backToUrl($request, true);
    return view('home.show');
  }
  edit(Request $request, $id){
    // 編集画面
    $this->backToUrl($request, true);
    return view('home.edit');
  }
  update(Request $request, $id){
    // 更新処理
    $this->backToUrl($request);
    return redirect('/'.$id.'/edit');
  }
}
?>

例えばこのような感じで使えば、おおよそどこから流入してもブラウザ内の戻るボタンのURLをsession(‘previous_url’)から正常に取得できるはずです。

ただ、この場合はバリデーションエラー後はうまくURLが取得できないので、バリデーション後のフックやtraitを利用してfailedValidationメソッドをオーバーライドしたりなどして必要があります。

その辺りについては後ほど書くかもしれないし書かないかもしれないです。
書くとしても、もうちょっと勉強して理解してから書くことになりそうですが・・・。

まとめ

Laravelは決まった書き方といったものが探してみてもなかなか見つからないため、わたしも調べつつ試しつつの状態で実装したりしています。

今回の実装も思いついたままに実装してみたらうまくいったといった感じなので、ほかにも様々な実装方法を調べてみてベストな方法を模索したいと思います。

フレームワークを触っていると新しい記述方法や小手先の知識では見抜けないような実装方法が多いので、PHP自体の理解も深まっていい刺激になっています。

まだまだtraitについても理解が乏しい部分があるので、今後も先人の知恵を頼りつつインプットを続けます。

関連記事