RSS

cakePHP2.1でSearchPlugin hasManyを扱う

24 3月

先日からSearchPluginを使った画面周りの実装してます。
今回は特に、一対多データの扱いについてです。
ブログにタグをつけたチュートリアルが結構あるので、HABTMデータは結構ありますね。
今回の実際はHABTAMではなく、中間テーブルを介在しません。

その1.企業モデルに「属性」を外だしで複数持たせる。(いわば、タグと同じ)
その2.属性は複数もてるが、マスターテーブルは持たない。
その3.属性テーブルはid,company_id,nameという構成。

というちょっと特殊なケースかもしれない。でも よくあるUseとPostの関係だと思ってもらってもいいです。
ただし、属性自体を「AND」条件で検索したい。というのが味噌です。

SearchPluginの準備
app配下にSearchというディレクトリ掘って、GitHubのこちら
一式ごっそりおきます。
bootstrap.phpのこの箇所が生きていれば、問題ないでしょう。

CakePlugin::loadAll(); // Loads all plugins at once

次に読みこむコントローラー側で利用できるように

public $components = array('Search.Prg'); 

こちらもセット。これで準備完了。

次に親となる企業モデルCompany.phpにこの設定。当然、テーブル構成にこのフィールドが必要です。
それと、SearchPluginで使う設定も一緒に書き足しておきましょう。
$filterArgsのmethodについては後ほど。

	public $hasMany = array(
		'CompaniesAttribute' => array(
			'className' => 'CompaniesAttribute',
			'foreignKey' => 'company_id',
			'dependent' => true,//企業が削除されたら、属性は一緒に削除されていい
			'conditions' => '',
			'fields' => '',
			'order' => 'order',
			'limit' => '',
			'offset' => '',
			'exclusive' => '',
			'finderQuery' => '',
			'counterQuery' => ''
		),
	);

	public $filterArgs = array(
		array('name' => 'attribute_id', 'type' => 'subquery', 'field' => 'Company.id', 'method' => 'searchByAttributes'),
 	);

次に、CompaniesAttribute.phpの方にも設定をしておきます。

	public $belongsTo = array(
		'Company' => array(
			'className' => 'Company',
			'foreignKey' => 'company_id',
			'conditions' => '',
			'fields' => '',
			'order' => ''
		)
	);

モデル側の設定はひとまずここまで。次は検索画面ですね。
先ほど、プラグインを読み込んだコントローラーにこんな検索メソッドを準備。
属性テーブルCompaniesAttributeから選択させる属性一覧を取得してViewに渡しています。
あとは検索結果をpaginateするための条件設定です。
検索画面と検索結果を一緒に表示しています。

	function search(){
    	  $this->Prg->commonProcess();
    	  $conditions = $this->Company->parseCriteria($this->passedArgs);//SearchPlugin
		$this->paginate = array(
		  'conditions' => $conditions,
		  'limit' => 5,
		  'order'=>'Company.id asc'
		);
		$attributes = $this->Company->CompaniesAttribute->findAllByProjectId($this->Session->read('selectedProjectId'));
		$attributes = Set::combine($attributes, '{n}.CompaniesAttribute.name', '{n}.CompaniesAttribute.name');
		$this->set('pager_numbers', $this->pager_numbers);
		$this->set(compact('attributes'));
		$this->set('companies', $this->paginate('Company'));  
	}

次にViewですね。検索フォームの箇所だけ、こんな感じ。
本当はいろんな検索条件があるのですが、属性だけにしてみました。
ひとまず属性を複数選択できるドロップダウン形式で表示しています。

<?php echo $this->Form->create('Company');?>
<fieldset>
	<legend><?php echo __('Search Company'); ?></legend>
<?php
	echo $this->Form->input('attribute_id',array('multiple'=>true,'options'=>$attributes));
?>
</fieldset>
<?php echo $this->Form->end(__('検索'));?>

これで肝心の企業モデルCompany.phpに設定していたsearchByAttributesを実装します。
こちらは @kanonjiさんのこちらの記事が非常に参考になりました。
属性自体は、IDを持たないので、値としては数字ではなくテキストが入ってきます。
検索画面のドロップダウンのリストのvalue値は「製造業」のような日本語が入ってくることを前提にしています。

    public function searchByAttributes($data = array()){
        $this->Behaviors->attach('Search.Searchable');
        $attribute_id = Set::extract($data,'/attribute_id');
	$options = array(
            'conditions' => array('CompaniesAttribute.name'  => $attribute_id),
            'contain' => $this->alias,
        );
        if (( $c = count ( $attribute_id )) !== 1 ){
        	//ここの条件を通すとAND条件として構成される。ここを通らないとOR条件として構成される。
            $options['group'] = 'CompaniesAttribute.company_id HAVING COUNT(CompaniesAttribute.company_id) = '.$c;
        }
	$data = $this->CompaniesAttribute->find('all',$options);
        $condition = implode(', ', Set::extract($data,'/Company/id'));
        if ( empty( $condition )){
            $condition = 'NULL';
        }
        return $condition;
    }

若干いじったところ
属性モデルから企業モデルを参照するのでcontainでCompanyモデルを利用しようとしたら、
find(‘list’)ではLEFTJOINされなかったのでall指定にしてextractでIDを引っ張り出しました。

広告
 
1件のコメント

投稿者: : 3月 24, 2012 投稿先 cakephp

 

cakePHP2.1でSearchPlugin hasManyを扱う」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

 
%d人のブロガーが「いいね」をつけました。