phalcon3系のコントローラ名にCamelCaseがうまく効かない話

スポンサーリンク

最初に

この変換の問題はphalcon4でほぼ解決しています。

Phalconには以前からControllerのCamelCase記法に問題がありました。

$router->add('/home', ['controller' => 'HomeHome', 'action' => 'index']);

このようなルーティングを書いた場合、HomeHomeControllerのindexActionを呼んでほしいわけですが実際は異なる結果になります。

実際にはHomehomeControllerindexActionを呼ぼうとします。
HomehomeControllerとかないからエラーになるわけですが、macなどのように大文字小文字を区別しないOSの場合、この問題に気づかずに進んでしまうことがあります。
(結果、Linux環境で確認したらあれ動かないぞとなる)

楽な解決案

シンタックスシュガーのほうを利用しましょう。

$router->add('/home', 'HomeHome::index');

なんでシンタックスシュガーと通常の書き方で変わるんだよ!というツッコミはあると思いますが、こうなってるから仕方ない。

そもそもphalconはどうやって呼ぼうとしているのか

実際にクラスを取得するdispatcherをみてみます。

public function getHandlerClass() -> string
{
    var handlerSuffix, handlerName, namespaceName,
        camelizedClass, handlerClass;

    this->_resolveEmptyProperties();

    let handlerSuffix = this->_handlerSuffix,
        handlerName = this->_handlerName,
        namespaceName = this->_namespaceName;

    // We don't camelize the classes if they are in namespaces
    if !memstr(handlerName, "\\") {
        let camelizedClass = camelize(handlerName);
    } else {
        let camelizedClass = handlerName;
    }

    // Create the complete controller class name prepending the namespace
    if namespaceName {
        if ends_with(namespaceName, "\\") {
            let handlerClass = namespaceName . camelizedClass . handlerSuffix;
        } else {
            let handlerClass = namespaceName . "\\" . camelizedClass . handlerSuffix;
        }
    } else {
        let handlerClass = camelizedClass . handlerSuffix;
    }

    return handlerClass;
}

camelize関数はZephier側の関数です。phalconからはPhalcon\Text::camelizeでも呼び出せます。

Camelizeの動作を見よう

$names = [
    'Sample',
    'SampleSample',
    'sample-sample',
    'sample_sample',
];

foreach($names as $name) {
    echo 'text: '. $name. ', camelized: '. \Phalcon\Text::camelize($name). "<br>";
}

結果は・・・?

text: Sample, camelized: Sample
text: SampleSample, camelized: Samplesample
text: sample-sample, camelized: SampleSample
text: sample_sample, camelized: SampleSample

このようになりました。
問題が起きそうなのはSampleSampleの場合にSamplesampleに変換されてしまっている点です。

なぜシンタックスシュガーなら大丈夫なのか

ソースを見てみるとわかりますが、シンタックスシュガーのほうだけuncamelize関数が呼び出されています。

実際にコードはソースの方から確認してください。
3.4.x/phalcon/mvc/router/route.zep#L347-L429

シンタックスシュガーではなくarrayで渡した場合はuncamelize関数が呼ばれずに通ってしまうので、実際のdispatchの際にcamelizeの変換が失敗してSamplesampleのほうになるわけです。

コメント

タイトルとURLをコピーしました