年齢検索追加
□10-19
■20-29
とすると 10代、 20代のユーザーを絞りこめる。
○コントローラー
array('field' => 'birthday', 'type' => 'checkbox'),
○ビュー
年齢で絞り込み
<?=$form->input('birthday',array('type' => 'select','multiple' => 'checkbox', 'options' => array('10-19' => '10代','20-29' => '20代','30-39' => '30代')));?><br />
○モデル
array('name' => 'birthday', 'type' => 'age'),
こんな感じ。
likeor検索も追加。
_addLikeOr
チェックボックスで
■つけ麺
■ラーメン
□ぼくイケメン
とあり、指定したフィールドから %つけ麺% and &ラーメン& 検索をする。
○モデル
array('name' => 'fortunes', 'type' => 'likeor'),
をやればよい。
で、コンとローラーで checkbox を指定。
or検索できんがね
やり方わからんだけなのか?
よくある
チェックボックスを 2つ3つ選択した場合、そのデータのどれかを持っている物を表示
ってやりたいんだけど。
で・・・改造しました。
改造した箇所は
・_addOrValue メソッドの追加
・parseCriteria をちょいいじり。
改造版 cakephp searchplugin の searchble.php ビヘイビア
<?php
/**
* CakePHP Tags Plugin
*
* Copyright 2009 - 2010, Cake Development Corporation
* 1785 E. Sahara Avenue, Suite 490-423
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright 2009 - 2010, Cake Development Corporation (http://cakedc.com)
* @link http://github.com/CakeDC/Search
* @package plugins.search
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Searchable behavior
*
* @package plugins.search
* @subpackage plugins.search.models.behaviors
*/
class SearchableBehavior extends ModelBehavior {
/**
* settings indexed by model name.
*
* @var array
* @access public
*/
public $settings = array();
/**
* Default settings
*
* @var string
**/
protected $_defaults = array();
/**
* Configuration of model
*
* @param AppModel $model
* @param array $config
*/
public function setup(Model $model, $config = array()) {
$this->settings[$model->alias] = array_merge($this->_defaults, $config);
}
/**
* parseCriteria
* parses the GET data and returns the conditions for the find('all')/paginate
* we are just going to test if the params are legit
*
* @param array $data Criteria of key->value pairs from post/named parameters
* @return array Array of conditions that express the conditions needed for the search.
* @access public
*/
public function parseCriteria(Model $model, $data) {
$conditions = array();
foreach ($model->filterArgs as $field) {
if (in_array($field['type'], array('string', 'like'))) {
$this->_addCondLike($model, $conditions, $data, $field);
} elseif (in_array($field['type'], array('int', 'value'))) {
$this->_addCondValue($model, $conditions, $data, $field);
} elseif ($field['type'] == 'expression') {
$this->_addCondExpression($model, $conditions, $data, $field);
} elseif ($field['type'] == 'query') {
$this->_addCondQuery($model, $conditions, $data, $field);
} elseif ($field['type'] == 'subquery') {
$this->_addCondSubquery($model, $conditions, $data, $field);
} elseif ($field['type'] == 'or') {
$this->_addOrValue($model, $conditions, $data, $field);
} elseif ($field['type'] == 'likeor') {
$this->_addLikeOr($model, $conditions, $data, $field);
} elseif ($field['type'] == 'age') {
$this->_addAgeBetween($model, $conditions, $data, $field);
}
}
return $conditions;
}
protected function _addAgeBetween(Model $model, &$conditions, $data, $field) {
if(!empty($data[$field['name']]) && preg_match('/\|/',$data[$field['name']])){
$data[$field['name']] = explode('|',$data[$field['name']]);
}
if(!empty($data[$field['name']]) && !is_array($data[$field['name']])){
$tmp = $data[$field['name']];
$data[$field['name']] = array();
$data[$field['name']][] = $tmp;
}
if(!empty($data[$field['name']])){
$range = array();
foreach($data[$field['name']] as $v){
$age = explode('-',$v);
$range[] = $this->_getBirthdayRange($age[0],$age[1]);
}
}
$fieldName = $field['name'];
if (isset($field['field'])) {
$fieldName = $field['field'];
}
if (strpos($fieldName, '.') === false) {
$fieldName = $model->alias . '.' . $fieldName;
}
if (!empty($data[$field['name']])) {
$conditions['or'] = '';
foreach($range as $key => $v){
$conditions['or'][$key][$fieldName . " >="] = $v[0];
$conditions['or'][$key][$fieldName . " <="] = $v[1];
}
}
return $conditions;
}
//年齢の範囲を取得する
function _getBirthdayRange($before_age,$after_age = '')
{
if(!empty($after_age)){
$age = $after_age;
} else {
$age = $before_age;
}
$start = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y') - $age - 1);
$end = mktime(0, 0, 0, date('m'), date('d'), date('Y') - $before_age);
return array(date('Y-m-d', $start), date('Y-m-d', $end));
}
/**
* Validate search
*
* @param object Model
* @return boolean always true
* @access public
*/
public function validateSearch(Model $model, $data = null) {
if (!empty($data)) {
$model->set($data);
}
$keys = array_keys($model->data[$model->alias]);
foreach ($keys as $key) {
if (empty($model->data[$model->alias][$key])) {
unset($model->data[$model->alias][$key]);
}
}
return true;
}
/**
* filter retrieving variables only that present in Model::filterArgs
*
* @param object Model
* @param array $vars
* @return array, filtered args
* @access public
*/
public function passedArgs(Model $model, $vars) {
$result = array();
foreach ($vars as $var => $val) {
if (in_array($var, Set::extract($model->filterArgs, '{n}.name'))) {
$result[$var] = $val;
}
}
return $result;
}
/**
* Method to generated DML SQL queries using find* style.
*
* Specifying 'fields' for new-notation 'list':
* - If no fields are specified, then 'id' is used for key and Model::$displayField is used for value.
* - If a single field is specified, 'id' is used for key and specified field is used for value.
* - If three fields are specified, they are used (in order) for key, value and group.
* - Otherwise, first and second fields are used for key and value.
*
* @param array $conditions SQL conditions array, or type of find operation (all / first / count / neighbors / list / threaded)
* @param mixed $fields Either a single string of a field name, or an array of field names, or options for matching
* @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC")
* @param integer $recursive The number of levels deep to fetch associated records
* @return string SQL query string.
* @access public
* @link http://book.cakephp.org/view/449/find
*/
public function getQuery(Model $model, $conditions = null, $fields = array(), $order = null, $recursive = null) {
if (!is_string($conditions) || (is_string($conditions) && !array_key_exists($conditions, $model->_findMethods))) {
$type = 'first';
$query = compact('conditions', 'fields', 'order', 'recursive');
} else {
list($type, $query) = array($conditions, $fields);
}
$db =& ConnectionManager::getDataSource($model->useDbConfig);
$model->findQueryType = $type;
$model->id = $model->getID();
$query = array_merge(
array(
'conditions' => null, 'fields' => null, 'joins' => array(),
'limit' => null, 'offset' => null, 'order' => null, 'page' => null,
'group' => null, 'callbacks' => true
),
(array)$query
);
if ($type != 'all') {
if ($model->_findMethods[$type] === true) {
$query = $model->{'_find' . ucfirst($type)}('before', $query);
}
}
if (!is_numeric($query['page']) || intval($query['page']) < 1) {
$query['page'] = 1;
}
if ($query['page'] > 1 && !empty($query['limit'])) {
$query['offset'] = ($query['page'] - 1) * $query['limit'];
}
if ($query['order'] === null && $model->order !== null) {
$query['order'] = $model->order;
}
$query['order'] = array($query['order']);
if ($query['callbacks'] === true || $query['callbacks'] === 'before') {
$return = $model->Behaviors->trigger($model, 'beforeFind', array($query), array(
'break' => true, 'breakOn' => false, 'modParams' => true
));
$query = (is_array($return)) ? $return : $query;
if ($return === false) {
return null;
}
$return = $model->beforeFind($query);
$query = (is_array($return)) ? $return : $query;
if ($return === false) {
return null;
}
}
return $this->__queryGet($model, $query, $recursive);
}
/**
* Clear all associations
*
* @param AppModel $model
* @param bool $reset
*/
public function unbindAllModels(Model $model, $reset = false) {
$assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
$unbind = array();
foreach ($assocs as $assoc) {
$unbind[$assoc] = array_keys($model->{$assoc});
}
$model->unbindModel($unbind, $reset);
}
/**
* Add Conditions based on fuzzy comparrison
*
* @param AppModel $model Reference to the model
* @param array $conditions existing Conditions collected for the model
* @param array $data Array of data used in search query
* @param array $field Field definition information
* @return array of conditions.
* @access protected
*/
protected function _addCondLike(Model $model, &$conditions, $data, $field) {
$fieldName = $field['name'];
if (isset($field['field'])) {
$fieldName = $field['field'];
}
if (strpos($fieldName, '.') === false) {
$fieldName = $model->alias . '.' . $fieldName;
}
if (!empty($data[$field['name']])) {
$conditions[$fieldName . " LIKE"] = "%" . $data[$field['name']] . "%";
}
return $conditions;
}
//オリジナル
//チェックボックスのデータをlike句で検索する
protected function _addLikeOr(Model $model, &$conditions, $data, $field) {
$fieldName = $field['name'];
if (isset($field['field'])) {
$fieldName = $field['field'];
}
if (strpos($fieldName, '.') === false) {
$fieldName = $model->alias . '.' . $fieldName;
}
if (!empty($data[$field['name']])) {
$conditions['or'] = '';
$ar = explode('|',$data[$field['name']]);
foreach($ar as $v){
$conditions['or'][][$fieldName . " LIKE"] = "%" . $v . "%";
}
}
return $conditions;
}
/**
* オリジナル。チェックボックスの配列データをorで検索
*
* @param AppModel $model Reference to the model
* @param array $conditions existing Conditions collected for the model
* @param array $data Array of data used in search query
* @param array $field Field definition information
* @return array of conditions.
* @access protected
*/
protected function _addOrValue(Model $model, &$conditions, $data, $field) {
if(!empty($data[$field['name']]) && preg_match('/\|/',$data[$field['name']])){
$data[$field['name']] = explode('|',$data[$field['name']]);
}
$fieldName = $field['name'];
if (isset($field['field'])) {
$fieldName = $field['field'];
}
if (strpos($fieldName, '.') === false) {
$fieldName = $model->alias . '.' . $fieldName;
}
if (!empty($data[$field['name']]) || (isset($data[$field['name']]) && (int)$data[$field['name']] === 0)) {
$conditions[$fieldName] = $data[$field['name']];
}
return $conditions;
}
/**
* Add Conditions based on exacltly comparrison
*
* @param AppModel $model Reference to the model
* @param array $conditions existing Conditions collected for the model
* @param array $data Array of data used in search query
* @param array $field Field definition information
* @return array of conditions.
* @access protected
*/
protected function _addCondValue(Model $model, &$conditions, $data, $field) {
$fieldName = $field['name'];
if (isset($field['field'])) {
$fieldName = $field['field'];
}
if (strpos($fieldName, '.') === false) {
$fieldName = $model->alias . '.' . $fieldName;
}
if (!empty($data[$field['name']]) || (isset($data[$field['name']]) && (int)$data[$field['name']] === 0)) {
$conditions[$fieldName] = $data[$field['name']];
}
return $conditions;
}
/**
* Add Conditions based query to search conditions.
*
* @param Object $model Instance of AppModel
* @param array $conditions Existing conditions.
* @param array $data Data for a field.
* @param array $field Info for field.
* @return array of conditions modified by this method.
* @access protected
*/
protected function _addCondQuery(Model $model, &$conditions, $data, $field) {
if ((method_exists($model, $field['method']) || $this->__checkBehaviorMethods($model, $field['method'])) && !empty($data[$field['name']])) {
$conditionsAdd = $model->{$field['method']}($data);
$conditions = array_merge($conditions, (array)$conditionsAdd);
}
return $conditions;
}
/**
* Add Conditions based expressions to search conditions.
*
* @param Object $model Instance of AppModel
* @param array $conditions Existing conditions.
* @param array $data Data for a field.
* @param array $field Info for field.
* @return array of conditions modified by this method.
*/
protected function _addCondExpression(Model $model, &$conditions, $data, $field) {
$fieldName = $field['field'];
if ((method_exists($model, $field['method']) || $this->__checkBehaviorMethods($model, $field['method'])) && !empty($data[$field['name']])) {
$fieldValues = $model->{$field['method']}($data, $field);
if (!empty($conditions[$fieldName]) && is_array($conditions[$fieldName])) {
$conditions[$fieldName] = array_unique(array_merge(array($conditions[$fieldName]), array($fieldValues)));
} else {
$conditions[$fieldName] = $fieldValues;
}
}
return $conditions;
}
/**
* Add Conditions based subquery to search conditions.
*
* @param Object $model Instance of AppModel
* @param array $conditions Existing conditions.
* @param array $data Data for a field.
* @param array $field Info for field.
* @return array of conditions modified by this method.
* @access protected
*/
protected function _addCondSubquery(Model $model, &$conditions, $data, $field) {
$fieldName = $field['field'];
if ((method_exists($model, $field['method']) || $this->__checkBehaviorMethods($model, $field['method'])) && !empty($data[$field['name']])) {
$subquery = $model->{$field['method']}($data);
$conditions[] = array("$fieldName in ($subquery)");
}
return $conditions;
}
/**
* Helper method for getQuery.
* extension of dbosource method. Create association query.
*
* @param AppModel $model
* @param array $queryData
* @param integer $recursive
* @access private
*/
private function __queryGet(Model $model, $queryData = array(), $recursive = null) {
$db =& ConnectionManager::getDataSource($model->useDbConfig);
$db->__scrubQueryData($queryData);
$null = null;
$array = array();
$linkedModels = array();
$db->__bypass = false;
$db->__booleans = array();
if ($recursive === null && isset($queryData['recursive'])) {
$recursive = $queryData['recursive'];
}
if (!is_null($recursive)) {
$_recursive = $model->recursive;
$model->recursive = $recursive;
}
if (!empty($queryData['fields'])) {
$db->__bypass = true;
$queryData['fields'] = $db->fields($model, null, $queryData['fields']);
} else {
$queryData['fields'] = $db->fields($model);
}
foreach ($model->__associations as $type) {
foreach ($model->{$type} as $assoc => $assocData) {
if ($model->recursive > -1) {
$linkModel =& $model->{$assoc};
$external = isset($assocData['external']);
if ($model->alias == $linkModel->alias && $type != 'hasAndBelongsToMany' && $type != 'hasMany') {
if (true === $db->generateSelfAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
$linkedModels[] = $type . '/' . $assoc;
}
} else {
if ($model->useDbConfig == $linkModel->useDbConfig) {
if (true === $db->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
$linkedModels[] = $type . '/' . $assoc;
}
}
}
}
}
}
return $db->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null);
}
/**
* Check if model have some method in attached behaviors
*
* @param Model $Model
* @param string $method
* @return boolean, true if method exists in attached and enabled behaviors
**/
private function __checkBehaviorMethods(Model $Model, $method) {
$behaviors = $Model->Behaviors->enabled();
$count = count($behaviors);
$found = false;
for ($i = 0; $i < $count; $i++) {
$name = $behaviors[$i];
$methods = get_class_methods($Model->Behaviors->{$name});
$check = array_flip($methods);
$found = isset($check[$method]);
if ($found) {
return true;
}
}
return $found;
}
}
?>
○prg.php コンポーネント
<?php
/**
* CakePHP Tags Plugin
*
* Copyright 2009 - 2010, Cake Development Corporation
* 1785 E. Sahara Avenue, Suite 490-423
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright 2009 - 2010, Cake Development Corporation (http://cakedc.com)
* @link http://github.com/CakeDC/Search
* @package plugins.search
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Post-Redirect-Get: Transfers POST Requests to GET Requests
*
* @package plugins.search
* @subpackage plugins.search.controllers.components
*/
class PrgComponent extends Object {
/**
* Actions used to fetch the post data
*
* Maps the action that takes the post data and processes it by using this
* component and maps it to another action that is accessed by a redirect which
* has the post data attached as get data now
*
* array('search' => 'results');
* array('search' => array('controller' => 'results');
*
* @var array actions
* @access public
*/
public $actions = array();
/**
* Intialize Callback
*
* @param object Controller object
* @access public
*/
public function initialize(&$controller) {
$this->controller = $controller;
}
/**
* Poplulates controller->data with allowed values from the named/passed get params
*
* Fields in $controller::$presetVars that have a type of 'lookup' the foreignKey value will be inserted
*
* 1) 'lookup'
* Is used for autocomplete selectors
* For autocomplete we have hidden field with value and autocomplete text box
* Component fills text part on id from hidden field
* 2) 'value'
* The value as it is entered in form
* 3) 'checkbox'
* Allows to pass several values internaly encoded as string
*
* 1 use field, model, formField, and modelField
* 2, 3 need only field parameter
*
* @param array
* @access public
*/
public function presetForm($model) {
$data = array($model => array());
$args = $this->controller->passedArgs;
foreach ($this->controller->presetVars as $field) {
if ($field['type'] == 'lookup') {
if (isset($args[$field['field']])) {
$searchModel = $field['model'];
$this->controller->loadModel($searchModel);
$this->controller->{$searchModel}->recursive = -1;
$result = $this->controller->{$searchModel}->findById($args[$field['field']]);
$data[$model][$field['field']] = $args[$field['field']];
$data[$model][$field['formField']] = $result[$searchModel][$field['modelField']];
}
}
if ($field['type'] == 'checkbox') {
if (isset($args[$field['field']])) {
$values = split('\|', $args[$field['field']]);
$data[$model][$field['field']] = $values;
}
}
if ($field['type'] == 'value') {
if (isset($args[$field['field']])) {
$data[$model][$field['field']] = $args[$field['field']];
}
}
}
$this->controller->data = $data;
$this->controller->parsedData = $data;
}
/**
* Restores form params for checkboxs and other url encoded params
*
* @param array
* @access public
*/
public function serializeParams(&$data) {
foreach ($this->controller->presetVars as $field) {
if ($field['type'] == 'checkbox') {
if (!empty($data[$field['field']]) && is_array($data[$field['field']])) {
$values = join('|', $data[$field['field']]);
} else {
$values = '';
}
$data[$field['field']] = $values;
}
}
return $data;
}
/**
* Connect named arguments
*
* @param array $data
* @param array $exclude
* @return void
* @access public
*/
public function connectNamed($data = null, $exclude = array()) {
if (!isset($data)) {
$data = $this->controller->passedArgs;
}
if (!is_array($data)) {
return;
}
foreach ($data as $key => $value) {
if (!is_numeric($key) && !in_array($key, $exclude)) {
Router::connectNamed(array($key));
}
}
}
/**
* Exclude
*
* Removes key/values from $array based on $exclude
* @param array Array of data to be filtered
* @param array Array of keys to exclude from other $array
* @return array
* @access public
*/
public function exclude($array, $exclude) {
$data = array();
foreach ($array as $key => $value) {
if (!is_numeric($key) && !in_array($key, $exclude)) {
$data[$key] = $value;
}
}
return $data;
}
/**
* Common search method
*
* Handles processes common to all PRG forms
*
* - Handles validation of post data
* - converting post data into named params
* - Issuing redirect(), and connecting named parameters before redirect
* - Setting named parameter form data to view
*
* @param string $modelName Name of the model class being used for the prg form
* @param array $options Optional parameters:
* - string form Name of the form involved in the prg
* - string action The action to redirect to. Defaults to the current action
* - mixed modelMethod If not false a string that is the model method that will be used to process the data
* @return void
* @access public
*/
public function commonProcess($modelName = null, $options = array()) {
$defaults = array(
'form' => null,
'keepPassed' => true,
'action' => null,
'modelMethod' => 'validateSearch');
extract(Set::merge($defaults, $options));
if (empty($modelName)) {
$modelName = $this->controller->modelClass;
}
if (empty($formName)) {
$formName = $modelName;
}
if (empty($action)) {
$action = $this->controller->action;
}
if (!empty($this->controller->data)) {
$this->controller->{$modelName}->data = $this->controller->data;
$valid = true;
if ($modelMethod !== false) {
$valid = $this->controller->{$modelName}->{$modelMethod}();
}
if ($valid) {
$passed = $this->controller->params['pass'];
$params = $this->controller->data[$modelName];
$params = $this->exclude($params, array());
if ($keepPassed) {
$params = array_merge($passed, $params);
}
$this->serializeParams($params);
$this->connectNamed($params, array());
$params['action'] = $action;
$params = array_merge($this->controller->params['named'], $params);
$this->controller->redirect($params);
} else {
$this->controller->Session->setFlash(__('Please correct the errors below.', true));
}
}
if (empty($this->controller->data) && !empty($this->controller->passedArgs)) {
$this->connectNamed($this->controller->passedArgs, array());
$this->presetForm($formName);
}
}
}
?>
んで使い方は
○適当なモデル
<?
class Searchtest extends AppModel {
var $actsAs = array(
'Search.Searchable'
);
var $filterArgs = array(
array('name' => 'vip', 'type' => 'or'),
);
}
?>
コントローラーのタイプは checkbox 。
モデルは type or を指定。
すると
□夢
□希望
のまま検索すれば夢も希望も無い人だけ取得。
■夢
■希望
とすれば、夢か希望を持っているユーザーのみ取得できますよーん。



