CakePHP
CakePHP 管理画面を作成する方法
2CakePHP で管理画面を作成する方法です。
管理画面も CakePHP では簡単に作成することができます。
設定
/app/config/core.php の下記のコメントアウトをはずします。
define('CAKE_ADMIN', 'admin');
これで http://www.example.com/admin/controller/action という URL でアクセスできるようになります。
CAKE_ADMIN の値を変更すれば URL の /admin/ の値が変わります。
コントローラ
管理画面で使用するコントローラに管理画面用のアクションを追加します。
管理画面用のアクション名は admin_index のように admin_ が付きます。
この ‘admin’ の部分も CAKE_ADMIN によって変わります。
ビュー
管理画面用のアクションで表示するデフォルトのビューはアクション名と同じです。admin_index.thtml のように admin_ を付けます。
レイアウト
ユーザサイドの画面レイアウトと管理画面はレイアウトが違うことが多いかと思います。管理画面用のレイアウトを admin.thtml のように views/layouts/ に作成します。
管理画面へのアクセス時の共通処理
管理画面のアクセス時の共通処理として、アクセス制限をしたり、画面レイアウトの変更などがあります。
個別にアクションに追加してもいいのですが漏れなどがあるとまずいのでコントローラの beforeFilter メソッドを使用するといいかと思います。
管理画面で使用するコントローラ全てに共通して処理させるために、 /app/app_controller.php の beforeFilter に処理を追加します。
http://www.example.com/admin/contoller/action にアクセスすると
$this->params['admin'] = 'admin'
がセットされます。管理者用URL かどうかにはこれを使用します。また、’admin’ の値は CAKE_ADMIN で指定した値になります。たとえば CAKE_ADMIN を hoge にすると
$this->params['hoge'] = 'hoge'
になります。
if (defined('CAKE_ADMIN') && !empty($this->params[CAKE_ADMIN])) { // 管理者用のレイアウトを指定 $this->layout = "admin"; // 管理者用ログインチェックなどを行う }
CakePHP 静的なページの作成方法
2CakePHP で静的なページを作成する方法です。
正確には CakePHP が出力するページなので静的ではなく動的なのですが、ページを簡単に作成することができます。
- 出力するページをテンプレートとして /views/pages/ ディレクトリ以下に作成します。
- 作成したテンプレートが hoge.thtml だとすると http://exmaple.com/pages/hoge でアクセスできます。
これだけで簡単にページを追加することができます。
コンテンツは静的なものですが、ビューなので例えばログイン状態によって表示を変更したりなどできますね。
なぜ /pages/hoge でアクセスできるかというと /app/config/routes.php で
$Route->connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
と定義されているからです。
pages_controller.php は /cake/libs/controller/pages_controller.php にあります。
上のルーティングで pages コントローラへのアクセスは全て pages コントローラの display アクションに渡されます。
また、/views/pages/hoge/foo/fuga.thtml というテンプレートを作成すると
http://example.com/pages/hoge/foo/fuga という URL でアクセスすることができます。
ちなみにページタイトルはテンプレートの名前が title タグに入れられます。
タイトルを指定する場合は
<? $this->pageTitle = 'ここにタイトルを指定する'; ?>
とビューでタイトルを指定します。
参考サイト:21 things I learned about CakePHP – Avatar Financial Group
CakePHP select タグの選択していないときの状態を指定する
0Cute CakePHP Trick of the Day – GenerateList Empty Slot In List | Web Development 2.0: Web Design, CakePHP, Javascript
で select タグの選択していないときの状態の値を指定する方法が書かれていますが、この方法は間違っています。
元のエントリのコメントでも指摘されていますが、ヘルパーのメソッドの使い方が違います。コードを実際に書いて検証してみれば、動かないのがすぐに分かります。
元の紹介されている方法はそもそも PHP の文法的におかしいのでそこは適当に修正して紹介します。(変数名に $ がなかったり、generateList() を出力をどこにも保存していないかったりします。)
コントローラで下記のように generateList でリストを取得して
$state_id = $this->State->generateList();
ビューで
echo $form->input($state_id, array('empty' => '--'));
と紹介されています。
CakePHP1.1 の Formヘルパーには input メソッドがないので CakePHP 1.2 でのやり方だと思いますが、実際に Form ヘルパーの input メソッドは
function input($fieldName, $options = array())
と定義されています。上記のように書くと
で、実際にはどう書けばいいかというと
echo $form->input('Model/Field', array('empty'=>'---', 'type'=>'select', 'options'=>$state_list));
または、
echo $form->select('Model/Field', $state_list, null, null, array('empty'=>'---'));
と書けば select タグの先頭に
<option value=''>---</option>
と入ります。
CakePHP1.1 では 「CakePHP HTMLヘルパーで select タグを表示する」のエントリで書いたように結構面倒だったので新しい Form ヘルパーは使いやすいですね。
CakePHP Model::generateList メソッドの {n}
2CakePHP で select タグを生成する際に generateList メソッドをよく使います。
ちなみに使い方は下記の通りです。
$this->Model->generateList($conditions, $order,$limit, $keyPath, $valuePath);
$coditions :検索条件
$order :ソートの指定
$limit :取り出す数
$keyPath :配列のキーにするフィールド
$valuePath :配列の値にするフィールド
この $keyPath と $valuePath の指定方法が曲者で
{n}.Model.field
のようにモデル名の前に「{n}.」をつけなくては正しくデータを取得できません。
この「{n}」というのがなんなのかが気になり調べてみました。
詳しくは下記リンク先を参照していただくと分かります。
{n} ? – Cake PHP | Google グループ
以下実際に CakePHP のコードを調べてみたことをまとめます。
- generateList メソッドでは検索条件などによって findAll する
- findAll したデータから Set::extract メソッドを使用して該当するフィールドデータのみ抜き出す
- Set::extract メソッドは配列以外にもオブジェクトからも extract できるように設計されている
- 配列の場合はモデル名の前に「{n}」があるかどうかで判定している
という感じのようです。
ちなみに Set クラスは /cake/libs/set.php で定義されていて、コメントを見ると配列用のライブラリクラスのようです。
また、generateList で $keyPath, $valuePath を指定しなかった場合は下記のようになるようです。
- $keyPath には モデルで指定した $primaryKey を使用
- $primaryKey の指定がなければ ‘id’ フィールドを使用
- $valuePath には モデルで指定した $displayField を使用
- $displayField の指定がなければ ‘title’ フィールドが存在すれば ‘title’ フィールドを使用
- ‘title’ フィールドが存在しなければ ‘name’ フィールドを使用
- ‘title’ フィールドも ‘name’ フィールドも存在しなければ ‘id’ フィールドを使用
フィールド名の付け方も重要ですね。
CakePHP ファイルアップロードするコンポーネント
2CakePHP でファイルアップロードを簡単に行うコンポーネントです。
ReverseFolds – CakePHP File Uploads
データベースにファイル名、MIMEタイプ、サイズなどを記録し、ファイルは指定したディレクトリへアップロードするようになっています。
ビューにファイルアップロード用のタグを設置
<input type='file' name='userfile[]'/>
複数配置したいときは
<input type='file' name='userfile[]'/> <input type='file' name='userfile[]'/>
コントローラに使用するコンポーネントを追加
var $components = array('FileHandler');
アップロード処理
$this->FileHandler->setDebugLevel(1); $this->FileHandler->setRequired(0); $this->FileHandler->setHandlerType('db'); $this->FileHandler->setDbModel('FileUpload'); $uploadDir = 'path/to'; // アップロードするディレクトリを指定 if ($this->FileHandler->upload('userfile', $uploadDir)) { echo 'アップロード成功'; } else { echo 'アップロード失敗'; }
実際の処理などはリンク先からダウンロードしたファイルにコンポーネントの他に、ビュー、コントローラ、モデル、SQL と必要なものは入っているのでソースを見てみるとすぐに分かると思います。
アップロードされるファイルは $uploadDir で指定したディレクトリ内にユニークなディレクトリ名を作成してそのディレクトリ内に元のファイル名で保存してくれます。
その他のメソッド
アップロードできるファイルタイプを限定するメソッド
void setAllowedMime( array $mimeTypes )
ファイルの最大容量を設定するメソッド
void setMaxSize( int $size )
などもあります。
CakePHP Pagination まとめ
2CakePHP の Pagination に関してまとめてみました。
コントローラでコンポーネント、ヘルパーに Pagination を指定
// 使用コンポーネント名 var $components = array('Pagination'); // 使用ヘルパー名 var $helpers = array('Pagination');
コントローラの一覧表示するアクションでの一覧表示取得方法
$this->Pagination->modelClass = 'Model'; // 使用するモデル $this->Pagination->sortBy = 'created'; // デフォルトのソートするフィールド名 $this->Pagination->direction = 'DESC'; // デフォルトの昇順、降順を指定 $this->Pagination->show = 10; // 1ページに表示する件数 $conditions = array(); // 検索条件 list($order,$limit,$page) = $this->Pagination->init($conditions); $lists = $this->Model->findAll($conditions, $fields, $order, $limit, $page, $recursive);
ビューでのヘルパー使用準備
ビューで Pagination ヘルパーを使用できるようにする
< ?php $pagination->setPaging($paging); ?>
ビューでの総件数と表示している件数の表示
< ?php echo $pagination->result('検索結果:', '/', '?'); ?>件
上記のように指定すると「検索結果:1?10/5253件」と表示されます。
ソートするフィールドを変更するリンクを表示する
< ?php echo $pagination->sortBy('field_name', 'フィールド名', 'ModelName'); ?>
field_name にソートするフィールド名、
フィールド名にリンクに表示する名前、
ModelName にはフィールド名が属するモデル名
を指定します。
モデル名は $this->Pagination->modelClass と同じ場合には省略可能です。
また、sortBy メソッドは
veiws/heplers/pagination.php
function sortBy ($value, $title=NULL, $Model=NULL,$escapeTitle=true,$upText=' ^',$downText=' v')
のように定義されています。見て分かるとおり第5、6引数を指定することにより、ソートしたときのリンクのフィールド名につく「^」「v」の文字を変更することができます。
select タグによってソートを指定したいときは sortBySelect メソッドがあります。
function sortBySelect($sortFields, $t='Sort By: ',$upText=' ^',$downText=' v')
CakePHP 携帯でセションを有効にする
2CakePHP で携帯サイトの開発をしています。
ドコモなどはクッキーが使用できないのでセションID を URL で引き継がないといけないのですが、PC サイトではクッキーでセションID を保持したいところです。
携帯サイトと PC サイトが共存しているときの携帯用のビューを表示させる方法は下記が参考になります。
CakePHP 携帯用ビューを表示する | Shin x blog
また、携帯でのアクセス時にクッキーを使用せずにセション を保持するのは下記が参考になります。
Docomoとセッション フォーラム – CakePHP Users in Japan
私は上記の方法に
ini_set('session.use_trans_sid', 1);
を入れて使用しています。
全てのリンク、フォームにセションID が付加されるので便利です。
ただリダイレクトするときだけ、
$this->redirect('/controller/action/'.session_name().'='.session_id());
のようにセションIDを入れました。
あとビューを書くときに覚えておくとよいのが、ini_set(‘session.use_trans_sid’, 1); を指定したときにリンクを http:// から始まる URL を書くとセションID は当然ですが付加されません。相対パス、絶対パスなどの自サイト内へのリンクのみセションIDが付加されます。
自サイト内のリンクに http:// から書くとセションID が付かないのではまらないように。
CakePHP findAll で INNER JOIN する方法
1開発中の CakePHP の案件でどうしても INNER JOIN する必要があり、かといって SQL を直接書くのは他のコンポーネントとの兼ね合いでできるだけ避けたい(というより無理)な状況だったので、絶対何か方法があるだろうと思いソースを調べたのでメモしておきます。
/cake/libs/model/model_php5.php の findAll メソッドに
$queryData = array('conditions' => $conditions, 'fields' => $fields, 'joins' => array(), 'limit' => $limit, 'offset' => $offset, 'order' => $order );
というのがあり、’joins’ に 空の配列を入れている。
この ‘joins’ の使い方を調べたら、
array( "type" => "INNER", "alias" => "", "table" => INNER JOIN するテーブル, "conditions" => INNER JOIN の ONに指定する条件, );
という配列を入れると INNER JOIN してくれるようです。
ただ、findAll の中で joins に空配列を入れているので、findAll を実行するときのパラメータに joins を指定しても無視されてしまう。
そこで、モデルの beforeFind メソッドを使用することにした。このメソッドは findAll の実行する前に呼ばれるメソッドです。
findAll を実行するモデルに次の beforeFind を定義
function beforeFind(&$queryData) { $queryData["joins"][] = array( "type" => "INNER", "alias" => "", "table" => "`model_name`", "conditions" => array("model_name.field=model_name2.field2"), ); return true; }
これで実行された SQL を確認すれば INNER JOIN されれいます。
CakePHP 保存したデータをすぐに find したい場合キャッシュを OFF にする
1CakePHP で保存したデータをすぐにfind するとキャッシュが効いている為に保存したばかりのデータを取得することができません。
その場合はキャッシュを OFF にすることにより新しいデータを取得することができます。
$this->Model->cacheQueries = false;
CakePHP findAll の条件に NOT IN 演算子を使う
0前回の投稿の「CakePHP findAll の条件に IN 演算子を使う」のつづきで、NOT IN 演算子を使用するときに少し調べたのでメモしておきます。
$this->model->findAll('field NOT IN (1, 2, 3)');
または、
$this->model->findAll(array('NOT' => array('field' => array(1, 2, 3))));
で出来ました。