Ground Sunlight

Windowsで作る - PHPプログラミングの開発環境

ユーザ用ツール

サイト用ツール


サイドバー

メインメニュー

XAMPP アレンジ

IED

WSL2

道具箱

リポジトリ編

フレームワーク編

公開ソフトウェア

メタ
リンク


このページへのアクセス
今日: 1 / 昨日: 1
総計: 1660

apricot:ext:interceptor

文書の過去の版を表示しています。


編集中

Apricot インターセプター

y2sunlight 2020-05-25

Apricot に戻る

関連記事

インターセプター とはアクションの前処理の事です。ミドルウェアと同じでリクエストを中断してレスポンスオブジェクトを生成することもできますが、アクションの後処理はできません。これを図示すると以下のようになります。

                Middleware      Action
               ┌──────────┐     ┌───────────────────────────────────────────┐
               |          |     |  Interceptor   Interceptor   Real Action  |
               |          |     |  ┌─────────┐   ┌─────────┐   ┌──────────┐ |
[Request ] --> | -------> | --> |--|-------->|-->|-------->|-->| ────┐    | | 
               |    ↓     |     |  |    ↓    |   |    ↓    |   |     |    | |
               |    ↓     |     |  └─────────┘   └─────────┘   |     |    | | 
               |    ↓     |     |       ↓             ↓        |     |    | |
[Response] <-- | <------  | <-- | <--------------------------- | <───┘    | |
               |          |     |                              └──────────┘ |
               └──────────┘     └───────────────────────────────────────────┘

上図から分かるようにミドルウェアパイプラインから見ると、インターセプターはアクションに含まれます。ミドルウェアとの一番の違いは、ミドルウェアは基本的に全てのコントローラを対象としているのに対し、インターセプターは、各コントローラで独自に設定ができるという点です。

インターセプターの主な用途としては入力データの検証(バリデーション)、入力データのフィルタリングや変換です。インターセプターを作ることで、すっきりしたアクションを作ることができます。


ベースコントローラの変更

インターセプターの仕組みを実装するために、コアのベースコントローラ( BaseController )を以下のように変更します。

/apricot/core/Foundation

BaseController.php
<?php
namespace Core\Foundation;
 
/**
 * Request Controller Class (Controller Base)
 */
class BaseController
{
    /**
     * The interceptors registered on the controller.
     * @var array
     */
    protected $interceptors = [];
 
    /**
     * Register interceptors on the controller.
     *
     * @param  string $actionName
     * @param  array|mixed $interceptors array or arguments list
     */
    protected function intercept($actionName, $interceptors)
    {
        $interceptor_arr = is_array($interceptors) ? $interceptors : array_slice(func_get_args(),1);
        if (!array_key_exists($actionName, $this->interceptors))
        {
            $this->interceptors[$actionName] = array();
        }
        $this->interceptors[$actionName] = array_merge($this->interceptors[$actionName] , $interceptor_arr);
    }
 
    /**
     * Call real Action
     * @param string $actionName
     * @param array $params
     * @return \Core\Foundation\Response
     */
    protected function callAction($actionName, $params)
    {
        return call_user_func_array(array($this, $actionName), $params);
    }
 
    /**
     * Invoke Action
     * @param string $actionName
     * @param array $params
     * @return \Core\Foundation\Response
     */
    public function invokeAction($actionName, $params)
    {
        // Interceptor parameters
        $iparams = array_merge(array('_controller'=>$this), $params);
 
        // Invoke Interceptor
        if (array_key_exists($actionName, $this->interceptors))
        {
            $response = null;
            foreach($this->interceptors[$actionName] as $interceptor)
            {
                if (is_callable($interceptor))
                {
                    // Case of callable
                    $response = call_user_func_array($interceptor, $iparams);
                }
                elseif(strpos($interceptor,'@')!==false)
                {
                    // Case of Controller/Action
                    list($class, $method) = explode('@', $interceptor);
                    if (empty($class))
                    {
                        $instance = $this;
                    }
                    else
                    {
                        $class = "\\App\\Controllers\\Interceptors\\{$class}";
                        $instance = new $class;
                    }
 
                    // Call interceptor
                    $response = call_user_func_array(array($instance, $method), $iparams);
                }
 
                if ($response instanceof \Core\Foundation\Response)
                {
                    return $response;
                }
            }
        }
 
        // Call Action
        return $this->callAction($actionName, $params);
    }
}

callAction() メソッドに変更はありません。intercept() メソッドを追加し、invokeAction() メソッドを変更します。

  • intercept($actionName, $interceptors) メソッド
    • アクションにインターセプターを追加します。
    • BaseControllerは、インターセプターを配列( $this->$interceptors )で管理しています。
  • invokeAction($actionName, $params) メソッド
    • ミドルウェアパイプラインからはこのメソッドが呼び出されます。
    • インターセプターを登録順に実行し最後に実際のアクションを実行します。
    • インターセプターがResponseインスタンスを返した場合、処理は中止され、そのインスタンスをアクションのレスポンスとして返します。

インターセプターの使い方は、次項をご覧ください。


インターセプターの使用

インターセプターの登録は、コントローラーのコンストラクタで intercept() メソッドを使って行います。インターセプターにはクロージャーとメソッドの両方が使用できます。簡単なバリデーション処理ならクロジャーで以下のように書きます。

class FooController extends Controller
{
    public function __construct()
    {
        // インターセプターの登録
        $this->intercept('action', function(Controller $controller, int $id)
        {
            $inputs = Input::all();
            ...
        });
    }
    ...
}

インターセプターに渡される引数は、第1引数に、コントローラのインスタンスが、その後にアクションと同じの引数が続きます。

intercept() にメソッドを使用する場合は、以下のように 'クラス名@メソッド名' の形式で指定します。

class FooController extends Controller
{
    public function __construct(User $user)
    {
        // インターセプター登録
        $this->intercept('action1', 'FooInterceptor@action1');
        $this->intercept('action2', 'FooInterceptor@action2');
        ...
    }
    ....
}

Apricotでは、インターセプターを配置する場所は以下に決めれられいます。

aprocot/app/Controllers/Interceptors

結果として、インターセプタークラスの名前空間は \\App\\Controllers\\Interceptors になります。

自分自身( $this )のメソッドを指定する場合は、'@メソッド名' のように指定します。但し、自分自身のメソッドでも public でないとアクセスできません。


認証コントローラ

認証コントローラのバリデーションをクロージャ型のインタセプターとして再実装します。セッション認証の章で作ったAuthController クラスに以下の変更を行います。

  1. コンストラクタ( __construct() ) を作ります。
  2. コンストラクタ内で、login()アクションのインタセプターを登録します。
    $this->intercept('login', function(Controller $controller)
    {
      // バリデーションのロジック
    });
  3. login() メソッド内からバリデーション( validate() ) の呼び出しを削除します。
  4. validate() を削除します。

以下に修正後の AuthController.php を示します。

/apricot/app/Controllers

AuthController.php
<?php
namespace App\Controllers;
 
use Core\Input;
use Core\Foundation\ErrorBag;
use App\Foundation\Security\AuthUser;
use App\Foundation\Controller;
use App\Foundation\ValidatorErrorBag;
 
/**
 * Authコントローラ
 */
class AuthController extends Controller
{
    public function __construct()
    {
        // インターセプターの登録
        $this->intercept('login', function(Controller $controller)
        {
            $inputs = Input::all();
 
            // Validation
            $v =(new \Valitron\Validator($inputs))
            ->rule('required', 'account')
            ->rule('alphaNum','account')
            ->rule('ascii','password')
            ->labels(inputLabels('auth.login'));
 
            if(!$v->validate())
            {
                $errorBag = new ValidatorErrorBag($v->errors());
                return redirect(back())->withInputs()->withErrors($errorBag);
            }
        });
    }
    ...
 
    /**
     * ログイン(ユーザ認証)
     * @return \Core\Foundation\Response
     */
    public function login()
    {
        $inputs = Input::all();
 
        if (!AuthUser::authenticate($inputs['account'], $inputs['password'], !empty($inputs['remember'])))
        {
            // ユーザが見つからない
            $errorBag = new ErrorBag([__('auth.login.error.no_account')]);
            return redirect(back())->withInputs()->withErrors($errorBag);
        }
 
        // ログイン成功
        return redirect(AuthUser::getPathAfterLogin());
    }
    ...
}


ユーザコントローラ

ユーザコントローラのバリデーションをメソッド型のインタセプターとして再実装します。ユーザ登録画面の章で作ったユーザコントローラ( UserController )に以下の変更を行います。

ユーザコントローラには、トランザクションの章でコンストラクタを追加しています。
  1. コンストラクタ内で、insert()アクションのインタセプターを登録します。
    $this->intercept('insert', 'UserInterceptor@insert');
  2. 同様に、update()アクションのインタセプターを登録します。
    $this->intercept('update', 'UserInterceptor@update');
  3. insert() と update()メソッド内からバリデーションの呼び出し部分を削除します。

以下に修正後の最終的な UserController.php を示します。

/apricot/app/Controllers

UserController.php
<?php
namespace App\Controllers;
 
use App\Exceptions\ApplicationException;
use App\Foundation\Controller;
use App\Models\User;
use Core\Input;
 
/**
 * ユーザコントローラ
 */
class UserController extends Controller
{
    /**
     * User
     * @var \App\Models\User
     */
    private $user;
 
