zendで作られたWEBサイトのスマートフォン用を作ることになったのですが、zendでシステム化されているところは外注で作られた所らしく、
しかも暗号化されており、ソースコードも契約上もらえないという状況。
仕方がないので、既存の仕組みはそのままにしてCakePHPでスマートフォン版を作成する事にしました。
サーバー環境からPHP5.1なのでCakePHP1.3を使用しました。
目次
- 基本
- その他
基本
モデル
テーブルはCakePHPの命名規則には当てはまってないので、キーとテーブル名を指定して作成します。
class UserTbl extends AppModel { var $name = 'UserTbl'; function __construct () { $id = array( 'id' => false, 'table' => 'user_tbl', ); parent::__construct($id); $this->primaryKey = 'user_id'; } }
また、複合キーを使ったテーブルもあるのでそこは諦めてSQL直書きで対応する事にしました。
class UserImageTbl extends AppModel { var $name = 'UserImageTbl'; var $useTable = false; // 複合キーのため function findById($user_id, $image_id) { $sql = <<<SQL SELECT * FROM user_image_tbl AS UserImageTbl WHERE user_image_user_id = ? AND user_image_id = ? SQL; $userImage = $this->query($sql, array($user_id, $image_id)); if (count($userImage) === 1) { return $userImage[0]; } return $userImage; } }
コントローラ
viewに渡すために$this->dataにモデルからとった値を設定します。
$profile = $this->UserProfileTbl->read(null, $id); $this->data['ProfileBasic'] = $profile['UserProfileTbl'];
フォーム用モデル(バリデーションまで行う)とデータ登録用モデル(SQL発行)を別々に作成し、一つのフォームに一つのフォーム用モデル、
一つのテーブルに一つのデータ登録用モデル、という風に決めて作成しました。
取得後のキー名(テーブル名のキャメルケース)とフォームのキー名が違うので、フォームに渡す際や更新する際は都度設定する必要が有りましたが、その方がわかりやすいと思ったのでその様にしました。
ビュー
ヘルパーにモデル名とurlを指定して作成しました。
<?php echo $this->Form->create('Contact', array('url' => '/contact/', 'name' => 'contact-form'));?> <?php echo $this->Form->text('Contact.mail', array('class' => 'w0')); ?> <?php echo $this->Form->error('Contact.mail');?>
その他
ページング
複合キーの場合は、paginateも使用できないので自分で仕組みを作成する必要がありました。
ページングで必要な情報は、件数と表示するページの情報が最低限必要です。
件数はapp_model.phpに件数をFOUND_ROWS()を使って件数を返す関数を用意しました。
class AppModel extends Model { function found_rows () { $rows = $this->query('SELECT FOUND_ROWS();', false); if (!empty($rows)) { return $rows[0][0]['FOUND_ROWS()']; } return 0; } }
あとは、検索用のSQLでSQL_CALC_FOUND_ROWSを指定すれば全件数は取得できます。
$sql = <<<SQL SELECT SQL_CALC_FOUND_ROWS * FROM {$tbl} WHERE {$where} ORDER BY {$order} DESC LIMIT ? OFFSET ? SQL; $users = $this->query($sql, $param); $rows = $this->found_rows(); $result = array(); foreach ($users as $user) { $i = key(array_slice($user, 0, 1)); $result[]['UserTbl'] = $user[$i]; } return array($result, $rows); }
ページングのリンクは共通処理を行うコンポーネントを作成してリンクを生成するようにしました。
/*---------------------------------------------------------- 検索結果共通処理(ページング) ----------------------------------------------------------*/ function _setPagingLink ($query, $members, $all, $page, $type) { $this->set('query', $query); $this->set('members', $members); $this->set('all', $all); $maxpage = ceil($all / 10); // ページングリンク if ($page != 1) { $this->set('prev', '<a href="/s/search/'.$type.'/?page='.($page - 1).'&'.http_build_query($query).'">前へ</a>'."\n"); } $start = ($page - 1) * 10; $end = $start + count($members); $this->set('counter', sprintf('%d件中/%d~%d件表示', $all, $start + 1, $end)); if ($page != $maxpage && $maxpage != 0) { $this->set('next', '<a href="/s/search/'.$type.'/?page='.($page + 1).'&'.http_build_query($query).'">次へ</a>'."\n"); } // セッション登録(検索結果戻る対策) $this->Session->delete('Search.back'); $this->Session->write('Search.back.url', '/s/search/'.$type.'/?page='.($page).'&'.http_build_query($query)); $this->Session->write('Search.back.pagename', '検索結果一覧'); }
初めて使ったコンポーネント・プラグイン
SSL Component https://github.com/plank/secured
→メソッド単位でSSLの切り替えができるのでめっちゃ便利でした。(ちょっとだけパフォーマンス悪くなる!?)
Yalog: Yet Another Logger for CakePHP https://github.com/k1LoW/yalog
→Log4phpが簡単に使える様になります。オリジナルのログローテーションクラスもLog4phpには引けをとらないと思いました。
参考になったサイト
AutoLoginComponentを参考に自動ログイン実装しました。 http://d.hatena.ne.jp/sanojimaru/20091210/1260447577
Auth Componentを使用したかったのですが、ユーザー認証がAPI経由で行う仕様だったので非常に参考になりました。http://weble.org/2011/04/05/cakephp-oauth