LoginSignup
13
12

More than 5 years have passed since last update.

Phalcon のルーティングについてメモ

Posted at

ドキュメントとコードリーディングだけであまり動作確認してないので事実と異なるかもしれない.

デフォルトルーティング

DI に何も設定しない場合, DI で Phalcon\Mvc\Router が設定されたものをつかう.
( Router のコンストラクタで true を指定する)router.c#L238
Routerのコンストラクタに true が指定された場合には Route が二つ登録されるようになっており下記二つとなっている.

  • /:controller/:action
  • /:controller/:action/:params

モジュールを使っている場合( config/modules.php などで registerModules() をしている場合)はおそらくデフォルトモジュールが設定されていないのでいろいろ方法はあると思うが下記のように対応するのが簡単だと思う.

  • 設定するモジュールが一つの場合は Router#setDefaultModule() して使用するモジュールを固定する
  • 下記のように URI 自体にモジュールを必要とする設定を追加する.ちなみに第二引き数の数字は URI の正規表現のグループで一致したグループ番号.ルーティングの定義
$router->add('/:module/:controller/:action', [
    'module' => 1,                            
    'controller' => 2,                        
    'action' => 3,                            
]); 

ルーティング設定の追加方法

もう上で書いてしまったけど簡単には Router#add() を使う.また Phalcon\Mvc\Router\Group#add() でグループ毎に設定してから Router#mount() でグループごと一気に追加する方法などもあるはず.

add()Phalcon\Mvc\Router\Route を返すので後述する beforeMatch()convert() などを使うメソッドチェーンなどが使える.

実行タイミング

Router#handle() で Route が一致するかの処理をするときの動きの擬似コード.

(Application 内)
application:boot
  (Router 内)
  remove_extra_shashes が設定されていれば除く
  foreach ルートのリスト
    HTTP メソッドのチェック  
    Hostname のチェック
    パスが一致するかのチェック
    beforeMatch() 
    converter() 
  Route がなければ notFound を設定
application:beforeStartModule
ここで registerAutoloaders() や registerServices() が呼ばれる
application:afterStartModule
もろもろあって Dispatcher#dispatch()

モジュールの読み込みが Router の動作後なのでおそらくモジュール単位でのルーティング設定はモジュール単位での動作に移った後にはできなさそうな雰囲気.
モジュールごとに定義したい場合は Phalcon\Mvc\Router\Group を使ってそれぞれまとめておき,それをプロジェクト全体のところで呼び出すような形で実装するのがよい?

beforeMatch について

Palcon\Mvc\Router#add() の返り値が Phalcon\Mvc\Router\Route オブジェクトになるわけだが,これに beforeMatch() でコールバックを指定すると URI によるマッチだけでなくほかにもいろいろな条件でマッチさせられるらしい.

また, Phalcon\Mvc\Router\Group にも beforeMatch() は設定できるが,これはそのグループに登録されている全てのルートに対してそれぞれ beforeMatch() が設定されていることと同じと考えてよさそう.ただし Group 側に記述している場合はルート個々に設定する beforeMatch()Router#mount() の時点でおそらく上書きされる. router.c#L1187

マッチング時のコールバックには第三引き数の存在は書かれていないが下記のようにコールバックを設定できる様子. Phalcon\Mvc\RouterPhalcon\DI\InjectionAwareInterface を実装しているため URI によるマッチだけでなく request などを取ってきて GET パラメータによるルーティングなども可能の様子.

$uri は現在チェック中の URI で $routebeforeMatch() が設定されるその Route オブジェクトで $router はその Route が設定されてる Router オブジェクト.router.c#L769

/**
 * Registering a router
 */
$di['router'] = function () use ($di) {

    $router = new Router(true);

    $router->add('/admin/index', array(
        'module' => 'backend',
        'controller' => 'admin',
        'action' => 'index'
    ))->beforeMatch(function ($uri, $route, $router) {
        // なんか処理する(例えば is_match パラメータが true のときだけとか)
        $isMatch = $router->getDI()->get('request')->get('is_match', null, 'false');
        return $isMatch === 'true';
    });

beforeMatch() ではマッチの結果として true/false しか返せ無さそうだし上記の「実行タイミング」を見てもらえればわかるが Dispacher の処理の前なのでここで ACL 噛ませて forward()redirect() は筋が悪そうな気がする.(実際には動きそう)

convert について

ルーティングパラメータの変換 に書いてある.第二引き数で指定したキーの名前に対して変換処理などを行うことができる.これは第二引き数に指定したものがコンバート対象となるだけな様子なので,例えば module をコンバート対象にした場合第二引き数に指定されていれば convert が起動するし指定せずに setDefaultModule() で設定されたものが選択された場合は convert は起動しない.またワイルドカードなどで指定できるわけではないので一気に変換等はできなさそう.

ここを使えば例えば symfony1.4 の sfDoctrineRoute のようなものが実現できる気がする.

参考文献

ルーティング — Phalcon 1.3.1 documentation

http://docs.phalconphp.com/ja/latest/reference/routing.html

動作とかは大抵ソース見てた

phalcon/cphalcon

https://github.com/phalcon/cphalcon

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12