はじめに
Laravel と Yii どちらともにアクション毎にフォームのバリデーションを分けたいとき、Laravel では Form Request Validation、Yii では Model を継承したフォームクラスを使えるんですが、役割に若干の違いがあるので、そこらへんをまとめたいと思います。
環境
Laravel 6.x
Yii 2.x
Laravel Form Request Validation
モデル:
app/Models/Post.php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'post';
protected $fillable = [
'title',
'content',
];
// ...
}
Form Request:
app/Http/Requests/PostStore.php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
class PostStore extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function attributes(): array
{
return [
'title' => 'Title',
'content' => 'Content',
];
}
public function rules(): array
{
return [
'title' => 'required|max:100',
'content' => 'required|max:10000',
];
}
protected function prepareForValidation(): void
{
// バリデーション前に何かを処理したい場合、ここに書くことができる
}
protected function failedValidation(Validator $validator): void
{
// バリデーション失敗時に何かを処理したい場合、ここに書くことができる
throw new ValidationException($validator);
}
protected function passedValidation(): void
{
// バリデーションが通ったあとに何かを処理したい場合、ここに書くことができる
}
}
コントローラー:
app/Http/Controllers/PostController.php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Http\Requests\PostStore;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class PostController extends Controller
{
// ...
public function create(): View
{
return view('post.create');
}
public function store(PostStore $request): RedirectResponse
{
Post::create($request->all());
return redirect()->route('post.index');
}
}
Yii の Model を継承したフォームモデル
モデル:
models/Post.php
declare(strict_types=1);
namespace app\models;
use yii\db\ActiveRecord;
/**
* @property int $id
* @property string $title
* @property string $content
*/
class Post extends ActiveRecord
{
public static function tableName(): string
{
return 'post';
}
}
フォームモデル:
models/PostCreateForm.php
declare(strict_types=1);
namespace app\models;
use yii\base\Model;
class PostCreateForm extends Model
{
public $title;
public $content;
public function attributeLabels(): array
{
return [
'title' => 'Title',
'content' => 'Content',
];
}
public function rules(): array
{
return [
[['title', 'content'], 'trim'],
[['title', 'content'], 'required'],
['title', 'string', 'max' => 100],
['content', 'string', 'max' => 10000],
];
}
public function beforeValidate(): bool
{
// バリデーション前に何かを処理したい場合、ここに書くことができる
return parent::beforeValidate();
}
public function afterValidate(): void
{
// バリデーション後に何かを処理したい場合、ここに書くことができる
parent::afterValidate();
}
public function save(): bool
{
// 処理が単純な場合、beforeValidate(), afterValidate() を使わずに validate() の前後に処理を書くこともできる
if ($this->validate()) {
// 例えばデータ保存処理
// データ保存後に何かを処理したい場合、ここに書くことができる
return true;
}
// バリデーションの失敗時に何かを処理したい場合、ここに書くことができる
return false;
}
}
コントローラー:
controllers/SiteController.php
declare(strict_types=1);
namespace app\controllers;
use app\models\PostCreateForm;
use Yii;
use yii\web\Controller;
use yii\web\Response;
// ...
class SiteController extends Controller
{
// ...
/**
* @return string|Response
*/
public function actionCreate()
{
$post = new PostCreateForm;
if ($post->load(Yii::$app->request->post()) && $post->save()) {
return $this->redirect(['index']);
}
return $this->render('index', [
'post' => $post,
]);
}
}
まとめ
Laravel の Form Request Validation は「ユーザーがリソースを更新する権限を持っているかの判断」と「ユーザーのフォーム入力に対してのバリデーション処理」と「バリデーション失敗時のリダイレクト処理」という役割を担っていて、Yii のモデルを継承したフォームクラスは、基本的に「ユーザーのフォーム入力に対してのバリデーション処理のみ」がメインで、あとの諸々の処理 (ログイン処理であったり、データの保存処理であったり) は適当にそこでやってくれという感じで、わりとモデルとの関わりが濃い印象でした (Model を継承しているので当たり前ですが) 。