DEVELOPERS BLOGデベロッパーズブログ

  1. HOME > 
  2. 加藤 正人のデベロッパーズブログ > 
  3. テキストフィールドを CSV として処理する CakePHP ビヘイビア・その2

加藤 正人のデベロッパーズブログ

加藤 正人

氏名
加藤 正人
役職
多分SE
血液型
秘密
出没
美味しいもののあるところ
特色
タヒチ大好き。ちょいメタボ。

加藤 正人

2014/12/20

テキストフィールドを CSV として処理する CakePHP ビヘイビア・その2

 

今回もテキストフィールドを CSV として処理するビヘイビアの作成を進める。

前回の取得用コールバックに引き続き、今回は保存時のコールバックを作成する。

データ保存時の変換

データ保存時には、beforeSave() コールバックで保存データをチェックし、該当するフィールドのデータをカンマ区切り文字列に変換する。渡されたデーがが空配列や空文字列の場合は '' (空文字列) に変換する。

01class SimpleCsvFieldBehavior extends ModelBehavior
02{
03    // …【中略】…
04    public function beforeSave(Model $model, array $options = array())
05    {
06        // CSV データ形式のフィールド対応 (配列 ⇒ CSV 文字列変換)
07        foreach ( $this->actual_settings['fields'] as $csv_field )
08        {
09            if ( isset($this->data[$this->alias][$csv_field]) )
10            {
11                if ( is_array($this->data[$this->alias][$csv_field]) )
12                {
13                    $this->data[$this->alias][$csv_field] = implode($this->_csv_separator, $this->data[$this->alias][$csv_field]);
14                }
15                else if ( strlen($this->data[$this->alias][$csv_field]) == 0 )
16                {
17                    $this->data[$this->alias][$csv_field] = '';
18                }
19                else
20                {
21                    // 何もしない
22                }
23            }
24        }
25        return TRUE;
26    }
27}

 

絞り込み条件の変換

最後に、find() 時の検索式の変換処理を beforeFind() コールバックで行なう。条件の変換は再帰処理になるので、プライベートメソッド __condition_replace() として独立させておく。

__condition_replace() の内部処理では、簡単のため条件配列のキーは {モデル名}.{フィールド名} のみ、値はスカラー値のみ (整数のみ) としており、!= や大小比較、IN 演算、あるいは MySQL 関数呼び出しには対応していない。

__condition_replace() では、CSV フィールドを検出すると、その {モデル名}.{フィールド名} => {値} の組を次の「OR」形式に変換する。

'OR' => array(
	"{モデル名}.{フィールド名} LIKE" => "{値}",	// 値が単独値の場合
	"{モデル名}.{フィールド名} LIKE" => "{値}{区切り文字}",	// CSV形式の先頭にマッチ
	"{モデル名}.{フィールド名} LIKE" => "{区切り文字}{値}{区切り文字}",	// CSV形式の途中にマッチ
	"{モデル名}.{フィールド名} LIKE" => "{区切り文字}{値}",	// CSV形式の末尾にマッチ
)

これにより、CSV フィールドに値が含まれるかどうかを文字列演算で行なうことができる。

この書き換えメソッドを beforeFind() コールバックで使用して条件配列を書き換える。実際のコードは下記のようになる。

01class SimpleCsvFieldBehavior extends ModelBehavior
02{
03    // …【中略】…
04    private function __condition_replace($array, $replace_key_patterns)
05    {
06        $separator = $this->actual_settings['separator'];
07        if ( $array )
08        {
09            $ret = array();
10            foreach ( $array as $key => $value )
11            {
12                if ( in_array($key, $replace_key_patterns) )
13                {
14                    $ret[] = array('OR' => array(
15                        array("{$key} LIKE" => "{$value}"), // 値が単独
16                        array("{$key} LIKE" => "{$value}{$separator}%"),    // 値が先頭
17                        array("{$key} LIKE" => "%{$separator}{$value}{$separator}%"),   // 値が中間
18                        array("{$key} LIKE" => "%{$separator}{$value}") // 値が末尾
19                    ));
20                }
21                else if ( is_array($value) )
22                {
23                    $ret[$key] = $this->__condition_replace($value, $replace_key_patterns);
24                }
25                else
26                {
27                    $ret[$key] = $value;
28                }
29            }
30            $array = $ret;
31        }
32        return $array;
33    }
34 
35    // find 前には queryの絞り込み条件 ($query['conditions']) の書き換えを行う
36    public function beforeFind(Model $model, array $query)
37    {
38        $model_name = $model->alias;
39        $fields = $this->actual_settings['fields'];
40 
41        $query['conditions'] = $this->__condition_replace($query['conditions'], array_map(function ($f) use($model_name) { return "{$model_name}.{$f}"; }, $fields));
42        return $query;
43    }
44    // …【以下略】…
45}

以上で CSV フィールドへの対応が簡易的ではあるが可能となる。

関連タグ: CakePHP2  PHP5.3  MySQL5 

関連エントリー

CakePHP のレンダリング結果を保存したい

CakePHP 2.x の Cookie と js.cookie.js

時刻入力用 jQuery Plugin TimePicki の不具合調整

CakePHP プラグインで HTTPS 判定

作業用モデルビヘイビア