[CakePHP] バリデーションルールを正規表現で定義する

バリデーションルールには正規表現が書ける。

参考サイト

データのバリデーション(Data Validation) — CakePHP Cookbook 1.3 ドキュメント
http://book.cakephp.org/1.3/ja/The-Manual/Common-Tasks-With-CakePHP/Data-Validation.html

[CakePHP] プレフィックスルーティングを使って管理者ページを作成する

管理者ページを作成したいときに役立つのがプレフィックスルーティング。

たとえば admin 以下を管理者ページとして、通常ページとレイアウトを切り替えたりできる。

1. プレフィックスルーティングを有効にする

デフォルトでは無効になっている。以下の行のコメントを外して有効にする。

2. コントローラにadminのプレフィックスをつけたメソッドを作成する

このメソッドは /admin/products/index のURLで呼び出される。

3. ビューファイルを作成する

メソッド名と同じ名前でビューファイルを作成する。app/Views/Products/admin_index.ctp

4. アクセスに応じてレイアウトを切り替える

まずはadmin用のレイアウトを作る。app/View/Layouts/admin.ctp

アクセスに応じてレイアウトを切り替えるには、adminのプレフィックスが付いたメソッドでレイアウトを指定する。

これは手軽だけど、全てのadminメソッドで指定しないといけないので手間。

基底クラスに以下のように書いておくと簡単で確実。

参考サイト

Routing — CakePHP Cookbook 2.x documentation
http://book.cakephp.org/2.0/en/development/routing.html#prefix-routing

[CakePHP] NetBeansで拡張子ctpをPHPファイルとしてシンタックスハイライトさせるには

拡張子ctpにファイルタイプphp5を関連付けてやれば良い。以下 BetBeans IDE 8.0 での設定方法を覚え書き。

  1. [ツール]-[オプション]メニューを選択。
  2. [オプション]ダイアログで[その他]グループの[ファイル]タブを選択。
  3. [ファイル拡張子]の[新規]ボタンを押下。
    netbeans-ctp-01
  4. [新規ファイル拡張子の入力]ダイアログで[ファイル拡張子]に ctp と入力して[OK]ボタンを押下。
    netbeans-ctp-02
  5. [関連付けられたファイル・タイプ(MIME)]で[text/x-php5]を選択。
    netbeans-ctp-03
  6. [OK]ボタンを押下して[オプション]ダイアログを閉じる。
    netbeans-ctp-04

以上で完了。

[CakePHP] HABTMの更新画面を自力で作ってみる

前回のエントリでは簡単なサンプルを作ってhasAndBelongsToMany(HABTM)の振る舞いを確認した。だけど、フロンエンドはscaffold任せで何もコーディングしていないので、今回は自力でビューやコントローラを定義してサンプルを作ってみる。

コントローラ定義

ビュー定義

HABTMで紐付けされているテーブルからのデータ選択はどうやったらできるのかいろいろ試行錯誤した結果、なんと $this->Form->input(‘Part’) の1行だけで実装できてしまうことが判明。CakePHP恐るべし。

動作

CakePHP-the-rapid-development-php-framework-Products-Mozilla-Firefox_00

CakePHP-the-rapid-development-php-framework-Products-Mozilla-Firefox_01

CakePHP-the-rapid-development-php-framework-Products-Mozilla-Firefox_02

[CakePHP] 簡単なサンプルを作ってHABTMの動きを確かめる

CakePHP初心者ゆえクックブックを読んだだけではどうもしっくりこないので、簡単なサンプルを作ってhasAndBelongsToMany(HABTM)の動きを確かめてみる。

アソシエーション: モデル同士を繋ぐ — CakePHP Cookbook 2.x ドキュメント
http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html

例題は「製品」対「部品」の多対多リレーション

例題として「製品」と「部品」の多対多リレーションを定義してみる。ある「部品」は特定の「製品」にしか使われていないかもしれないし、またある「部品」は複数の「製品」に使われているかもしれない。すなわち、「製品」と「部品」の間には排他関係の無い多対多のリレーションが存在する。

テーブル定義

あくまでサンプルなので、テーブルには最低限のカラムしか持たせていない。

モデル定義

コントローラ定義

とりあえずscaffoldに頼る。

実行

実行すると期待通りの動作が確認できた。