    /**
     * ユーザコントローラの生成
     */
    public function __construct()
    {
        // モデル
        $this->user = new User();
 
        // トランザクションアクション登録
        $this->transactional('insert','update','delete');
    }
 
    /**
     * ユーザ一覧
     * @return \Core\Foundation\Response
     */
    public function index()
    {
        // 全件検索
        $users = $this->user->findAll();
        return render("user.index", ["users"=>$users]);
    }
 
    /**
     * ユーザ新規登録
     * @return \Core\Foundation\Response
     */
    public function create()
    {
        // 新規作成
        $user = $this->user->create();
        return render("user.create", ["user"=>$user]);
    }
 
    /**
     * ユーザレコード挿入
     * @return \Core\Foundation\Response
     */
    public function insert()
    {
        // バリデーション
        $response = (new Interceptors\UserInterceptor())->insert($this);
        if ($response instanceof \Core\Foundation\Response)
        {
            return $response;
        }
 
        $inputs = Input::all();
 
        try
        {
            // ユーザレコード挿入
            $user = $this->user->insert($inputs);
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.insert'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$user->id}/edit"))->with('msg',__('messages.success.db.insert'));
    }
 
    /**
     * ユーザ編集
     * @return \Core\Foundation\Response
     */
    public function edit(int $id)
    {
        // 主キー検索
        $user = $this->user->findOne($id);
        if ($user!==false)
        {
            return render("user.edit", ["user"=>$user]);
        }
        else
        {
            return redirect(route("users"))->withOldErrors();
        }
    }
 
    /**
     * ユーザレコード更新
     * @param int $id
     * @return \Core\Foundation\Response
     */
    public function update(int $id)
    {
        // バリデーション
        $response = (new Interceptors\UserInterceptor())->update($this, $id);
        if ($response instanceof \Core\Foundation\Response)
        {
            return $response;
        }
 
        $inputs = Input::all();
 
        try
        {
            // レコード更新
            $this->user->update($id, $inputs);
        }
        catch(ApplicationException $e)
        {
            throw $e;
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.update'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$id}/edit"))->with('msg',__('messages.success.db.update'));
    }
 
    /**
     * ユーザレコード削除
     * @param int $id
     * @return \Core\Foundation\Response
     */
    public function delete(int $id)
    {
        try
        {
            // レコード削除
            $this->user->delete($id);
        }
        catch(ApplicationException $e)
        {
            throw $e;
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.delete'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一覧画面にリダイレクト
        return redirect(route("users"))->with('msg',__('messages.success.db.delete'));
    }
}


コメント

test117.26.76.84, 2022/11/24 14:10

https://www.nikewomensshoes.us.com/ https://www.nikeairmaxs-270.us.com/ https://www.nikerunningshoes.us.org/ https://www.nikeshoesoutletstoreonlineshopping.us.com/ https://www.pandoraa.us/ https://www.pandorajewelryshops.us.com/ https://www.nhlshops.ca/ https://www.jordan11concordshoes.us/ https://www.nikeoutletshoes.us.org/ https://www.nikefactory-store.us.com/ https://www.nhljerseysstore.ca/ https://www.nikeblackfridaycybermonday.us.org/ https://www.nikerunningshoesforwomen.us.com/ https://www.jordan35.us/ https://www.jordan5whatthe.us/ https://www.nikesoutletstores.us.com/ https://www.jordan18.us/ https://www.wholesalejordansfactory.us/ https://www.jordans28.us/ https://www.nikeepicreactuptempo.us.org/ https://www.nike-clearance.us.org/ https://www.cheapshoeswholesalefreeshipping.us/ https://www.jordan17.us/ https://www.jordans23.us/ https://www.jordan31.us/ https://www.nikewholesalesuppliers.us.com/ https://www.christianslouboutin.us.org/ https://www.michaeljordan-shoes.us/ https://www.pandorabracelet-clearance.us.com/ https://www.pandorasjewelrycharms.us/ https://www.jerseysstore.ca/ https://www.nikeairmax270s.us.com/ https://www.jordanshoess.us.org/ https://www.officialpandorajewelry.us/ https://www.pandora-jewelry-charms.us/ https://www.nflshoponline.ca/ https://www.nikefree.us.org/ https://www.nikeair-force1.us.org/ https://www.pandoraoutletsjewelry.us.com/ https://www.huaraches.us.org/ https://www.nikeoutletstoreonlines.us.org/ https://www.newnikesneakers.us.org/ https://www.huaracheshoes.us.com/ https://www.charmspandoras.us.com/ https://www.cheapjerseyswholesale.ca/ https://www.airjordans13.us/ https://www.wholesaleshoescheap.us/ https://www.cheapjordansshoessale.us/ https://www.christianlouboutinshoess.us.com/ https://www.cheapjordanshoessuppliers.us.org/ https://www.jordan11s.us.org/ https://www.wholesaleshoessneakers.us/ https://www.nikesoutletstore.us.com/ https://www.jordan20.us/ https://www.nikesneakerss.us.com/ https://www.jordan21.us/ https://www.kidsjordans.us/ https://www.mlbjerseysshop.ca/ https://www.nbastorecanada.ca/ https://www.pandora-jewelrysite.us/ https://www.nikeairjordan.us.org/ https://www.cheapjordanswholesalefreeshipping.us/ https://www.nikecortezshox.us.org/ https://www.nikerosheblazers.us.com/ https://www.nikeoutlet-store.us.org/ https://www.nikeshoesformens.us.com/ https://www.toddlerbabyinfantjordans.us/ https://www.foamposites.us.org/ https://www.jordan19.us/ https://www.wholesaleshoesclothing.us/ https://www.nikejordan1.us.com/ https://www.jordans12.us/ https://www.jordan11lowretro.us/ https://www.nikeairforce1s.us.org/ https://www.officialpandorarings.us/ https://www.ringspandora.us/ https://www.lebronsjamesshoes.us.com/ https://www.nikewholesale.us.org/ https://www.jordans32.us/ https://www.jordan27.us/ https://www.nikesbdunk.us.com/ https://www.jordan6s.us/ https://www.nikerosheblazer.us.org/ https://www.jordan-12.us.org/ https://www.nikefoampositeacghyperdunk.us.com/ https://www.newnikesshoes.us.org/ https://www.airjordanretro.us.org/ https://www.air-maxs.us.com/ https://www.pandorajewelryblackfriday.us.com/ https://www.shoesstores.ca/ https://www.nmdr1.us.com/ https://www.jordan22.us/ https://www.shoeswholesalesuppliers.us/ https://www.jordans13shoes.us/ https://www.wholesaleadidas.us.com/ https://www.airforce1s.us.org/ https://www.newjordans.us.org/ https://www.nikemetcons.us.com/ https://www.jordan26.us/ https://www.airmax-outlet.us.com/ https://www.adidasstoreoutlet.us.com/ https://www.jordans34.us/ https://www.air-max2019.us.org/ https://www.redbottomslouboutinshoes.us.org/ https://www.retro12.us/ https://www.nikeshoesdeals.us.com/ https://www.jordans33.us/ https://www.nikeshops.us.com/ https://www.jordan4.us.org/ https://www.cheapshoeswholesalefromchina.us/ https://www.nikess.us.com/ https://www.pandorajewelryofficialsites.us/ https://www.yeezysboost350v2.us.org/ https://www.jordan1.us.org/ https://www.jordan29.us/ https://www.jordans14.us/ https://www.pandorajewelrycz.us/ https://www.airjordan-retros.us/ https://www.nikeoffwhite.us.org/ https://www.jordan15.us/ https://www.pandorajewelryauthentic.us/ https://www.pandorasbracelets.us/ https://www.nikeairforces.us.com/ https://www.nikezoomshoes.us.com/ https://www.nikeshoessale.us.org/ https://www.nikeairhuaraches.us.com/ https://www.jordan16.us/ https://www.cheapjordansshoeswholesale.us.org/ https://www.nikeshoesstores.us.com/ https://www.airjordan33.us/ https://www.nikes.us.org/ https://www.nikesoutletfactory.us.com/ https://www.cheapadidasshoes.us.org/ https://www.adidasyeezywebsite.us.org/ https://www.diorjordans.us/ https://www.jordan25.us/ https://www.airmax720.us.org/ https://www.nikeair-max95.us.com/ https://www.pandorajewelryoutlets.us.com/ https://www.nikeairmaxs.us.org/ https://www.jordan2s.us/ https://www.nike-outlets.us.com/ https://www.pandora-charmssale.us/ https://www.nikeairforceones.us.org/ https://www.nikecanadashoesshop.ca/ https://www.jewelryspandora.us.com/ https://www.jordan33.us.org/ https://www.jordanswholesale.us.org/ https://www.airmaxs97.us.com/ https://www.charmspandora.us.org/ https://www.jordan30.us/ https://www.wholesalenikeshoesclothing.us.com/ https://www.nikesnew.us.com/ https://www.nikeairzoom.us.com/ https://www.canadashoesoutlet.ca/ https://www.airjordans11retro.us/ https://www.pandorajewelrycharmscanada.ca/ https://www.jordan-aj1.us/ https://www.jordan24.us/ https://www.airmaxs.us.org/

コメントを入力. Wiki文法が有効です:
 
apricot/ext/interceptor.1590407208.txt.gz · 最終更新: 2020/05/25 20:46 by y2sunlight