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
