ラベル cakePHP の投稿を表示しています。 すべての投稿を表示
ラベル cakePHP の投稿を表示しています。 すべての投稿を表示

2016年3月31日木曜日

【CakePHP】余計なヴァリデーションはしない(saveがなぜか失敗する場合)

CakePHPで開発中のシステムで、少し前まで問題なく動いていた新規データ登録フォームからのデータ登録ができなくなってしまっていた。

原因を検索したところ、以下のページがヒット:
cakePHPでsaveできない時

Model->save()の際にヴァリデーションが自動で行われる。
該当のモデルクラスのヴァリデーション設定に問題がないかどうかをチェック。

そういえば、複数のテーブルで同じ名前のフィールドがあったので、自作のModelクラスが共通で継承する抽象クラスにそのフィールド名のヴァリデーション設定を追加していた。
required を true にし、allowEmpty を false にしていたので、Model->save()の際のPOST送信値に該当の名前のデータがない場合ヴァリデーションエラーになってしまう。これが原因だった。新規登録が出来なくなっていた該当テーブルには継承した抽象クラスで設定したヴァリデーションに該当するフィールドがなかった。

教訓:ヴァリデーション設定は横着せずに。

2015年8月13日木曜日

【cakePHP】ヴァリデーション時、UPDATEの場合であればプライマリキーのセットを忘れずに

cakePHPではデータベースを扱うMODELクラスにバリデーションの設定を書いておくことで入力内容の妥当性のチェックが容易にできる。

今回、バリデーションでしくじったケースがあったのでメモ。

モデルクラスによるバリデーションが行われるタイミングは主にふたつ。
■保存系:例・モデルクラスのインスタンスの save() が実行されるとき。
■明示的ヴァリデート系:例・モデルクラスのインスタンスの validates() を実行したとき。

save()の挙動は、新規レコードの追加(INSERT)と既存レコードの更新(UPDATE)とを兼ねるので、今書いている処理がINSERTなのかUPDATEなのかをしっかり意識して制御する必要がある。
主要な区別は、
■INSERT:モデルに渡される配列が、そのテーブルのプライマリキーの値を含んでいない。
■UPDATE:モデルに渡される配列が、そのテーブルのプライマリキーの値を含んでいる。


今回やってしまったエラーは以下のケース。
あるテーブルについて、レコードを新規追加する処理を追加した。
その際、そのテーブルを扱うモデルクラスについて、ヴァリデーションルールを追加した。
そのヴァリデーションルールは「isUnique」。そのテーブル内で値が重複していたらエラー。

そのモデルでのヴァリデーションを使用している箇所は、今回作った新規追加だけではなく、既存の処理にもあった。
過去に作った既存の処理においては、UPDATEにおけるヴァリデーションであるのにも関わらず、プライマリキーを配列に含めないでチェックさせていた。これまではそれで問題なかった。
しかし、「isUnique」のヴァリデーションルールは、INSERT時とUPDATE時とで挙動が違うため、既存の処理側でエラーを起こしてしまった(エラーとしたくないケースの入力においてもエラーになってしまった)。


今回の教訓:
ヴァリデーションが必要な場合、INSERTかUPDATEかを意識して、UPDATEであればプライマリキーを忘れずにモデルに渡すこと。

【cakePHP】半角・全角・カタカナ・ひらがななどの混じった文字列でのあいまい検索

cakePHPで、データベースからの検索をする場合。
キーワード入力欄などで、いい加減な入力にも柔軟に対応したいという要望がある場合。

MySQLの機能をうまく使うと、以下の曖昧入力での検索が簡単にできるようになる。
■アルファベットが、半角/全角、大文字/小文字にかかわらず、検索可能
■数字が、半角/全角にかかわらず、検索可能
■平仮名、カタカナ、半角カナにかかわらず、検索可能


参考URL:
http://tutty.info/527
http://qiita.com/kazu56/items/108075fcb5e98c0d637a
https://www.softel.co.jp/blogs/tech/archives/1877


要点:
■「collate utf8_unicode_ci like」を使う
    select * from item where item_name collate utf8_unicode_ci like '%りんご%';

