-
-
Save MadFaill/0c576a5f9c555a9a1aae to your computer and use it in GitHub Desktop.
Quto.ru new search (with MONGO)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"_id" : ObjectId("7d04bbbe5494ae9d2f5a76aa"), | |
"car_modification_id" : 486, | |
"title" : "Audi A4 2.0 TFSI quattro AMT", | |
"price_min" : 1503100, | |
"price_max" : 2443936, | |
"car_brand_id" : 33, | |
"car_model_id" : 62, | |
"car_model_sub_generation_id" : 470, | |
"car_body_id" : 1, | |
"car_class_id" : 4, | |
"car_type_id" : 1, | |
"main_info" : { | |
"modification_url" : "/Audi/A4/b8/sedan4d/20TFSIAMT_Quattro/", | |
"generation_url" : "/Audi/A4/b8/sedan4d/", | |
"image_hash" : "4bb9e5fac9f59.jpeg", | |
"brand" : "Audi", | |
"model" : "A4", | |
"brand_model_title" : "Audi A4 седан", | |
"modification_title" : "2.0 TFSI quattro AMT Базовая", | |
"model_sub_title" : "A4 седан", | |
"horsepower" : 211, | |
"fuel" : "бензин", | |
"gear" : "полный", | |
"is_swf" : false, | |
"is_new" : "1", | |
"url" : { | |
"brand" : "Audi", | |
"model" : "A4", | |
"model_sub" : "sedan4d", | |
"model_gen" : "b8", | |
"modification" : "20TFSIAMT_Quattro" | |
} | |
}, | |
"property_60" : "made_in_germany", | |
"property_58" : "fr", | |
"property_56" : "robot", | |
"property_62" : "benzin", | |
"property_67" : "european", | |
"property_8" : 1984, | |
"property_10" : 211, | |
"property_44" : 6.5, | |
"property_45" : 7.5, | |
"property_34" : 0, | |
"property_61" : 0, | |
"property_16" : 1, | |
"property_29" : 0, | |
"property_28" : 0, | |
"property_30" : 0, | |
"property_27" : 0, | |
"property_39" : 0, | |
"property_61_min" : 5, | |
"property_61_max" : 5, | |
"advanced_options" : [ | |
20, | |
22, | |
31, | |
40, | |
42, | |
59, | |
64, | |
69, | |
80, | |
81, | |
94, | |
101, | |
103, | |
122, | |
131, | |
149, | |
193, | |
198, | |
135, | |
117, | |
88, | |
93, | |
149, | |
144, | |
198, | |
84 | |
], | |
"advanced_options_price" : { | |
"20" : 60918, | |
"22" : 4446, | |
"31" : 54288, | |
"40" : 14664, | |
"42" : 19422, | |
"59" : 19968, | |
"64" : 11856, | |
"69" : 48750, | |
"80" : 16614, | |
"81" : 14976, | |
"94" : 13572, | |
"101" : 155610, | |
"103" : 68094, | |
"122" : 34086, | |
"131" : 14664, | |
"149" : 29094, | |
"193" : 30498, | |
"198" : 43212, | |
"135" : 14976, | |
"117" : 155610, | |
"88" : 0, | |
"93" : 0, | |
"144" : 0, | |
"84" : 43212 | |
}, | |
"base_options" : [ | |
1, | |
2, | |
6, | |
8, | |
14, | |
15, | |
16, | |
39, | |
48, | |
58, | |
61, | |
62, | |
63, | |
66, | |
74, | |
85, | |
104, | |
3, | |
9, | |
135, | |
117, | |
75, | |
76, | |
88, | |
93, | |
149, | |
144, | |
116, | |
198, | |
84, | |
20, | |
22, | |
31, | |
40, | |
42, | |
59, | |
64, | |
69, | |
80, | |
81, | |
94, | |
101, | |
103, | |
122, | |
131, | |
193 | |
], | |
"ignore_options" : [], | |
"linked_options" : { | |
"1" : "138289", | |
"2" : "138290", | |
"6" : "138293", | |
"8" : "138294", | |
"14" : "138297", | |
"15" : "138298", | |
"16" : "138299", | |
"20" : "233642", | |
"22" : "138304", | |
"31" : "138314", | |
"39" : "138319", | |
"40" : "138320", | |
"42" : "138322", | |
"48" : "138329", | |
"52" : "205568", | |
"58" : "138335", | |
"59" : "138336", | |
"61" : "138337", | |
"62" : "138338", | |
"63" : "138339", | |
"64" : "138340", | |
"66" : "138341", | |
"69" : "138342", | |
"74" : "138347", | |
"80" : "138350", | |
"81" : "138351", | |
"85" : "138356", | |
"87" : "224080", | |
"90" : "138367", | |
"92" : "138365", | |
"94" : "138368", | |
"101" : "138364", | |
"103" : "138358", | |
"104" : "138371", | |
"122" : "138349", | |
"131" : "138308", | |
"144" : "233648", | |
"149" : "138306", | |
"193" : "138307", | |
"198" : "138357", | |
"3" : "138290", | |
"9" : "138294", | |
"135" : "138351", | |
"117" : "138364", | |
"75" : "138347", | |
"76" : "138347", | |
"88" : "224080", | |
"93" : "138365", | |
"116" : "138356", | |
"84" : "138357" | |
}, | |
"brand_models_available" : [ | |
62, | |
190, | |
240, | |
266, | |
267, | |
448, | |
460, | |
461, | |
462, | |
463, | |
464, | |
465, | |
466, | |
467, | |
468, | |
469, | |
470, | |
471, | |
472, | |
551, | |
552, | |
553, | |
554, | |
555, | |
563 | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"$match": { | |
"$and": [ | |
{ | |
"car_type_id": 1 | |
}, | |
{ | |
"price_min": { | |
"$gte": 0 | |
} | |
}, | |
{ | |
"price_min": { | |
"$lte": 4000000 | |
} | |
}, | |
{ | |
"car_body_id": { | |
"$in": [1] | |
} | |
}, | |
{ | |
"base_options": { | |
"$in": [74] | |
} | |
}, | |
{ | |
"base_options": { | |
"$all": [83, 122, 337] | |
} | |
}, | |
{ | |
"ignore_options.83": { | |
"$nin": [122, 74, 337] | |
} | |
}, | |
{ | |
"ignore_options.122": { | |
"$nin": [83, 74, 337] | |
} | |
}, | |
{ | |
"ignore_options.74": { | |
"$nin": [83, 122, 337] | |
} | |
}, | |
{ | |
"ignore_options.337": { | |
"$nin": [83, 122, 74] | |
} | |
} | |
] | |
} | |
}, | |
{ | |
"$group": { | |
"_id": "$car_model_sub_generation_id", | |
"brand": { | |
"$first": "$car_brand_id" | |
}, | |
"model": { | |
"$first": "$car_model_id" | |
}, | |
"sub_generation_id": { | |
"$first": "$car_model_sub_generation_id" | |
}, | |
"is_new": { | |
"$first": "$main_info.is_new" | |
}, | |
"is_swf": { | |
"$first": "$main_info.is_swf" | |
}, | |
"modifications": { | |
"$addToSet": { | |
"title": "$title", | |
"id": "$car_modification_id", | |
"price_min": "$price_min", | |
"price_max": "$price_max", | |
"price": { | |
"$add": ["$price_min", { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.83", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.83", 0] | |
}, | |
"$advanced_options_price.83", | |
0 | |
] | |
}, | |
0 | |
] | |
}, { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.122", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.122", 0] | |
}, | |
"$advanced_options_price.122", | |
0 | |
] | |
}, | |
0 | |
] | |
}, { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.74", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.74", 0] | |
}, | |
"$advanced_options_price.74", | |
0 | |
] | |
}, | |
0 | |
] | |
}, { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.337", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.337", 0] | |
}, | |
"$advanced_options_price.337", | |
0 | |
] | |
}, | |
0 | |
] | |
}] | |
}, | |
"options_with_prices": { | |
"PRICE": "$price_min", | |
"OP_83": { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.83", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.83", 0] | |
}, | |
"$advanced_options_price.83", | |
0 | |
] | |
}, | |
0 | |
] | |
}, | |
"OP_122": { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.122", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.122", 0] | |
}, | |
"$advanced_options_price.122", | |
0 | |
] | |
}, | |
0 | |
] | |
}, | |
"OP_74": { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.74", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.74", 0] | |
}, | |
"$advanced_options_price.74", | |
0 | |
] | |
}, | |
0 | |
] | |
}, | |
"OP_337": { | |
"$cond": [ | |
{ | |
"$ne": ["$advanced_options_price.337", []] | |
}, | |
{ | |
"$cond": [ | |
{ | |
"$gt": ["$advanced_options_price.337", 0] | |
}, | |
"$advanced_options_price.337", | |
0 | |
] | |
}, | |
0 | |
] | |
} | |
}, | |
"main_info": "$main_info", | |
"power": "$property_10", | |
"linked_options": "$linked_options" | |
} | |
}, | |
"modifications_count": { | |
"$sum": 1 | |
} | |
} | |
}, | |
{ | |
"$unwind": "$modifications" | |
}, | |
{ | |
"$match": { | |
"modifications.price": { | |
"$gte": 0, | |
"$lte": 4000000 | |
} | |
} | |
}, | |
{ | |
"$group": { | |
"_id": "$_id", | |
"modifications": { | |
"$addToSet": "$modifications" | |
}, | |
"brand": { | |
"$first": "$brand" | |
}, | |
"model": { | |
"$first": "$model" | |
}, | |
"sub_generation_id": { | |
"$first": "$sub_generation_id" | |
}, | |
"is_new": { | |
"$first": "$is_new" | |
}, | |
"is_swf": { | |
"$first": "$is_swf" | |
}, | |
"modifications_count": { | |
"$sum": 1 | |
} | |
} | |
}, | |
{ | |
"$sort": { | |
"modifications.price": 1 | |
} | |
}, | |
{ | |
"$skip": 0 | |
}, | |
{ | |
"$limit": 10 | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Quto\Common\Search; | |
class Result implements \ArrayAccess, \Iterator | |
{ | |
/** @var array */ | |
private $search_result, $pager, $last_search_params = array(); | |
/** @var int */ | |
private $key=0; | |
/** @var array линковка ТТХ */ | |
private $ttx_links = array(); | |
private $ttx_options_result_data = array( | |
// для опций а-ля ТТХ | |
183 => 'пневматическая', | |
131 => 'спортивная', | |
20 => 'с регулировкой жесткости', | |
// сами ТТХ | |
'engine_type' => array( | |
'benzin' => 'бензиновый', | |
'disel' => 'дизельный', | |
'hybride' => 'гибридный' | |
), | |
'control' => array( | |
'fr' => 'полный', | |
'f' => 'передний', | |
'r' => 'задний' | |
), | |
'transmission' => array( | |
'mex' => 'механическая', | |
'avt' => 'автоматическая', | |
'robot' => 'робот', | |
'variator' => 'вариатор' | |
) | |
); | |
/** | |
* @param array $search_result | |
* @param array $pager | |
* @param SearchCriteriaDefault $criteria | |
*/ | |
public function __construct(array $search_result, array $pager, SearchCriteriaDefault $criteria) | |
{ | |
$this->search_result = $search_result; | |
$this->pager = $pager; | |
$this->last_search_params = $criteria->getLastSearchParams(); | |
$this->ttx_links = $criteria->list_ttx_options_links(); | |
} | |
/** | |
* Кол-во результатов поиска (без среза) | |
* | |
* @return int | |
*/ | |
public function totalCount() | |
{ | |
return $this->pager['total_count']; | |
} | |
/** | |
* Размер среза (лимит записей при выводе) | |
* | |
* @return int | |
*/ | |
public function limit() | |
{ | |
return $this->pager['limit']; | |
} | |
/** | |
* Текущая страница (с учетом среза) | |
* | |
* @return int | |
*/ | |
public function currentPage() | |
{ | |
return $this->pager['page']; | |
} | |
/** | |
* Общее кол-во страниц с учетом среза | |
* | |
* @return int | |
*/ | |
public function totalPagesCount() | |
{ | |
return $this->pager['pages']; | |
} | |
/** | |
* Параметры поиска | |
* для JS фильтра | |
* | |
* @return array | |
*/ | |
public function filterJsParams() | |
{ | |
$filter = array(); | |
if (isset($this->last_search_params['option'])) | |
{ | |
$options = (array)$this->last_search_params['option']; | |
foreach ($options as $op) { | |
$filter[] = 'option-'.$op; | |
} | |
} | |
return $filter; | |
} | |
/** | |
* Параметры поиска | |
* для smarty-фильтра | |
* | |
* @return array | |
*/ | |
public function filterSmartyParams() | |
{ | |
$params = array( | |
'ttx' => false, | |
); | |
foreach ($this->last_search_params as $param => $value) | |
{ | |
if ('car_body_id' == $param) | |
{ | |
$param = 'body'; | |
$values = $value; | |
if (is_string($value)) { | |
$values = explode('+', $value); | |
} | |
$values = array_filter($values, function($v) { return (int)$v?true:false; }); | |
$values = array_values($values); | |
$value = array_fill_keys($values, true); | |
} | |
if ('car_class_id' == $param) | |
{ | |
$param = 'class'; | |
$values = $value; | |
if (is_string($value)) { | |
$values = explode('+', $value); | |
} | |
$values = array_map(function($v){ return str_replace('class_', '', $v); }, $values); | |
$values = array_filter($values, function($v) { return (int)$v?true:false; }); | |
$values = array_values($values); | |
$value = array_fill_keys($values, true); | |
} | |
if ('car_brand_id' == $param) { | |
$value = array_fill_keys((array)$value, true); | |
} | |
if ('car_model_id' == $param) { | |
$value = json_encode((array)$value); | |
} | |
// if ('transmission' == $param) { | |
// $value = array_fill_keys((array)$value, true); | |
// } | |
if ('countries' == $param) { | |
$value = array_fill_keys((array)$value, true); | |
} | |
if ('country_collected' == $param) { | |
$value = array_fill_keys((array)$value, true); | |
} | |
// TTX | |
if (array_key_exists($param, $this->ttx_links)) | |
{ | |
$p_key = $param; | |
if (strpos($param, '_min') || strpos($param, '_max')) { | |
$is_min = strpos($param, '_min')!==false; | |
$p_key = $is_min ? 'min' : 'max'; | |
} | |
$params['ttx'] = true; | |
$ttx_key = $this->ttx_links[$param]; | |
if (!array_key_exists($ttx_key, $params)) { | |
$params[$ttx_key] = array(); | |
} | |
$params[$ttx_key][$p_key] = $value; | |
$params[$ttx_key][$param] = $value; | |
} | |
if (array_key_exists($param, $this->ttx_options_result_data)) | |
{ | |
$value = array_fill_keys((array) $value, true); | |
foreach ($value as $v=>$_) { | |
if (array_key_exists($v, $this->ttx_options_result_data[$param])) { | |
$value[$v] = $this->ttx_options_result_data[$param][$v]; | |
} | |
} | |
} | |
if ('boost' == $param) { | |
// fix | |
if (is_array($value)) { $value = 100500; } | |
else { $value = intval($value); } | |
} | |
if ('option' == $param) | |
{ | |
$value = array_fill_keys((array) $value, false); | |
foreach ($this->ttx_options_result_data as $op_key=>$ttx_option) { | |
if (isset($value[$op_key])) { | |
$params['ttx'] = true; | |
$value[$op_key] = $ttx_option; | |
} | |
} | |
$value = array_filter($value, function($v) { return (bool) $v; }); | |
} | |
$params[$param] = $value; | |
} | |
// var_dump($params);exit; | |
return $params; | |
} | |
/** | |
* Жопа, конечно.... | |
* Но делать нечего - формирование строки запроса из параметров | |
* | |
* @param array $exclude | |
* @param array $include | |
* @return string | |
*/ | |
public function generateQueryString(array $exclude=array(), array $include=array()) | |
{ | |
$params = $this->last_search_params; | |
$result_string = '?'; | |
unset( | |
$params['page'], | |
$params['car_type_id'], | |
$params['search_price_to_usd'], | |
$params['search_price_to_euro'] | |
); | |
// exclude params | |
foreach ($exclude as $param) { | |
if(isset($params[$param])) { | |
unset($params[$param]); | |
} | |
} | |
// exclude if not include | |
if ($include) { | |
foreach ($params as $p => $pv) { | |
if (!in_array($p, $include)) { | |
unset($params[$p]); | |
} | |
} | |
} | |
if (isset($params['car_body_id'])) { | |
$params['car_body_id'] = str_replace(' ', '+', $params['car_body_id']); | |
} | |
if (isset($params['car_class_id'])) { | |
$params['car_class_id'] = str_replace(' ', '+', $params['car_class_id']); | |
} | |
$array_properties = array('option', 'transmission', 'countries', 'country_collected'); | |
foreach ($params as $o => $v) | |
{ | |
if (in_array($o, $array_properties)) {$v = (array)$v;} | |
if (is_array($v)) { | |
foreach ($v as $vv) { | |
$result_string .= "$o=$vv&"; | |
} | |
} else { | |
$result_string .= "$o=$v&"; | |
} | |
} | |
if ($result_string == '?') { | |
$result_string = ''; | |
} | |
return $result_string; | |
} | |
/** | |
* Генерация результативного массива по запросу | |
* Так как существует необходимость дергать данные | |
* в одном и том же формате в разных местах, | |
* включая json api - собирается вся эта история | |
* в отдельном методе | |
* | |
* @return array | |
*/ | |
public function generateSearchResultArrayFromResultData() | |
{ | |
$elements = array(); | |
foreach ($this->search_result as $item) | |
{ | |
$element = array( | |
'id' => $item['sub_generation_id'], | |
'is_new' => $item['is_new'], | |
'is_swf' => $item['is_swf'], | |
'title' => '', | |
'brand_title' => '', | |
'model_sub_title' => '', | |
's_url' => '', | |
'image' => '', | |
'modifications' => array() | |
); | |
foreach ($item['modifications'] as $modification) | |
{ | |
$element['title'] = $modification['main_info']['brand_model_title']; | |
$element['brand_title'] = $modification['main_info']['brand']; | |
$element['model_sub_title'] = $modification['main_info']['model_sub_title']; | |
$element['s_url'] = $modification['main_info']['generation_url']; | |
if ($modification['main_info']['image_hash']) { | |
$element['image'] = $modification['main_info']['image_hash']; | |
} | |
$price_options = 0; | |
$modification_options = array(); | |
foreach ($modification['options_with_prices'] as $op=>$opv) { | |
if ($op != 'PRICE') { | |
$price_options += $opv; | |
if (intval($opv)) | |
{ | |
$option_current = (int)preg_replace('|[^\d]+|ius', '', $op); | |
$modification_options[] = array( | |
'id' => $modification['linked_options'][$option_current] | |
); | |
} | |
} | |
} | |
$element['modifications'][] = array( | |
'id' => $modification['id'], | |
#fixed-mf[9900]: дублирование в выдаче | |
'title' => $modification['main_info']['modification_title'], //$modification['title'], | |
// 'completion_title' => $modification['main_info']['modification_title'], | |
'price' => $modification['price'], | |
'price_special' => null, | |
'fuel' => $modification['main_info']['fuel'], | |
'control' => $modification['main_info']['gear'], | |
'power' => $modification['main_info']['horsepower'], | |
's_url' => $modification['main_info']['modification_url'], | |
'url' => $modification['main_info']['url'], | |
'price_options' => $price_options, | |
'options' => $modification_options | |
); | |
} | |
$elements[] = $element; | |
} | |
// var_dump($elements);exit; | |
return $elements; | |
} | |
public function filterSocial() | |
{ | |
$data = array( | |
1 => array(1000, 1001), | |
2 => range(1002, 1005), | |
3 => range(1006, 1009), | |
4 => range(1010, 1015), | |
); | |
$result = array( | |
1 => 0, | |
2 => 0, | |
3 => 0, | |
4 => 0 | |
); | |
$options = isset($this->last_search_params['option']) ? (array) $this->last_search_params['option'] : array(); | |
// вот реально... что в голову пришло.. | |
// по хорошему - переписать бы.... | |
foreach ($options as $op) { | |
foreach ($data as $k => $a) { | |
if (in_array($op, $a)) { | |
$result[$k] = (int) $op; | |
} | |
} | |
} | |
return $result; | |
} | |
/** | |
* Вхерачиваем в смарти результат | |
* | |
* @param \Smarty $smarty | |
*/ | |
public function assignToSmarty(\Smarty $smarty) | |
{ | |
$elements = $this->generateSearchResultArrayFromResultData(); | |
$smarty->assign ('search_result', $elements); | |
$smarty->assign ('page_iteration', ($this->currentPage()-1)*$this->limit()+1); | |
$smarty->assign ('page_total_result_count', $this->totalCount()); | |
} | |
# ---- // IMPLEMENTATION | |
/** | |
* @param mixed $offset | |
* @return bool | |
*/ | |
public function offsetExists($offset) | |
{ | |
return isset($this->search_result[$offset]); | |
} | |
/** | |
* @param mixed $offset | |
* @return mixed|null | |
*/ | |
public function offsetGet($offset) | |
{ | |
return isset($this->search_result[$offset]) ? $this->search_result[$offset] : null; | |
} | |
/** | |
* @param mixed $offset | |
* @param mixed $value | |
* @throws \Exception | |
*/ | |
public function offsetSet($offset, $value) | |
{ | |
throw new \Exception('Unable to set search result item'); | |
} | |
/** | |
* @param mixed $offset | |
* @throws \Exception | |
*/ | |
public function offsetUnset($offset) | |
{ | |
throw new \Exception('Unable to unset search result item'); | |
} | |
/** | |
* @return mixed | |
*/ | |
public function current() | |
{ | |
return $this->search_result[$this->key]; | |
} | |
public function next() | |
{ | |
$this->key += 1; | |
} | |
/** | |
* @return int|mixed | |
*/ | |
public function key() | |
{ | |
return $this->key; | |
} | |
/** | |
* @return bool | |
*/ | |
public function valid() | |
{ | |
return isset($this->search_result[$this->key]); | |
} | |
public function rewind() | |
{ | |
$this->key = 0; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Quto\Common\Search; | |
class Search | |
{ | |
/** @var SearchCriteriaDefault */ | |
private $criteria; | |
public function __construct(SearchCriteriaDefault $criteria) | |
{ | |
$this->criteria = $criteria; | |
} | |
/** | |
* Получение кол-ва эл-тов выборки | |
* | |
* @param $collection | |
* @return int | |
* @throws \Exception | |
*/ | |
public function count($collection) | |
{ | |
if ( !($collection instanceof \MongoCollection) | |
&& !($collection instanceof \MongoPinba\MongoCollection) | |
) { | |
throw new \Exception('Collection must be instance of MongoCollection'); | |
} | |
$result = $collection->aggregate($this->criteria->count()); | |
if (isset($result['result']) && $result['result']) { | |
return (int) $result['result'][0]['count']; | |
} | |
return 0; | |
} | |
/** | |
* Получение результатов | |
* | |
* @param \MongoCollection $collection | |
* @param bool $use_custom_sort | |
* @return array | |
* @throws \Exception | |
*/ | |
public function result($collection, $use_custom_sort=false) | |
{ | |
if ( !($collection instanceof \MongoCollection) | |
&& !($collection instanceof \MongoPinba\MongoCollection) | |
) { | |
throw new \Exception('Collection must be instance of MongoCollection'); | |
} | |
$result = $collection->aggregate($this->criteria->result()); | |
if (isset($result['result'])) | |
{ | |
if ($use_custom_sort) { | |
return $this->_sort($result['result'], $this->criteria->getSortOrder()); | |
} | |
return $result['result']; | |
} | |
throw new \Exception(json_encode($result)); | |
} | |
/** | |
* Так как монга не совсем нормально некоорые вещи сортирует | |
* вынужденная мера - своя сортировка | |
* | |
* @param array $result | |
* @param $order | |
* | |
* @return array | |
*/ | |
private function _sort(array $result, $order) | |
{ | |
$sort_function = function($a, $b) use($order) | |
{ | |
$direction_up = 0; | |
$direction_down = 0; | |
$key = null; | |
switch ($order) | |
{ | |
case SearchCriteriaDefault::ORDER_PRICE_ASC: | |
$key = 'price'; | |
$direction_down = -1; | |
$direction_up = 1; | |
break; | |
case SearchCriteriaDefault::ORDER_PRICE_DESC: | |
$key = 'price'; | |
$direction_down = 1; | |
$direction_up = -1; | |
break; | |
case SearchCriteriaDefault::ORDER_POWER_ASC: | |
$key = 'power'; | |
$direction_down = -1; | |
$direction_up = 1; | |
break; | |
case SearchCriteriaDefault::ORDER_POWER_DESC: | |
$key = 'power'; | |
$direction_down = 1; | |
$direction_up = -1; | |
break; | |
case SearchCriteriaDefault::ORDER_BM_ASC: | |
$key = 'brand_model'; | |
$direction_down = -1; | |
$direction_up = 1; | |
break; | |
case SearchCriteriaDefault::ORDER_BM_DESC: | |
$key = 'brand_model'; | |
$direction_down = 1; | |
$direction_up = -1; | |
break; | |
} | |
if (!$key) { | |
return 0; | |
} | |
if ('brand_model' == $key) { | |
return strcmp($a['title'], $b['title']) < 0 ? $direction_down : $direction_up; | |
} | |
if ($a[$key]===$b[$key]) {return 0;} | |
return $a[$key] < $b[$key] ? $direction_down : $direction_up; | |
}; | |
foreach ($result as $k=>$item) { | |
uasort($result[$k]['modifications'],$sort_function); | |
} | |
return $result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Quto\Common\Search; | |
class SearchCriteriaBuilder | |
{ | |
const SORT_DESC = -1; | |
const SORT_ASC = 1; | |
private $limit = 0; | |
private $skip = 0; | |
private $match = array(); | |
private $group = array(); | |
private $project = array(); | |
private $sort = array(); | |
private $sort_before = array(); | |
private $pipelines = array(); | |
private $unwind = ''; | |
private $having = array(); | |
private $finalize_group = array(); | |
public function prependPipeline(array $pipeline) | |
{ | |
array_unshift($this->pipelines, $pipeline); | |
} | |
public function setFinalizeGroup(array $group) | |
{ | |
$this->finalize_group = $group; | |
} | |
public function appendPipeline(array $pipeline) | |
{ | |
$this->pipelines[] = $pipeline; | |
} | |
public function setUnwind($unwind) | |
{ | |
$this->unwind = $unwind; | |
} | |
public function getLimit() | |
{ | |
return $this->limit; | |
} | |
public function getOffset() | |
{ | |
return $this->skip; | |
} | |
public function setProject(array $project) | |
{ | |
$this->project = $project; | |
} | |
public function setMatch(array $match) | |
{ | |
$this->match = $match; | |
} | |
public function setGroup(array $group) | |
{ | |
$this->group = $group; | |
} | |
public function setLimit($limit) | |
{ | |
$this->limit = (int) $limit; | |
} | |
public function setOffset($offset) | |
{ | |
$this->skip = (int) $offset; | |
} | |
public function setSort(array $sort) | |
{ | |
$this->sort = $sort; | |
} | |
public function addMatch($key, array $value) | |
{ | |
$this->match[$key] = $value; | |
} | |
public function addSort($key, $direction) | |
{ | |
$this->sort[$key] = (int) $direction; | |
} | |
public function addSortBefore($key, $direction) | |
{ | |
$this->sort_before[$key] = (int) $direction; | |
} | |
/** | |
* @return array | |
*/ | |
public function getPipelines() | |
{ | |
$pipelines = $this->pipelines; | |
$this->pipelines = array(); | |
return $pipelines; | |
} | |
/** | |
* Aggregation count pipeline | |
* @return array | |
*/ | |
public function count() | |
{ | |
$this->appendPipeline(array('$match'=>$this->match)); | |
$this->appendPipeline(array('$group'=>$this->group)); | |
if ($this->unwind) { | |
$this->appendPipeline(array('$unwind'=>$this->unwind)); | |
} | |
if ($this->having) { | |
$this->appendPipeline(array('$match'=>$this->having)); | |
} | |
if ($this->finalize_group) { | |
$this->appendPipeline(array('$group'=>$this->finalize_group)); | |
} | |
$this->appendPipeline(array( | |
'$group' => array( | |
'_id' => null, | |
'count' => array('$sum'=>1), | |
) | |
)); | |
$this->appendPipeline(array('$skip' => 0)); | |
$this->appendPipeline(array('$limit' => 1)); | |
return $this->getPipelines(); | |
} | |
public function setHaving(array $having) | |
{ | |
$this->having = $having; | |
} | |
/** | |
* Aggregation search pipeline | |
* @return array | |
*/ | |
public function result() | |
{ | |
$this->appendPipeline(array('$match'=>$this->match)); | |
if ($this->sort_before) { | |
$this->appendPipeline(array('$sort' => $this->sort_before)); | |
} | |
$this->appendPipeline(array('$group'=>$this->group)); | |
if ($this->project) { | |
$this->appendPipeline(array('$project' => $this->project)); | |
} | |
if ($this->unwind) { | |
$this->appendPipeline(array('$unwind'=>$this->unwind)); | |
} | |
if ($this->having) { | |
$this->appendPipeline(array('$match'=>$this->having)); | |
} | |
if ($this->finalize_group) { | |
$this->appendPipeline(array('$group'=>$this->finalize_group)); | |
} | |
if ($this->sort) { | |
$this->appendPipeline(array('$sort' => $this->sort)); | |
} | |
if ($this->limit) { | |
$this->appendPipeline(array('$skip' => $this->skip)); | |
$this->appendPipeline(array('$limit' => $this->limit)); | |
} | |
return $this->getPipelines(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Quto\Common\Search; | |
use \Quto\Fetcher_Car_Property; | |
class SearchCriteriaDefault | |
{ | |
const ORDER_PRICE_ASC = 'price_asc'; | |
const ORDER_PRICE_DESC = 'price_desc'; | |
const ORDER_POWER_ASC = 'power_asc'; | |
const ORDER_POWER_DESC = 'power_desc'; | |
const ORDER_BM_ASC = 'brand_model_asc'; | |
const ORDER_BM_DESC = 'brand_model_desc'; | |
const LIMIT_PER_PAGE = 10; | |
const CAR_TYPE_LCV = 2; | |
const CAR_TYPE_CAR = 1; | |
/** @var SearchCriteriaBuilder */ | |
private $builder; | |
/** @var int Кол-во элементов поиска */ | |
private $limit_per_page = 0; | |
/** @var array список того что передается через OR */ | |
private $or_list = array( | |
array(324, 326, 328, 329, 331), // салон ткань там или кожа | |
array(72, 73, 74), // климаты | |
array(183, 171), // подвеска | |
array(144, 149), // мультируль | |
array(85, 116, 198), // парктроники | |
array(84, 116, 198), // парктроники | |
); | |
/** @var string sort order */ | |
private $sort_order=SearchCriteriaDefault::ORDER_PRICE_ASC; | |
/** @var array */ | |
private $last_search_params = array(); | |
/** | |
* @param SearchCriteriaBuilder $builder | |
*/ | |
public function __construct(SearchCriteriaBuilder $builder) | |
{ | |
$this->builder = $builder; | |
// default | |
$this->limit_per_page = static::LIMIT_PER_PAGE; | |
} | |
/** | |
* @param $lpp | |
*/ | |
public function setLimitPerPage($lpp) | |
{ | |
$this->limit_per_page = (int) $lpp; | |
} | |
/** | |
* @return array | |
*/ | |
public function getLastSearchParams() | |
{ | |
return $this->last_search_params; | |
} | |
/** | |
* @param array $params | |
* @return array | |
*/ | |
private function filter_params(array $params) | |
{ | |
return array_filter($params, function($param) { | |
if (is_numeric($param)) { | |
return true; | |
} | |
if (is_string($param) && empty($param)) { | |
return null; | |
} | |
return true; | |
}); | |
} | |
private function filter_array_param($param) | |
{ | |
if (is_array($param)) { | |
return $param[0]; | |
} | |
return $param; | |
} | |
/** | |
* Магический метод. | |
* Формирование запроса в БД исходя из параметров в query_string | |
* | |
* @param array $params | |
*/ | |
public function fillWithParams(array $params) | |
{ | |
$params = $this->filter_params($params); | |
// sort must have | |
if (!isset($params['order'])) { $params['order'] = $this->sort_order; } | |
else {$this->sort_order = $params['order'];} | |
// just save it | |
$this->last_search_params = $params; | |
$b = $this->getBuilder(); | |
$match = array( | |
'$and' => array(), | |
); | |
# ----- // тип авто: LCV или CAR | |
if (array_key_exists('car_type_id', $params)) { | |
$match['$and'][] = array('car_type_id'=>intval($params['car_type_id'])); | |
} | |
# ----- // если по modification_id | |
if (array_key_exists('mids', $params)) | |
{ | |
$m_ids = array_map(function($v){ return intval($v); }, (array)$params['mids']); | |
if ($m_ids) { | |
$match['$and'][] = array('car_modification_id'=>array('$in'=>array_values($m_ids))); | |
} | |
} | |
# ----- // если по sub_generation_id | |
if (array_key_exists('ids', $params)) | |
{ | |
$ids = array_map(function($v){ return intval($v); }, (array)$params['ids']); | |
if ($ids) { | |
$match['$and'][] = array('car_model_sub_generation_id'=>array('$in'=>array_values($ids))); | |
} | |
} | |
# ----- // обработка ценового диапазона | |
$having = array(); | |
if (array_key_exists('price_min', $params)) | |
{ | |
$match['$and'][] = array('price_min' => array('$gte'=>(int)$params['price_min'])); | |
$having['$gte'] = (int)$params['price_min']; | |
} | |
if (array_key_exists('price_max', $params)) | |
{ | |
$match['$and'][] = array('price_min' => array('$lte'=>(int)$params['price_max'])); | |
$having['$lte'] = (int)$params['price_max']; | |
$having['$lte'] = (int)$params['price_max']; | |
} | |
// дополнительно фильтруем результат | |
// первоначально идет выборка по дельте цены | |
// второй фильтр уже отвечает за отсечку после установки опций | |
if (count($having) > 0) { | |
$b->setHaving(array('modifications.price'=>$having)); | |
} | |
# ----- // кузов | |
if (array_key_exists('car_body_id', $params)) | |
{ | |
/** кароче. суть в том что оооочень криво сделана штука в query_string... */ | |
if (is_string($params['car_body_id'])) { | |
$op_slice = strpos($params['car_body_id'], '+')===false ? '%20' : '+'; | |
$body_ids = explode($op_slice, $params['car_body_id']); | |
} else { | |
$body_ids = $params['car_body_id']; | |
} | |
$body_ids = array_filter($body_ids, function ($v) { | |
$v = intval($v); | |
return $v ?: null; | |
}); | |
$body_ids = array_map(function($v){ return intval($v); }, $body_ids); | |
if ($body_ids) { | |
$match['$and'][] = array('car_body_id'=>array('$in'=>array_values($body_ids))); | |
} | |
} | |
# ----- // класс | |
if (array_key_exists('car_class_id', $params)) | |
{ | |
/** кароче. суть в том что оооочень криво сделана штука в query_string... */ | |
if (is_string($params['car_class_id'])) { | |
$op_slice = strpos($params['car_class_id'], '+')===false ? '%20' : '+'; | |
$class_ids = explode($op_slice, $params['car_class_id']); | |
} else { | |
$class_ids = $params['car_class_id']; | |
} | |
$class_ids = array_filter($class_ids, function ($v) { | |
return strpos($v, 'class_')===0 ? $v : null; | |
}); | |
$class_ids = array_map(function($v){ return intval(str_replace('class_', '', $v)); }, $class_ids); | |
if ($class_ids) { | |
$match['$and'][] = array('car_class_id'=>array('$in'=>array_values($class_ids))); | |
} | |
} | |
# ----- // модель и бренд | |
if (array_key_exists('car_brand_id', $params)) | |
{ | |
$params['car_brand_id'] = (array) $params['car_brand_id']; | |
$params['car_brand_id'] = array_map(function($v){ return intval($v); }, $params['car_brand_id']); | |
} | |
if (array_key_exists('car_model_id', $params)) | |
{ | |
$params['car_model_id'] = (array) $params['car_model_id']; | |
$params['car_model_id'] = array_map(function($v){ return intval($v); }, $params['car_model_id']); | |
} | |
# если выбраны и бренд и модельки | |
if (isset($params['car_brand_id']) && isset($params['car_model_id'])) | |
{ | |
# собственно тут уже находится та самая магия | |
# дело в том что у нас не передаются в запрос | |
# связки моделей с брендами, но у нас есть возможность | |
# на этапе индексации влить в коллекцию все возможные модели | |
# для конкретного бренда. это такого рода "чит" | |
# идем от обратного. | |
# | |
# если выбран бренд и модель, сначала проверяем на вхождение | |
# брендов и НЕ ВХОЖДЕНИЕ выбранных моделей в возможные для бренда | |
# (это на случай если у одного бренда выбраны модели а у второго нет) | |
# после чего уже просто ищим вхождение моделей | |
# у нас не может один ид модельки принадлежать двум брендам | |
# PROFIT !!! | |
$match['$and'][] = array( | |
'$or' => array( | |
array( | |
# условия для выборки отдельного бренда без моделей | |
# прокатит только в том случае если модели переданы | |
# но к конкретному бренду они не имеют отношения | |
'$and'=> array( | |
array('car_brand_id'=>array('$in'=>$params['car_brand_id'])), | |
array('brand_models_available'=>array('$nin'=>$params['car_model_id'])), | |
), | |
), | |
# так как модели без бренда не бывает и ид модельки уникален | |
# тут уже выборка по переданным моделям | |
array('car_model_id'=>array('$in'=>$params['car_model_id'])) | |
), | |
); | |
} | |
elseif (isset($params['car_brand_id'])) { | |
$match['$and'][] = array('car_brand_id'=>array('$in'=>$params['car_brand_id'])); | |
} | |
// не уверен, что такое в принципе бывает | |
// но мало ли =) | |
elseif (isset($params['car_model_id'])) { | |
$match['$and'][] = array('car_model_id'=>array('$in'=>$params['car_model_id'])); | |
} | |
# ----- // ограничения по ТТХ | |
$properties = $this->list_ttx_options_from_params($params); | |
if ($properties) { | |
$match['$and'][] = $properties; | |
} | |
# ----- // переборо опций и формирование их выборки | |
if (array_key_exists('option', $params)) | |
{ | |
$params['option'] = (array) $params['option']; | |
$params['option'] = array_map(function($v){ return intval($v); }, $params['option']); | |
$params['option'] = array_filter($params['option'], function($v) { return intval($v) > 0; }); | |
$params['option'] = array_fill_keys($params['option'], true); | |
$params['option'] = array_keys($params['option']); | |
// var_dump($params['option']);exit; | |
$or = array(); | |
$all = array(); | |
foreach ($params['option'] as $option) | |
{ | |
foreach ($this->or_list as $__i=>$__v) { | |
if (in_array($option, $this->or_list[$__i])) { | |
$or[] = $option; | |
continue 2; | |
} | |
} | |
$all[] = $option; | |
} | |
if ($or) { | |
$match['$and'][] = array('base_options' => array('$in'=>$or)); | |
} | |
if ($all) { | |
$match['$and'][] = array('base_options'=>array('$all'=>$all)); | |
} | |
foreach ($params['option'] as $option) | |
{ | |
$nin = array_diff($params['option'], array($option)); | |
if ($nin) { | |
$match['$and'][] = array('ignore_options.'.$option => array('$nin'=>array_values($nin))); | |
} | |
} | |
} | |
# ----- // сортировка | |
switch ($this->sort_order) | |
{ | |
case self::ORDER_PRICE_ASC: | |
$b->addSort('modifications.price', SearchCriteriaBuilder::SORT_ASC); | |
break; | |
case self::ORDER_PRICE_DESC: | |
$b->addSort('modifications.price', SearchCriteriaBuilder::SORT_DESC); | |
break; | |
case self::ORDER_POWER_ASC: | |
$b->addSort('modifications.power', SearchCriteriaBuilder::SORT_ASC); | |
break; | |
case self::ORDER_POWER_DESC: | |
$b->addSort('modifications.power', SearchCriteriaBuilder::SORT_DESC); | |
break; | |
case self::ORDER_BM_ASC: | |
$b->addSort('modifications.title', SearchCriteriaBuilder::SORT_ASC); | |
break; | |
case self::ORDER_BM_DESC: | |
$b->addSort('modifications.title', SearchCriteriaBuilder::SORT_DESC); | |
break; | |
} | |
$b->setMatch($match); | |
# ----- // лимит | |
$page = isset($params['page']) ? $params['page'] : 1; | |
$offset = ($page-1)*$this->limit_per_page; | |
$b->setLimit($this->limit_per_page); | |
$b->setOffset($offset); | |
# ----- // после того как все отфильтровано - процессинг группы | |
$this->_process_group($params, count($having)>0); | |
} | |
private function _process_group(array $params, $use_having=false) | |
{ | |
$sum_array = array( | |
'PRICE' => '$price_min', | |
); | |
if (isset($params['option'])) | |
{ | |
# (!) WARNING: тут собирается цена. | |
# как для выборки блока с ценами опций | |
# так и для формирования конечной цены модификации | |
# в зависимости от поставленых опций | |
$params['option'] = (array) $params['option']; | |
foreach ($params['option'] as $op) { | |
$sum_array['OP_'.$op] = array( | |
'$cond'=>array( | |
array('$ne' => array('$advanced_options_price.'.$op, array())), | |
array('$cond'=>array( | |
array('$gt'=>array('$advanced_options_price.'.$op, 0)), | |
'$advanced_options_price.'.$op, | |
0 | |
)), | |
0 | |
) | |
); | |
} | |
} | |
// group | |
$group = array( | |
'_id' => '$car_model_sub_generation_id', | |
"brand" => array('$first'=>'$car_brand_id'), | |
"model" => array('$first'=>'$car_model_id'), | |
"sub_generation_id" => array('$first'=>'$car_model_sub_generation_id'), | |
"is_new" => array('$first'=>'$main_info.is_new'), | |
"is_swf" => array('$first'=>'$main_info.is_swf'), | |
"modifications" => array('$addToSet' => array( | |
'title' => '$title', | |
'id' => '$car_modification_id', | |
'price_min' => '$price_min', | |
'price_max' => '$price_max', | |
'price' => array('$add'=>array_values($sum_array)), | |
'options_with_prices' => $sum_array, | |
'main_info' => '$main_info', | |
'power' => '$property_'.Fetcher_Car_Property::HORSE_POWER_ID, | |
'linked_options' => '$linked_options', | |
)), | |
"modifications_count" => array('$sum'=>1), | |
); | |
$this->builder->setGroup($group); | |
if ($use_having) | |
{ | |
$this->builder->setUnwind('$modifications'); | |
$final = array( | |
"_id" => '$_id', | |
"modifications" => array('$addToSet' => '$modifications'), | |
'brand' => array('$first' => '$brand'), | |
'model' => array('$first' => '$model'), | |
'sub_generation_id' => array('$first' => '$sub_generation_id'), | |
'is_new' => array('$first' => '$is_new'), | |
'is_swf' => array('$first' => '$is_swf'), | |
'modifications_count' => array('$sum' => 1), | |
); | |
$this->builder->setFinalizeGroup($final); | |
} | |
} | |
/** | |
* @return SearchCriteriaBuilder | |
*/ | |
public function getBuilder() | |
{ | |
return $this->builder; | |
} | |
public function getSortOrder() | |
{ | |
return $this->sort_order; | |
} | |
public function count() | |
{ | |
return $this->builder->count(); | |
} | |
public function result() | |
{ | |
return $this->builder->result(); | |
} | |
/** | |
* Выборка всех ТТХ параметров | |
* Формирование запроса в монгу | |
* | |
* @param array $params | |
* @return array | |
*/ | |
private function list_ttx_options_from_params(array $params) | |
{ | |
$result = array(); | |
foreach ($params as $key=>$value) | |
{ | |
if ($option = $this->read_ttx_option($key)) | |
{ | |
if (in_array($key, array('country_collected', 'countries', 'transmission', 'engine_type', 'control'))) | |
{ | |
$result[$option] = array( | |
'$in' => array_values((array) $value) | |
); | |
} | |
elseif (strpos($key,'_min') !== false) | |
{ | |
$value = $this->filter_array_param($value); | |
if (in_array($option, | |
array('property_8', 'property_39', 'property_27', 'property_28', 'property_29')) ) { | |
$value = $value*1000; | |
} | |
if ('property_8'==$option) { | |
# remove 3% of value | |
$value = $value * .97; | |
} | |
if (in_array($option, array('property_61', 'property_39'))) { $option .= '_min'; } | |
if (isset($result[$option])) { | |
$result[$option]['$gte'] = (int) $value; | |
} else { | |
$result[$option] = array('$gte'=>(int) $value); | |
} | |
} | |
elseif (strpos($key,'_max') !== false) | |
{ | |
$value = $this->filter_array_param($value); | |
if (in_array($option, | |
array('property_8', 'property_39', 'property_27', 'property_28', 'property_29')) ) { | |
$value = $value*1000; | |
} | |
if ('property_8'==$option) { | |
# + 3% of power | |
$value = $value + ($value - $value * .97); | |
} | |
if (in_array($option, array('property_61', 'property_39'))) { $option .= '_max'; } | |
if (isset($result[$option])) { | |
$result[$option]['$lte'] = (int) $value; | |
} else { | |
$result[$option] = array('$lte'=>(int) $value); | |
} | |
} | |
else | |
{ | |
// clearence | |
if (in_array($option, array('property_34')) ) { | |
$value = array('$gte'=>$value*10); | |
} | |
if (in_array($key, array('number_of_seats'))) { | |
$value = array('$gte'=>7); | |
$option = 'property_61_min'; | |
} | |
$result[$option] = is_numeric($value) ? (int)$value : $value; | |
} | |
#fixed-mf[9900]: суть в том что если мы не знаем сколько и есть ли вообще описание | |
# конкретного параметра - необходимо его исключить | |
# так как в противном случае показываются авто которые показывать нельзя | |
# исходя из параметров в фильтре | |
if (is_array($result[$option])) { | |
#todo-mf: надо как-то по-умнее переписать.. костыльненько это... | |
$result[$option]['$ne'] = 0; | |
} | |
} | |
} | |
// var_dump($result);exit; | |
return $result; | |
} | |
/** | |
* Получение опции из поискового параметра и приведение ее к свойству в БД | |
* @param $option | |
* @return null|string | |
*/ | |
private function read_ttx_option($option) | |
{ | |
$options = $this->list_ttx_options_links(); | |
if (isset($options[$option])) { | |
return 'property_'.$options[$option]; | |
} | |
return null; | |
} | |
/** | |
* Линковка ТТХ | |
* | |
* [get_key=>[mongo_key]] | |
* | |
* @return array | |
*/ | |
public function list_ttx_options_links() | |
{ | |
return array( | |
'country_collected' => Fetcher_Car_Property::MAID_IN, | |
'control' => Fetcher_Car_Property::GEAR_TYPE_ID, | |
'transmission' => Fetcher_Car_Property::TRANSMISSION_ID, | |
'engine_type' => Fetcher_Car_Property::ENGINE_TYPE_ID, | |
'countries' => Fetcher_Car_Property::COUNTRY_ID, | |
'volume_min' => Fetcher_Car_Property::DISPLACEMENT_ID, | |
'volume_max' => Fetcher_Car_Property::DISPLACEMENT_ID, | |
'power_min' => Fetcher_Car_Property::HORSE_POWER_ID, | |
'power_max' => Fetcher_Car_Property::HORSE_POWER_ID, | |
'razgon_min' => Fetcher_Car_Property::RAZGON_ID, | |
'razgon_max' => Fetcher_Car_Property::RAZGON_ID, | |
'rashod_min' => Fetcher_Car_Property::RASCHOD_ID, | |
'rashod_max' => Fetcher_Car_Property::RASCHOD_ID, | |
'number_of_seats' => Fetcher_Car_Property::NUMBER_OF_SEATS_ID, | |
'boost' => Fetcher_Car_Property::BOOST_ID, | |
'clearance' => Fetcher_Car_Property::CLEARANCE_ID, | |
'number_places_min' => Fetcher_Car_Property::NUMBER_OF_SEATS_ID, | |
'number_places_max' => Fetcher_Car_Property::NUMBER_OF_SEATS_ID, | |
'dimensions_cargo_length_min' => Fetcher_Car_Property::DIMENSIONS_LENGTH_ID, | |
'dimensions_cargo_length_max' => Fetcher_Car_Property::DIMENSIONS_LENGTH_ID, | |
'dimensions_cargo_width_min' => Fetcher_Car_Property::DIMENSIONS_WIDTH_ID, | |
'dimensions_cargo_width_max' => Fetcher_Car_Property::DIMENSIONS_WIDTH_ID, | |
'dimensions_cargo_height_min' => Fetcher_Car_Property::DIMENSIONS_HEIGHT_ID, | |
'dimensions_cargo_height_max' => Fetcher_Car_Property::DIMENSIONS_HEIGHT_ID, | |
'dimensions_cargo_volume_min' => Fetcher_Car_Property::DIMENSIONS_VOLUME_ID, | |
'dimensions_cargo_volume_max' => Fetcher_Car_Property::DIMENSIONS_VOLUME_ID, | |
'capacity_min' => Fetcher_Car_Property::CAPACITY_ID, | |
'capacity_max' => Fetcher_Car_Property::CAPACITY_ID, | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Quto\Common\Search; | |
use \Quto\Common_Bootstrap; | |
final class SearchHelper | |
{ | |
const SEARCH_COLLECTION_NAME = 'new_search_collection'; | |
/** @var SearchCriteriaBuilder */ | |
private $builder; | |
/** @var SearchCriteriaDefault */ | |
private $criteria; | |
/** @var Search */ | |
private $search; | |
private $mongo_collection; | |
/** | |
* @return Search | |
*/ | |
public function getSearchObject() | |
{ | |
return $this->search; | |
} | |
/** | |
* @return SearchCriteriaDefault | |
*/ | |
public function getCriteriaObject() | |
{ | |
return $this->criteria; | |
} | |
/** | |
* @return SearchCriteriaBuilder | |
*/ | |
public function getBuilderObject() | |
{ | |
return $this->builder; | |
} | |
/** | |
* @param $limit | |
*/ | |
public function setLimit($limit) | |
{ | |
$this->getCriteriaObject()->setLimitPerPage($limit); | |
} | |
/** | |
* Именованый конструктор | |
* | |
* @param \MongoCollection $collection | |
* @throws \Exception | |
* @return SearchHelper | |
*/ | |
public static function createWithCollection($collection) | |
{ | |
if ( !($collection instanceof \MongoCollection) | |
&& !($collection instanceof \MongoPinba\MongoCollection) | |
) { | |
throw new \Exception('Collection must be instance of MongoCollection'); | |
} | |
$helper = new self(); | |
$helper->builder = new SearchCriteriaBuilder(); | |
$helper->criteria = new SearchCriteriaDefault($helper->builder); | |
$helper->search = new Search($helper->criteria); | |
$helper->mongo_collection = $collection; | |
return $helper; | |
} | |
/** | |
* Чит-инит =) | |
* | |
* @return SearchHelper | |
*/ | |
public static function cheatInit() | |
{ | |
/** @var \MongoDB $mongo */ | |
$mongo = Common_Bootstrap::getMongoDb(); | |
$collection = $mongo->selectCollection(self::SEARCH_COLLECTION_NAME); | |
return self::createWithCollection($collection); | |
} | |
/** | |
* Поиск | |
* @param array $filter | |
* @param bool $sort | |
* @return mixed | |
*/ | |
public function find(array $filter, $sort=false) | |
{ | |
$this->getCriteriaObject()->fillWithParams($filter); | |
return $this->getSearchObject()->result($this->mongo_collection, $sort); | |
} | |
/** | |
* Кол-во элементов | |
* | |
* @param array $filter | |
* @return int | |
*/ | |
public function count(array $filter) | |
{ | |
$this->getCriteriaObject()->fillWithParams($filter); | |
return $this->getSearchObject()->count($this->mongo_collection); | |
} | |
/** | |
* Возвращает массив для пагинации | |
* | |
* @param array $filter | |
* @return array | |
*/ | |
public function pager(array $filter) | |
{ | |
$count = $this->count($filter); | |
$limit = $this->getBuilderObject()->getLimit(); | |
$offset = $this->getBuilderObject()->getOffset(); | |
return array( | |
'pages' => ceil($count/$limit), | |
'page' => ceil($offset/$limit)+1, | |
'total_count' => $count, | |
'limit' => $limit | |
); | |
} | |
/** | |
* Фасад. | |
* Ищет сразу пагинашку + результат | |
* | |
* @param array $filter | |
* @param bool $use_custom_sort | |
* @return Result | |
*/ | |
public function findResult(array $filter, $use_custom_sort=false) | |
{ | |
// print $this->getCriteriaFindJson($filter);exit; | |
$pager = $this->pager($filter); | |
$result = $this->find($filter, $use_custom_sort); | |
return new Result($result, $pager, $this->criteria); | |
} | |
/** | |
* JSON критерия запроса | |
* | |
* @param array $filter | |
* @return string | |
*/ | |
public function getCriteriaFindJson(array $filter) | |
{ | |
$this->getCriteriaObject()->fillWithParams($filter); | |
return json_encode($this->getCriteriaObject()->result()); | |
} | |
/** | |
* @return QueryLog | |
*/ | |
public function getLogger() | |
{ | |
static $logger; | |
if (!$logger) { | |
$logger = QueryLog::createWithCollection($this->mongo_collection); | |
} | |
return $logger; | |
} | |
/** | |
* Фасад | |
* | |
* @param array $filter | |
* @param array $advanced | |
*/ | |
public function logQuery(array $filter, array $advanced=array()) | |
{ | |
$this->getLogger()->log($filter, $advanced); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment