バリデーションって何?必要?
サービスクラスって何?メリットは?
Laravelでの実装方が知りたい!
本記事はこんな悩みを解決します。
この記事を書いている私は、
2020年1月現在メガベンチャーの社内スタートアップの部署でエンジニア(1年目)をしてます。
プログラミング未経験からメガベンチャーへの転職を成功させた経験・ノウハウ
Webエンジニアになってから学んだこと
をブログにまとめています。
本記事では、「バリデーション」と「サービスクラス」をソースコード付きで解説します。
前回記事でAjaxでのポストを実装しましたが、
そこにバリデーションとロジック部分をサービスクラスに分離することで
少し実践的なソースコードに変えていきます。
Github: https://github.com/Shuto-san/laravel-vue-docker
バリデーションとは?必須なの?
バリデーション(validation)を英訳すると、
「検証、実証、妥当性」
といった意味ですが、
プログラミングの世界では、
入力されたデータが正しいかどうか検証する
ことを意味します。
よくエンジニアとの会話では
「変数をバリデする」
という感じで登場します。
入力されたデータは正しいのかどうかは
どんなシステムでも必ず行われなければならない
バリデーションはまさにエンジニアにとっては必須の知識・スキルです。
本記事では、バックエンド側(PHP/Laravel)での実装例のみを紹介しますが、
当然バリデーションは
フロントエンド側(JS)、バックエンド側(PHP)の両方で行われるべきです。
「バリデーションは両側で必ずやって」
と入社当初口酸っぱく言われたものです。。。
バリデーション(Laravel)
Laravelの実装はとても簡単です。
まず、Httpリクエスト時に入力データに対するバリデーションルール
を設定できるクラスを以下のコマンドで自動生成します。
php artisan make:request TweetRequest
app/Http/Requests以下にTweetRequestクラスが自動生成されるので
バリデーションルールを実装します。
- app/Http/Requests/TweetRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class TweetRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
// change false => true
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
// configure validation rules
return [
'tweet' => 'required|min:1|max:255',
];
}
}
authorize()は、ユーザーのリクエスト権限を判定するメソッドですが、
今回は返り値をtrueにして全ユーザーに対してリクエストの権限を付与します。
rules()にバリデーションルールを記述します。
required=>必須項目、min:1=>最小1文字、 max:255=>最大255文字
としました。
あとはコントローラークラスで、設定したルールでバリデーションを行います。
- app/Http/Controllers/TweetController.php
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Requests\TweetRequest $request
* @return \Illuminate\Http\Response
*/
public function store(TweetRequest $request)
{
// validate posted tweet
$validatedTweet = $request->validated();
// ....
}
TweetRequest
のvalidate()
メソッドを用いることで、
先ほど設定したルールでバリデーションを行うことができます。
成功したらコードは通常通り続けて実行されます。
逆にバリデーションに失敗すると、例外が投げられ、
ユーザーに対し自動的に適切なJSONエラーレスポンスが返されます。
これでリクエスト毎にバリデーションが実行されるようになります!
サービスクラスとは?
サービスクラスとは、リクエストのビジネスロジックやDB処理をまとめて記述するためのクラスです。
Laravelではコマンドによるサービスクラス自動生成はサポートされておらず、
処理を実行する上で必須なクラスではありません。
特に一人で開発しているとサービスクラス必要性を感じにくいかもしれません。
Laravelでは、
リクエストに対する処理はコントローラークラスに記述することになっていますね。
ところが
システムの規模が大きくなったり
リクエストに対する処理ロジックが煩雑になってくるとと
当然ながらコントローラークラスのコード量がどんどん膨れていきます。
コントローラークラスが膨れ上がると
他の人はおろか自分でもどこに何が書いてあるか分かりにくい。。。
コードの変更箇所を発見するのに時間がかかるし、修正箇所が多くなる。。。
サービスクラスはそんな状況を助けます。
処理が煩雑なビジネスロジックやDB処理をサービスクラスに切り出してあげることで
可読性や保守性の向上や単体テスト実施など、
システム開発の効率化に多くのメリットがあります。
したがって筆者は、Laravelにも基本的にサービスクラスを導入することにしています。
(※システムの設計指針によります)
具体的な実装例を紹介します。
サービスクラス作成
artisanコマンドで自動生成は出来ないので、
まず、ディレクトリapp/Http/Services
を作成します。
作成したディレクトリにサービスクラスを作成していきます。
- app/Http/Services/TweetService.php
<?php
namespace app\Http\Services;
use App\Tweet;
use Illuminate\Support\Facades\Auth;
class TweetService {
public function saveTweet($postedTweet)
{
$user = Auth::user();
$tweet = new Tweet();
$tweet->user_id = $user->id;
$tweet->nickname = $user->name;
$tweet->tweet = $postedTweet['tweet'];
$tweet->save();
return $tweet->tweet;
}
}
前回TweetController
のstore
メソッド内に書いていたDB処理をサービスクラスに切り出しました。
今後、DBやRedisに接続しに行く処理はサービスクラスに記述していくことにしましょう。
そしてTweetController
から呼び出します。
- app/Http/Controllers/TweetController.php
<?php
namespace App\Http\Controllers;
use App\Http\Services\TweetService;
use Illuminate\Http\Request;
use App\Http\Requests\TweetRequest;
class TweetController extends Controller
{
protected $tweetService;
public function __construct(TweetService $tweet_service)
{
$this->middleware('auth')->only(['index']);
$this->tweetService = $tweet_service;
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(TweetRequest $request)
{
// validate posted tweet
$validatedTweet = $request->validated();
// save tweet in DB
$tweet = $this->tweetService->saveTweet($validatedTweet);
return $tweet;
}
サービスクラスをコントローラークラスに依存注入する場合pretected
でサービスクラスの変数$tweetService
を定義
↓Construct(TweetService $tweet_service)
でコンストラクタの引数にサービスクラスのインスタンスを設定
↓
コンストラクタ内で$tweetService
にサービスクラスのインスタンスを代入
これでサービスクラスをコントローラークラス内で使えるようになります。store
メソッド内は
ツイート内容をバリデーション
↓
サービスクラスのメソッドにツイートを渡して呼び出し、
DB保存を実行
↓
ツイート内容をレスポンス
という処理の流れになりました。
コントローラーの中身がスッキリしましたね!
まとめ:バックエンド側バリデーション&サービスクラス作成
以上、Laravelのバリデーション実装方法とサービスクラスの活用法でした。
これで前回のただのAjaxリクエストのコードが
少しだけ実践的なコードに生まれ変わりました。
趣味で書くプログラミングと世にリリースするプロダクトは
品質が全く違います。
今後はより実践的なコードを
ブログやGithubに共有していきたいと考えています。
次回は、「バリデーション(Vue、ライブラリ不使用)」を解説します!
↓↓
それではまた!
コメント