■cakePHPの場合、テーブル名やコラム名にバッククオーテーションがつくので、カッコで囲む。
    $this->find('all',[
        'conditions'=>['(name) collate utf8_unicode_ci like'=>'%hoge%'
    ]);

■データベースがUTF8でない場合はもう一段階変換を挟む。「convert(コラム名 using utf8)」という書式。

    select * from member where convert(namae using utf8) collate utf8_unicode_ci like '%サトウ%';



現在の案件だと、データベースの文字コードがUTF8ではなかったので、以下のような感じになった。

コントローラーにおける記述:
---------------------------------------------------
//検索結果
$items = array();
if(empty($this->request->data) == false){
    //検索条件のセット
    $condition = array();

    //会員名あいまい検索
    $condition['and'][] = array('(convert(Member.name using utf8)) collate utf8_unicode_ci like'=>'%'.$this->request->data['Member']['name'].'%');

    //~ここにさらに検索条件を追加する処理~

    //ページネイターを使っての検索実行
    $items = $this->paginate('Member', $condition);
}//if
//検索結果をセット
$this->set("items", $items);
---------------------------------------------------


【cakePHP】Paginator を使っての検索結果並び替え

cakePHPで作るシステムはたいていデータベースと連動する。

基本的な構造として、ひとつのDBテーブルあたり、以下の機能がワンセットで作られる。
■一覧:検索フォームと検索結果
■新規登録
■詳細&編集
■削除


検索結果ページにおいて、検索結果にページネーション機能をもたせたりいろいろな条件での並び替えをさせたかったりする。

cakePHPには「Paginator」という便利な機能があるので、一覧画面のためのDB検索にはこの機能を使う。
今回、ページネイターを使ってのレコードの並び替えをはじめて使ってみて便利だったのでメモを残す。

Viewにおいて、

<?php echo($this->Paginator->sort("並び替え対象モデル名.並び替え対象コラム名", "リンク文字列")); ?>

これが基本。
これで、並び替えのためのURLが仕込まれたリンクを作成することができる。
この場合、指定されたコラムでの並び替えになり、昇順・降順がトグルする(クリックするたびに昇順降順が入れ替わる)。

トグルするのが気色悪いという場合、昇順降順指定込みのリンクをワンセットで作っておくとよい。sort() の第三引数にオプションを設定できるのでここに書く。
こんな感じ。たいてい検索結果はテーブルで出すだろうからテーブルの一部を抜き出した感じのソースで。

------------------------
<th>
    会員ID
    <?php echo($this->Paginator->sort("Member.id", "▲", array('direction' => 'asc' , 'lock' => true))); ?>
    <?php echo($this->Paginator->sort("Member.id", "▼", array('direction' => 'desc', 'lock' => true))); ?><br>
</th>
------------------------

2015年7月17日金曜日

【cakePHP】/プレフィックス/クラス/メソッド ルーティングプレフィックスの話



コントローラーのメソッドに、アンダーバーを持ったプレフィックスを設定して、変則的なURLを生成する技がある。

class TestsController extends AppController{
    public function prefix_index(){
    }//function
}//class

こういうクラスがあるとき、

/tests/prefix_index
というのが本来のURL

これに、ルーティングプレフィックスという設定を組み合わせる。
参考:
https://24nwakahana.wordpress.com/2013/02/13/cakephp-2-0-routing-prefixes-%E3%82%92%E4%BD%BF%E3%81%86%E3%80%82%E3%81%9D%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E6%AD%A2%E3%82%81%E3%82%8B%E3%80%82/

Configure::write('Routing.prefixes', array('prefix'));

このコンフィグは、/app/Config/core.php に書かないといけないらしい。

この設定を有効にすると、上記メソッドによるURLは以下の形になる。

/prefix/tests/index

注意しなくてはならないのは、

/クラス/プレフィックス/メソッド
というURLにはならず、

/プレフィックス/クラス/メソッド
というURLになること。

prefix_index()

prefix/index
とはならないので注意。

2015年6月11日木曜日

【cakePHP】ヴァリデーションエラーをDIVで囲わせたくない

cakePHP で、ヴァリデーションエラーを明示的に表示したい場合、以下のようなコードをViewに書く。
-------------- 

<?php echo $this->Form->error("モデル名.フィールド名"); ?>
-------------- 

すると、実際は以下のようなHTMLが出力される。

-------------- 
<div class="error-message"> 
    郵便番号の形式が不正です。(半角数字と半角ハイフンのみ有効)
 </div>
-------------- 

しかし、DIVが邪魔であると。
DIVで囲わせたくない時、以下のように書く。第2引数、第3引数(配列)が必要。

[Viewに書くコード]
-------------- 

<?php echo $this->Form->error("モデル名.フィールド名", null, array("wrap"=>false,)); ?>
-------------- 

2015年1月21日水曜日

【cakePHP】データベース構造を変更したらキャッシュを殺せ

cakePHPを使ってのシステム開発。
データベーステーブルを追加する必要があったのでPHPMyAdminからテーブルを追加。
そのテーブルを受け持つモデルクラスを作成し、find()で動作テスト。



動かん!!!


3時間苦しんだ挙句、原因がわかりました。
キャッシュです。

参考
http://oneday.ter.jp/php/cakephp-php/983.html

\app\tmp\cache\models
に、データベーステーブルとモデルクラスとをつなぐファイルのキャッシュがあるようです。

テーブル構造を変更したら(カラムやテーブルを追加したり名前を変えたりしたら)キャッシュをバシバシ皆殺しにしよう!!!