まずは製品一覧を表示。

CakePHP-the-rapid-development-php-framework-Scaffold-Index-Products-Mozilla-Firefox_00

製品を[View]すると、製品に(多対多リレーションで)紐付けされている部品のリストも表示される。

CakePHP-the-rapid-development-php-framework-Scaffold-View-Products-Mozilla-Firefox_00

製品を[Edit]すると、紐付けする部品を複数選択可能なリストボックスが表示される。

CakePHP-the-rapid-development-php-framework-Scaffold-Edit-Products-Mozilla-Firefox_00

Scaffoldを使ったお陰で簡単に実装できた。自力でコントロールを書いて実装するとなると大変そう。

[CakePHP] 多対多のリレーション定義でのHABTMとhasMany throughの使い分け

CakePHPの4つのアソシエーションのうち、hasOne(1対1)、hasMany(1対多)、belongsTo(多対1)の3つに関しては理解が容易。だけど初心者としては、残りの1つ、hasAndBelongsToMany(HABTM)(多対多)のアソシエーションに関しては更なる理解が必要だなと思ったので、少し突っ込んで調べてみる。

HABTMの特徴

まずはクックブックを読んでHABTMの特徴を頭に入れる。

「このアソシエーションは、結合される2つのモデルがある場合に使われます。」
言い換えると、2つのテーブルを結合するために使われるということ。

「hasManyとHABTMの大きな違いはHABTMモデル間のリンクは排他的ではない、ということです。」
レシピと材料のテーブルがある場合、hasManyだと、あるレシピで使われている材料は他のレシピには使えない(排他的)けど、HABTMだと、材料が既にあるレシピで使われていても他のレシピでも使える(排他的ではない)ということ。

アソシエーション: モデル同士を繋ぐ — CakePHP Cookbook 2.x ドキュメント
http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html

HABTMとhasMany throughの使い分け

クックブックによると、多対多のリレーションを定義できるのはHABTMに限らない。

多対多のリレーションを定義するには2つの方法がある。

  • hasAndBelongToMeny (HABTM)
  • hasMany through

その使い分けの基準については、以下のページが参考になる。

“HABTMの中間モデルの利用について” フォーラム – CakePHP Users in Japan
http://cakephp.jp/modules/newbb/viewtopic.php?topic_id=2819&forum=6

上記仮定において話を進めます。A, BはCの中間テーブルを元にしたhabtmな関係ですが、今回のようにCに中間データ以外の情報を載せるときには、$hasAndBelongsToManyを使用すると、用意されているひどく単純な処理から外れるのが難しいか、または細かいデータ取得の制御に向いていません。
これは重い足枷となります。よってhasMany throughという方法をとるのが一般的なプラクティスです。
詳細は http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html#hasmany-through を見てください。

クックブックにも以下の説明がある。

  • HABTMの中間テーブルは付加データを持つことをサポートしていない。
  • なぜなら、hasAndBelongsToManyアソシエーションはデータを一旦削除してから、そのあとでデータを保存するため。
  • そのため、新しいレコードが挿入されるとき、外部キーID以外の追加フィールドのデータが失われてしまう。

ただし、最近のバージョンでは改良されているみたいだけど。

バージョン 2.1 で変更.
unique に keepExisting を指定すれば、追加フィールドのデータを失うことなく保存できます。 unique キーについてはHABTM association arrays を参照してください。

ということで、とりあえず僕の結論としては、多対多のリレーション定義は以下のルールに従うことにする。

  • アソシエーションに付加データが無い場合はHABTM
  • アソシエーションに付加データがある場合はhasMany though

[CakePHP] 自習用に超簡単なサンプルを書いてみた

CakePHPのアーカイブにはサンプルが含まれていないので、自習用に超簡単なサンプルを書いてみた。簡易掲示板的なソフトで、テーブルは利用者(user)と投稿(post)の2つだけ。利用者を投稿に紐付けして、Scaffoldでデータ管理を行いつつ、インデックスページにページネーション付きで投稿を一覧表示する。とっても簡単なソフトだけど、僕のような超初心者が勉強するためのたたき台にはちょうどいいかも。

テーブル作成。

データベース定義

モデル定義

コントローラ定義

ビュー定義

動作画面

cakephp_01

cakephp_02

cakephp_03

[MySQL] テーブル構造を変更するためのSQL文例

普段の作業にはphpMyAdminを使っているので、僕はSQLにはあまり明るくない。だけど、同じスキームで複数のデータベースを運営しているので、スキーム変更を一括して行うためにはSQLを書かなければならない。

というわけで、自分が良く使いそうなSQL文例を覚え書きしておく。構文については参考サイトに大変解りやすく説明されているので参照のこと。

参考サイト

MySQL: 既存テーブルの構造の変更 – ALTER TABLE文、CHANGE COLUMN句
http://www.yukun.info/blog/2008/11/alter-table-add-drop-change-modify.html

[MySQL] utf8_general_ci と utf8_unicode_ci の違い

データベースのコレーション(Collation: 適合順序)について。

これまであまり深く考えずにutf8_general_ciを設定することが多かったけど、書籍やネットで見かけるサンプルにはutf8_unicode_ciを使っているものも少なくない。これらの振る舞いの違いは何なのか、一度しっかり押さえておきたい。

とりあえず公式サイトのマニュアルを探したら記述が見つかった。

MySQL :: MySQL 3.23, 4.0, 4.1 Reference Manual :: 9.1.12.1 Unicode Character Sets
http://dev.mysql.com/doc/refman/4.1/en/charset-unicode-sets.html

For any Unicode character set, operations performed using the xxx_general_ci collation are faster than those for the xxx_unicode_ci collation. For example, comparisons for the utf8_general_ci collation are faster, but slightly less correct, than comparisons for utf8_unicode_ci. The reason for this is that utf8_unicode_ci supports mappings such as expansions; that is, when one character compares as equal to combinations of other characters. For example, in German and some other languages “ß” is equal to “ss”. utf8_unicode_ci also supports contractions and ignorable characters. utf8_general_ci is a legacy collation that does not support expansions, contractions, or ignorable characters. It can make only one-to-one comparisons between characters.

抜粋拙訳

  • xxx_unicode_ciよりもxxx_general_ciのほうが処理が速い。
  • たとえばutf8_general_ciはutf_8_unicode_ciよりも速いけど精度は落ちる。
  • その理由はutf8_unciode_ciは拡張したマッピングをするから (1つの文字が他の文字の組み合わせと等しいか比較する)。

もっと具体的に言ってくれないとわからない・・・

参考サイト

ネットを探すと解りやすく説明したサイトが見つかった。

utf8_general_ci
– 英字の大文字小文字は区別しない。
– 全角半角は区別する。
utf8_unicode_ci
– 英字の大文字小文字は区別しない。
– 全角半角も区別しない。
– さらに濁音、半濁音、ひらがな、カタカナも区別しない。
– 「は」で検索すると「は」「ば」「ぱ」「ハ」「バ」「パ」「ハ」がヒットする。

utf8_general_ciとutf8_unicode_ci – 技術メモ
http://seesaawiki.jp/notepad/d/utf8_general_ci%A4%C8utf8_unicode_ci

問題
select * from member where namae like ‘%サトウ%’;
こんなSQLで、namaeがサトウ、サトウ、さとう、サトウ(一部半角)何でもマッチさせたい!

【MySQL】大文字小文字、全角半角区別しないでマッチする検索をしたい at softelメモhttp://www.softel.co.jp/blogs/tech/archives/1877

[MySQL] ソート後のレコード順位を取得する

特定のレコードが、テーブルをある条件でソートした後に先頭から何番目にあるか、を知るにはどうするか?

そのレコードより前に位置するレコードを数えればよい

たとえば、生徒名簿にテスト得点が記録されているとして、鈴木太郎のテスト順位(得点の高い順)は何番か?

たとえば、商品一覧に発売日が記録されているとして、商品Aは何番目(発売日の古い順)に発売したか?

面倒なのは上に示したように、レコードから順位を逆引きしたい場合だけ。順位からレコードを取得するテーブルの順引きは簡単。普通にテーブルをソートしてLIMITで順位をオフセットとして与えてやれば済む。

やりたいことはできたけど、処理時間に関しては考察が必要かもしれない。

参考サイト

MySQLでソート後の順位を取得する方法を教えて下さい。 例えば、.. – 人力検索はてな
http://q.hatena.ne.jp/1336143424