Help us understand the problem. What is going on with this article?

Yii 2: スタンドアローンなアクションについて

More than 5 years have passed since last update.

はじめに

各コントローラのアクションに同じようなコードを書いているのであれば、それを再利用可能な形にするということは、保守性の面からいっても大事かなと思います。そこで Yii 1.x でもあった機能ですが、Yii 2 のスタンドアローンなアクションについて少しだけですが紹介したいと思います!

例えば Gii の CRUD Generator でコードを自動生成するとコントローラの actioinCreate() は以下のようなものになっています。

HogeController.php
class HogeController extends Controller
{
    public function actionCreate()
    {
        $model = new Hoge();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }
}

フォームから値を受け取って、正しい値ならデータを保存して /view/12345 にリダイレクトする、みたいなごく一般的なデータの追加アクションです。このようなコードが他のコントローラにもたくさんあったとしたら、以下のように再利用可能な形に書き換えることができます。

CreateAction.php
<?php

namespace app\actions;

use Yii;
use yii\base\Action;

class CreateAction extends Action
{
    public $modelClass;
    public $modelNamespace = 'app\models';
    public $view = 'create';

    protected function beforeRun()
    {
        $modelClass = $this->modelClass;

        if ($modelClass === null) {
            $modelClass = ucfirst($this->controller->id);
        }
        $this->modelClass = $this->modelNamespace . '\\' . $modelClass;

        return true;
    }

    public function run()
    {
        $model = new $this->modelClass;

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->controller->redirect(['view', 'id' => $model->id]);
        }
        return $this->controller->render($this->view, [
            'model' => $model,
        ]);
    }
}

多少長くなりますが、一度書いておけば他のコントローラでも、他のプロジェクトでも使いまわせるのでとても便利です。yii\base\Action クラスを継承したクラスを追加し run() というメソッド内に再利用可能なコードを書いていきます。コントローラには $this->controller でアクセスできます。run() が呼ばれる前に何か処理を追加したい場合は beforeRun() メソッド内に記述します。run() が呼ばれたあとに何か処理をしたい場合のために afterRun() というメソッドも用意されています。

コントローラ側では actions() メソッドを追加して、どの再利用アクションを使うのか指定します。以下の場合 actionCreate() は app\actions\CreateAction クラスを使う、という意味になります。

HogeController.php
class HogeController extends Controller
{
    public function actions()
    {
        return [
            'create' => 'app\actions\CreateAction',
        ];
    }

コントローラがすっきりしました!

上記の CreateAction() の場合、モデルクラスはコントローラの ID 名を使って処理しているので、モデルクラスとコントローラ ID 名が異なる場合はパラメータを追加して調整してやります。

HogeController.php
public function actions()
{
    return [
        'create' => [
            'class' => 'app\actions\CreateAction',
            'modelClass' => 'Fuga', // 調整
        ],
    ];
}

$modelNamespace$view も同様ですが、yii\base\Action クラスを継承したクラスの public なプロパティはコントローラの actions() のパラメータとして変更可能なものになります。

気をつけておきたいこと

自分は一般的な CRUD のために再利用可能な CURD アクション (ファイル構成: BaseAction, IndexAction, CreateAction, ViewAction, UpdateAction, DeleteAction) を作ってみたりしたんですが、コントローラをすっきりさせるために、あれやこれや処理を追加していってどうしたもんかなぁという状況に陥りました。あらゆるものに対処するために処理を詰め込めばそれ相応にコントローラはすっきりしますが、逆に再利用可能なアクションクラスたちは複雑さを増してきてメンテナンスも大変になります。

ですので、再利用可能なアクションクラスも (キャプチャアクションのような特定の機能に特化したアクションなどは別ですが ) できるだけシンプルで最低限の機能のみ実装しておいて、あとはコントローラに普通にそのまま記述するか、それでもコントローラが太っていく場合は、アプリケーションコンポーネントなどを利用する形を取るのが良いのかなと思います。要はバランスと使い分けです。

参考にできるクラス

以下は Yii のコアで書かれている yii\base\Action を継承したクラスたちです。あと yii\rest\Action を継承した CRUD クラスもあります。ここらへんのコード読むといろいろヒントもありそうですね!

おわりに

簡単ではありますが、スタンドアローンなアクションについて紹介しました。詳しくは公式ガイドにも書かれていますので、以下の関連リンクなどを参考にしてみて下さい。

現時点ではまだ公式サイトに Yii 2 の日本語ガイドのページがないみたいなので、yiijan/yii2-i18n-ja という日本の Yii ユーザさんが集まってガイドなどを翻訳しているリポジトリのリンクを貼っておきます。

関連リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした