PHP5 配列をメソッドチェインで再帰処理するクラス

CakePHPを使っていると、データ構造が多階層の配列で管理されていることが多く、一括で処理をしたい場合などに度々再帰処理を実装することがあります。
通常であれば、array_map系の関数を使って再帰的に処理を記述することになりますが、

  • 毎回array_mapを使うのは面倒だし、もっと簡潔に記述したい
  • 個別のグローバル関数・各メソッドを連続して簡単に利用したい

という理由で、以下のように記述できるクラスを作成しました。
(クラスのソースコードは最後に記述しています)

PHP:
  1. // $arrの全ての要素にtrimと半角カナ変換を実施
  2. ArrayMap::create($arr)->trim()->mb_convert_kana('KV');
  3.  
  4. // $arrの全ての要素に「先頭:」という文字を追加
  5. ArrayMap::create($arr)->sprintf('先頭:%s');

※PHP5のマジックメソッドを使って実現していますので、PHP4系では使えません
※通常の手続き型で実装する場合は「array_walk_recursive」「array_map recursive」などで検索するといろいろ参考情報があります。

Read more

CakePHP IRC集会に参加しました

昨日cakephperさん主催のCakePHP第三回IRC集会に参加させて頂きました。

業務中だったこともあり、前半ほとんど発言できず、、途中開発環境の件では、みなさんの環境が立派すぎて「sakuraエディタです」とは言えませんでした。。
(社内の2名はEmacs派のようです)
結局、最後の1時間くらいでようやくご挨拶。このブログも取り上げて頂き有難うございました。

ウチの記事を知って頂いていた方もいらして、少しはCakePHP界に貢献できていることが実感できました。

IRCでも話に出ていましたが、CakePHPの素晴らしさはFWとしての機能も当然ありますが、
知識の共有が積極的に行われていることに尽きると思います。
本の執筆活動、フォーラムでのフォロー、勉強会やIRC集会、各自のブログ、etc・・
これらの活動をされている方々には本当に感謝しています。

弊社も少しずつですが、何らかで貢献していければと思っています。

CakePHP MySQLのバックアップ(mysqldump)を行うバッチ

CakePHP1.2からコマンドラインからCakeが起動できるようになりました。
この機能を使って、MySQLのバックアップを行う簡単なスクリプトを作成してみました。
データベースの接続には、/app/config/database.phpの接続情報を利用しています。

Read more

CakePHP 動的なウィジェットの作り方

CakePHPではコントローラーでの処理はビューを介してレイアウトのメインコンテンツ($content_for_layout)の部分に展開されます。
その際レイアウトに配置してあるメインコンテンツ以外の部分は基本的にはコントローラーから操作ができません。(たぶん)
一般的なサイトでは2段組みや3段組みのレイアウトを使うケースが多いと思いますが、メインコンテンツ領域以外もCakeを使って柔軟に制御する方法を検討します。
(出力されるHTMLの部品をウィジェットとします)

※今回の実装サンプルはこちらから確認できます。
※ソースコードはこちらからダウンロードできます。
※サンプルではメインコンテンツ側で指定されたカテゴリの情報をフッター部に表示しています。

Read more

CakePHP Behaviorでバリデーション周りの効率化を図る 応用編

前回紹介したBasicValidationBehaviorを使って、動的にバリデーションを切り替える方法を紹介します。
共通のモデルを複数のフォームで利用している場合にバリデーションの定義を動的に変更したい場合などに有効です。

例1:新規登録時と編集時でバリデーションの登録項目を変更する

対応1)loadValidate()メソッドに引数を追加し、条件によって分岐させる

[モデル内の処理]

PHP:
  1. function loadValidate($action = 'add') {
  2.     $valid = array(
  3.         'name'   => 'required | maxLen[50]',
  4.         'email'         => 'required | email | isUnique | maxLen[200]',
  5.         'password'  => 'required | single | maxLen[20] | minLen[6]',
  6.         're_password'   => 'required | confirm[password]',
  7.         'sex'     => 'required | numeric | maxLen[1]',
  8.         'birthday'  => 'required | ymd',
  9.         'tel'      => 'required | phone | maxLen[13]',
  10.         'zip'      => 'required | zip | maxLen[8]',
  11.         'pref'    => 'required | maxLen[12]',
  12.         'addr1'      => 'required | maxLen[200]',
  13.         'addr2'      => 'maxLen[200]',
  14.     );
  15.     // 新規登録時以外はパスワード関連の項目を無効にする
  16.     if($action !== 'add'){
  17.         unset($valid['password']);
  18.         unset($valid['re_password']);
  19.     }
  20.     $this->setValidate($valid);
  21. }

