(レガシー改善に関しては文章が長くなるのでいつもと違って、〜だ、〜である口調で書きます。)
bake
CakePHPははじめてなのでところどころハマったが基本的なCRUDは出来た。というかbakeで殆ど生成されるのだが。CakePHP1.3のbakeはデフォルトでページングとカラム毎のソート機能が入っている。
しかし、「データがたくさんある時ページ分けして欲しい」というタスクが幾つかRedmineにあったし、ソースをみても既存の部分はbakeを使った形跡は無い。俺が初bakeか。
i18n
bakeにともなってi18nも使った(bakeで生成されるソースにはi18n前提だし)。現状、poファイルが無い。俺が初i18nか。
% cake bake i18n extract
こんな感じでソースからpotファイルを生成する。app/vendorsにPHPExcelというプラグインがあって、それの処理に死ぬほどメモリと時間がかかる。app/vendorsを除外する方法は無いものか。
ソースを見ると上記にpotを既存poにマージする機能があるっぽいが、やり方がわからなかったのでとりあえず初回はmsginitした。
macではデフォルトでgettextが入っているが、% brew link gettext
しないとパスが通らないところが若干罠だった。
既存ソースに何故か
__('')
msgid ""
msgstr ""
みたいな空文字を翻訳している箇所が5箇所ぐらいあってmsginitが出来ない。どういう理由でこういうコードがあるのか不明だが、とりあえず消した。
validateエラーメッセージのi18n
modelでvalidateエラーメッセージをi18nしようとしたがsyntax errorが出る。何故?と思ったがphpではrubyと違ってインスタンス変数の定義は定義であって評価じゃない。初期値は書けるが関数の実行はできない。
要は下記はOKだが、
class User {
public $name = 'komagata';
}
下記は駄目ということだ。
class User {
public $length = strlen('komagata');
}
rubyを始めた頃はattr_accessorを見て「クラス定義内も普通に式が評価されるのか、凄いなー!」なんて思ったはずだが、それが当たり前になりすぎてそうじゃない言語が沢山あることを忘れていた…。(array()はOKなのでarrayは関数じゃなくてリテラルなのかな?)
class RegularOrder extends AppModel {
public $validate = array(
'interval' => array(
array(
'rule' => 'numeric',
'message' => __('must be number', true)
)
)
);
}
何故これがsyntax errorなんだー!・・・みたいな。
FormHelperへの疑問
CakePHP1.3のbakeが生成するコードはFormHelperを使っている。railsのscaffoldと比較して疑問点がいくつかあった。
bakeが生成するviewのコードは下記のようになっている。(分かりやすく色々端折ってます)
<?= $form->input('interval') ?>
でも実際は下記のようにモデル名も書かないと動かない。
<?= $form->input('RegularOrder.interval') ?>
formはmodelを知ってるんだから自動で付けてくれてもいい気がするが、PHP4もサポートするせいでモデル名がわからないのかもしれない。それだったらPHP4サポートを切ったCakePHP2系だったら改善されてるのかも。
レガシー改善パターン "Partial Proxy Pattern"
既存のレガシーの中にリーダブルコードを書いていく為のショーモナイテクニックに勝手に名前を付けていきたいと思います。
既存のテンプレートの中の共通化したい部分はこんな感じで書かれてる。
<body> <?php include('../views/head-menu.ctp');?> <h2 class="title_1">注文入力</h2>
ファイル名と置き場所が分かり辛い。include(!)ではなく、CakePHPのElementを使って欲しい。かといって既存部分をいじったら他で何が起こるか分かったもんじゃない。怖い。
app/views/elements/admin/menu.ctp:
<?= $this->element('../head-menu') ?>
そこでこんな感じで本来置きたい場所に一旦既存のテンプレを読み込むだけのProxy的なElementを作る。そうすると、新しく実装するviewはリーダブルでいられる。
app/views/layouts/admin.ctp:
<?= $html->doctype('xhtml-trans') ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<?= $html->charset() ?>
<title><?= $title_for_layout ?></title>
<?= $html->css('admin') ?>
<?= $scripts_for_layout ?>
</head>
<body>
<?= $this->element('admin/menu') ?>
<div id="content">
<?= $content_for_layout ?>
</div>
</body>
</html>
レガシー改善パターン "CSS Proxy Pattern"
同じく、既存のCSS(style.css)はゴチャゴチャなので新しく作るview用のCSSはリーダブルにしたい。そこでこう!
app/webroot/css/admin.css:
@import url('style.css'); /* ここに新しいviewで必要なcssを書いてく */
レガシーCSSとリーダブルCSSを切り分けることが出来る。
絶賛募集中
僕と一緒にレガシー改善をしてくださるプログラマーを募集しています。常駐・受託、開発会社・フリーランス、派遣・バイト問いませんので是非お願いします。というか助けて欲しい・・・。詳しくはこちら。
https://github.com/ichikaway/cakeplus
レガシー改善パターン "Partial Proxy Pattern" > 別の切り口としてPartialHelperというのがあったりします。2.x系からはViewクラスになっていますが、1.3系ではHelperとして簡単に利用できます。
https://github.com/kozo/Partial
両方とも、自分の案件ではほぼ必須で利用していますので、お時間があるときに見てみてください。
cakeplus導入しました。メチャクチャ便利ですね。ありがとうございます!