対応2)コントローラーでモデルのvalidate()やsave()前にloadValidate()を明示的に実行する

[コントローラー内の処理]

PHP:
  1. function add(){
  2. // 処理を省略
  3.  
  4.     $this->TestUser->set($this->data);
  5.     // バリデーションを設定
  6.     $this->TestUser->loadValidate('add');
  7.     if($this->TestUser->validates()) {
  8.    
  9. // 処理を省略
  10. }
  11.  
  12. function edit($id = null){
  13. // 処理を省略
  14.  
  15.     $this->TestUser->id = $id;
  16.     $this->TestUser->set($this->data);
  17.     // バリデーションを設定
  18.     $this->TestUser->loadValidate('edit');
  19.     if($this->TestUser->validates()) {
  20.    
  21. // 処理を省略
  22. }

Read more

CakePHP Behaviorでバリデーション周りの効率化を図る

CakePHPでバリデーションを使う際、標準(CakePHP1.2)のままでも十分開発はできますが、大きめのプロジェクトや複数のプロジェクトでも汎用的かつ効率的に使えるようにできないかと検討しました。

バリデーション改善の目的

  1. エラーメッセージを日本語化し共通化・デフォルト化したい
  2. 独自バリデーションメソッドを共通化したい
  3. ルール配列を簡単に記述したい(項目が多いとソースが長くなり過ぎて見通しがよくない)
  4. バリデーションの前に自動で整形処理をしたい(半角英数変換やカタカナ変換など)

実装にあたって

バリデーションメソッドの共通化については、
cakephperさんの日記:よく使う独自バリデーションルールをプラグインのbehaviorにまとめる
に記載してありますように、プラグインのbehaviorで管理するほうが良いと思いますが、今回は弊社で過去に実装した通常のbehavior(BasicValidationBehaviorとします)を使った方法を紹介します。

Read more

CakePHP Formヘルパの拡張 その2
3項目の電話番号入力フィールド

$form->textを拡張して3項目の電話番号入力フィールドを生成

前回に続いて、Formヘルパの拡張の第二弾です。
入力欄としてよくあるものとしては、電話番号や郵便番号を分割された入力フィールドで入力させるケースがあります。
入力フォームはモデル(テーブル)と連携するケースが多いですが、テーブルのカラムが1つなのに入力フォームは分割しなければならない場合などは、少々面倒なことを行う必要があります。

この煩わしさを回避する為に、カラムは1つでも入力欄は3つに自動的に分割されるようにに拡張する方法を検討しました。

結論から言えば、ヘルパだけの拡張では入力欄を分割するところまではできましたが、DBに格納する際に自動的に分割した値を結合することができませんでした。
(イマイチな)解決案として、AppModel内に処理を追加することでDB格納時の自動結合化を行っています。
動作はこちらから確認できます。
Read more

CakePHP Formヘルパの拡張 その1
日本語日付選択プルダウン

$form->datetimeを拡張して日本語の日付選択プルダウンを生成

CakePHP1.2のFormHelperには日付をプルダウンメニューで選択する機能があります。
生年月日の入力などに重宝しますが、日付の書式が英語なので日本の日付形式に変更する必要があります。

そこで、Formヘルパを拡張してExformヘルパクラスを生成し、独自メソッド内で日本語化対応を実施します。
動作はこちらから確認できます。
Read more

CakePHP HABTMモデルの検索

HABTMで関連付けされたテーブルを検索条件に加えたい場合、一回のfindメソッドで取得しようとすると、joinの設定やグループ化で面倒な実装が必要になってきます。

データ量にもよりますが、

1)関連テーブルを先に検索し、ID配列を取得
2)ID配列を検索条件に追加

としたほうが簡単に実装できるケースが多そうです。
Read more

CakePHP コントローラーのアクションをコンポーネントにまとめる

本業のほうが忙しく久々の更新になってしまいましたが小ネタです。

Cakeを使っていると最初はbakeやscaffoldを利用する機会がありますが、序々に利用頻度が減ってきました。(現在では殆ど使っていません)

理由としては、社内での共通のルールであったり、プロジェクト毎の特性を反映した雛型から複製して作成したほうが効率的になってきたということが大きいと思います。

ただ、bakeでの自動生成や複製方式だと初回は良いのですが、大規模なものになってくると、同様のソースが点在し一括での改修などが面倒なことになってきます。

ということで、明らかに同様の処理はscaffold風にコンポーネント化することにしました。
※コンポーネントからコントローラーを制御する場合は、ロジックが分散すると見通しが悪くなりますので、ロジック全体を委譲できる場合に利用することをお勧めします。
Read more

Next Page →