PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/system/modules/Catalog.php

https://github.com/andreydust/Booot
PHP | 1869 lines | 1398 code | 270 blank | 201 comment | 324 complexity | c99e104b5dfbcab0587894471a2887ab MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. class Catalog {
  3. private $data, $holder;
  4. public $path, $topic, $product, $menuOpened;
  5. private $localCacheLink, $productsFilter, $currentTopicTypes;
  6. private $alter_pages = array(
  7. 'seen' => array('method'=>'Seen', 'name'=>'Вы смотрели'),
  8. 'search' => array('method'=>'Search', 'name'=>'Поиск по каталогу'),
  9. 'compare' => array('method'=>'Compare', 'name'=>'Сравнение товаров')
  10. );
  11. /**
  12. * Конструктор модуля
  13. */
  14. function __construct() {
  15. if(!session_id()) session_start();
  16. $this->data = $GLOBALS['data'];
  17. }
  18. /**
  19. * Метод вызываемый для работы модуля
  20. */
  21. function Output() {
  22. $this->buildModulePath();
  23. return $this->startController();
  24. }
  25. /**
  26. * SEO для каталога
  27. * @param int $id
  28. */
  29. private function SEO($table, $id, $module=__CLASS__) {
  30. $this->seo = db()->query_first("SELECT * FROM `prefix_seo` WHERE `module` = '".$module."' AND `module_id` = ".(int)$id." AND `module_table` = '".$table."'");
  31. if(!empty($this->seo)) {
  32. //Keywords
  33. if(!empty($this->seo['keywords'])) {
  34. $GLOBALS['head_add'] .= "\r\n".'<meta name="keywords" content="'.htmlspecialchars($this->seo['keywords']).'" />';
  35. }
  36. //Description
  37. if(!empty($this->seo['description'])) {
  38. $GLOBALS['head_add'] .= "\r\n".'<meta name="description" content="'.htmlspecialchars($this->seo['description']).'" />';
  39. }
  40. $GLOBALS['head_add'] .= "\r\n";
  41. //Title
  42. if(!empty($this->seo['title'])) {
  43. $this->seo['title'] = $this->seo['title'];
  44. }
  45. }
  46. }
  47. /**
  48. * Создает и проверяет путь модуля на валидность
  49. * заполняет необходимые для работы модуля переменные
  50. * $this->holder, $this->path, $this->topic, $this->product
  51. *
  52. * При случае неверной адресации отдает 404
  53. *
  54. * Валидный адрес:
  55. * [группа](/.../[группа](/[товар]))
  56. *
  57. */
  58. private function buildModulePath() {
  59. $this->holder = end($GLOBALS['path']);
  60. $request =
  61. strpos($_SERVER['REQUEST_URI'], '?')!==false
  62. ?
  63. substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'))
  64. :
  65. $_SERVER['REQUEST_URI'];
  66. $mlink = trim(str_replace(linkById($this->holder['id']), '', $request));
  67. $mpath = array_filter(explode('/', $mlink));
  68. //Альтернативные страницы
  69. $check_alter = current($mpath);
  70. if(isset($this->alter_pages[$check_alter])) {
  71. if(!method_exists($this, $this->alter_pages[$check_alter]['method'])) page404();
  72. $params_path = array();
  73. $params_path[] = array(
  74. 'type' => 'alter_page',
  75. 'method' => $this->alter_pages[$check_alter]['method'],
  76. 'data' => $check_alter
  77. );
  78. foreach ($mpath as $ppath) {
  79. if(!isset($skipFirst)) { $skipFirst=true; continue; }
  80. $params_path[] = array(
  81. 'type' => 'param',
  82. 'data' => $ppath
  83. );
  84. }
  85. $this->path = $params_path;
  86. return true;
  87. }
  88. $topics = $this->data->GetData('products_topics', "AND `show` = 'Y'");
  89. $topicsByTop = array();
  90. foreach ($topics as $topic) $topicsByTop[$topic['top']][] = $topic;
  91. $top = 0;
  92. $path = array();
  93. //По путю модуля
  94. foreach ($mpath as $k=>$chunk) {
  95. //По топикам
  96. if(isset($topicsByTop[$top]))
  97. foreach ($topicsByTop[$top] as $topic) {
  98. if($topic['nav'] == $chunk) {
  99. $path[$k]['type'] = 'topic';
  100. $path[$k]['data'] = $topic;
  101. $this->topic = $topic;
  102. $top = $topic['id'];
  103. unset($mpath[$k]);
  104. break;
  105. }
  106. }
  107. }
  108. //Если остался неизвестный трэшняк, то сори, 404
  109. if(count($mpath) > 1) page404();
  110. //А так это возможно товар
  111. if(count($mpath) == 1) {
  112. $product = current($mpath);
  113. $curTopic = end($path);
  114. $curTopic = $curTopic['data'];
  115. $curProduct = end($mpath);
  116. if(is_numeric($curProduct)) {
  117. $product_sql = "AND p.`id` = ".(int)$curProduct;
  118. } else {
  119. $product_sql = "AND p.`nav` = '".q($curProduct)."'";
  120. }
  121. $productData = db()->rows("
  122. SELECT p.*, b.name AS `brand_name`, t.singular_name AS `product_singular_name`
  123. FROM `prefix_products` AS p
  124. LEFT JOIN `prefix_products_brands` AS b ON b.id = p.brand
  125. LEFT JOIN `prefix_products_topics` AS t ON t.id = p.top
  126. WHERE p.`deleted` = 'N' AND p.`show` = 'Y' AND p.`top` = ".(int)$curTopic['id']." $product_sql
  127. ");
  128. $productCount = count($productData);
  129. if($productCount == 0) page404();
  130. elseif($productCount > 1) $productData = current($productData);
  131. else $productData = current($productData);
  132. $this->product = $productData;
  133. $path[] = array(
  134. 'type' => 'product',
  135. 'data' => $productData
  136. );
  137. }
  138. $this->path = $path;
  139. return true;
  140. }
  141. /**
  142. * Запуск нужного метода модуля
  143. */
  144. private function startController() {
  145. //Альтернативные страницы
  146. $check_alter = current($this->path);
  147. if($check_alter['type'] == 'alter_page') {
  148. //unset($this->path[0]);
  149. return $this->$check_alter['method']();
  150. }
  151. $last = end($this->path);
  152. //Главная каталога
  153. if(empty($this->path)) {
  154. return $this->MainPage();
  155. }
  156. //Товар
  157. elseif($last['type'] == 'product') {
  158. return $this->Product();
  159. }
  160. //Группа (список товаров)
  161. else {
  162. return $this->ProductsList();
  163. }
  164. }
  165. public function MainPage() {
  166. $this->SEO('content', $this->holder['id'], 'Content');
  167. return tpl('modules/'.__CLASS__.'/mainPage', array(
  168. 'name' => $this->holder['name'],
  169. 'title' => isset($this->seo['title'])&&!empty($this->seo['title'])?$this->seo['title']:$this->holder['name'].' — '.$GLOBALS['config']['site']['title']
  170. ));
  171. }
  172. /**
  173. * Блок каталога на главной странице в теме cloudyNoon
  174. */
  175. public function MainPage_cloudyNoon() {
  176. $mostPopularProducts = array();
  177. //Список всех категорий по родительским
  178. $topicsByTop = $this->CatalogMenuTopics();
  179. if(!isset($topicsByTop[0])) return;
  180. //Количества товаров в категориях
  181. $productsCounts = db()->rows("
  182. SELECT `top`, COUNT(*) AS 'count' FROM `prefix_products` WHERE `deleted` = 'N' AND `show` = 'Y'
  183. GROUP BY `top`
  184. ", MYSQLI_ASSOC, 'top');
  185. //Картинки из товаров к категориям
  186. $topImagesRows = db()->rows("
  187. SELECT p.top, p.id
  188. FROM
  189. (
  190. SELECT `top`, MAX(`rate`) AS `max_rate`
  191. FROM `bm_products`
  192. GROUP BY `top`
  193. ) AS r
  194. LEFT JOIN `bm_products` AS p ON p.top = r.top AND p.`rate` = r.`max_rate`
  195. GROUP BY p.`top`
  196. ", MYSQLI_ASSOC, 'top');
  197. $topImages = array();
  198. foreach ($topImagesRows as $key => $value) $topImages[$key] = $value['id'];
  199. img()->PrepareImages('Catalog', $topImages);
  200. //Товары в корневых категориях
  201. $products = db()->rows("
  202. SELECT p.id, p.top, p.rate, p.name AS pname, t.singular_name, b.name AS bname, p.top AS root
  203. FROM `prefix_products` as p
  204. LEFT JOIN `prefix_products_brands` AS b ON b.id = p.brand
  205. INNER JOIN `prefix_products_topics` AS t ON t.id = p.top
  206. WHERE p.`deleted` = 'N' AND p.`show` = 'Y' AND p.`is_exist` = 'Y' AND p.`top` IN (".implode(',', array_keys($topicsByTop[0])).")
  207. ORDER BY `rate` DESC
  208. ", MYSQLI_ASSOC);
  209. $productsByRoot = array();
  210. foreach ($products as $product) {
  211. $productsByRoot[$product['root']][$product['id']] = $product;
  212. $productsByRoot[$product['root']][$product['id']]['link'] = $this->Link($product['top'], $product['id']);
  213. }
  214. return tpl('modules/'.__CLASS__.'/mainPageBlock', array(
  215. 'topicsByTop' => $topicsByTop,
  216. 'productsCounts' => $productsCounts,
  217. 'topImages' => $topImages,
  218. 'productsByRoot' => $productsByRoot
  219. ));
  220. }
  221. /**
  222. * Меню каталога
  223. */
  224. function Menu() {
  225. $topicsByTop = $this->CatalogMenuTopics();
  226. return tpl('modules/'.__CLASS__.'/menu', array(
  227. 'topics' => $topicsByTop
  228. ));
  229. }
  230. /**
  231. * Возвращает массив категрий сгруппированный по родительской категории
  232. */
  233. private function CatalogMenuTopics() {
  234. $counts_ = db()->rows("SELECT `top` , COUNT(`id`) AS `count` FROM `prefix_products` WHERE `deleted`='N' AND `show`='Y' GROUP BY `top`");
  235. $counts = array();
  236. foreach ($counts_ as $count) {
  237. $counts[$count['top']] = $count['count'];
  238. }
  239. $active_ids = array();
  240. if(!empty($this->path)) {
  241. foreach ($this->path as $v) {
  242. if($v['type'] == 'topic') {
  243. $active_ids[] = $v['data']['id'];
  244. }
  245. }
  246. }
  247. $topics = $this->data->GetData('products_topics', "AND `show` = 'Y'");
  248. $topicsByTop = array();
  249. foreach ($topics as $v) {
  250. $v['link'] = $this->Link($v['id']);
  251. $v['count'] = isset($counts[$v['id']])?$counts[$v['id']]:0;
  252. //set active
  253. if(in_array($v['id'], $active_ids)) {
  254. $v['active'] = true;
  255. $this->menuOpened = true;
  256. } else {
  257. $v['active'] = false;
  258. }
  259. $topicsByTop[$v['top']][$v['id']] = $v;
  260. }
  261. unset($topics);
  262. return $topicsByTop;
  263. }
  264. /**
  265. * Возвращает массив топовых категрий для модуля контента (для генерации меню)
  266. */
  267. public function SubMenu() {
  268. $topicsByTop = $this->CatalogMenuTopics();
  269. return $topicsByTop[0];
  270. }
  271. /**
  272. * Генерация ссылки
  273. */
  274. function Link($topic_id=0, $product_id=0) {
  275. $topic_id=(int)$topic_id;
  276. if($topic_id != 0 || $product_id != 0) {
  277. $topics = $this->data->GetData('products_topics', "AND `show` = 'Y'");
  278. if($product_id !== 0) {
  279. //if($topic_id == 0) {
  280. // $product = $this->data->GetDataById('products', $product_id);
  281. // $topic_id = $product['top'];
  282. //}
  283. $product = $this->data->GetDataById('products', $product_id);
  284. if(isset($product['nav']) && !empty($product['nav'])) {
  285. $product_link = '/'.$product['nav'];
  286. } else {
  287. $product_link = '/'.$product_id;
  288. }
  289. } else {
  290. $product_link = '';
  291. }
  292. foreach($topics as $i) $topicsByTop[$i['top']][$i['id']] = $i;
  293. $linkById = function($topic_id, $topicsByTop, $topics, $linkById) {
  294. if($topic_id==0) return;
  295. return $linkById($topics[$topic_id]['top'], $topicsByTop, $topics, $linkById).'/'.$topics[$topic_id]['nav'];
  296. };
  297. $topic_link = $linkById($topic_id, $topicsByTop, $topics, $linkById);
  298. $prepared_link = $topic_link.$product_link;
  299. }
  300. if(empty($this->localCacheLink)) $this->localCacheLink = linkByModule(__CLASS__);
  301. return $this->localCacheLink.$prepared_link;
  302. }
  303. /**
  304. * Массив для хлебных крошек модуля
  305. *
  306. * array( array('name','link') )
  307. */
  308. public function breadCrumbs() {
  309. if(!empty($this->path)) {
  310. $ret = array();
  311. foreach ($this->path as $i) {
  312. if($i['type'] == 'alter_page') {
  313. $ret[] = array(
  314. 'name' => $this->alter_pages[$i['data']]['name'],
  315. 'link' => linkByModule('Catalog').'/'.$i['data']
  316. );
  317. break;
  318. }
  319. $link = '';
  320. $name = $i['data']['name'];
  321. if($i['type'] == 'topic') $link = $this->Link($i['data']['id']);
  322. if($i['type'] == 'product') {
  323. $name = $i['data']['product_singular_name'].' '.$i['data']['brand_name'].' '.$i['data']['name'];
  324. $link = $this->Link($i['data']['top'], $i['data']['id']);
  325. }
  326. $ret[] = array('name'=>$name, 'link'=>$link);
  327. }
  328. return $ret;
  329. } else return array();
  330. }
  331. function GetSorting() {
  332. $this->sortPanel();
  333. return array($this->sorting['field'], $this->sorting['direction']);
  334. }
  335. function sortPanel() {
  336. if(isset($this->sorting['html'])) return $this->sorting['html'];
  337. //Значения по-умолчанию
  338. $options = array(
  339. 'rate' => array('name'=>'По рейтингу', 'current'=>true, 'direction'=>'desc'),
  340. 'name' => array('name'=>'По названию', 'current'=>false, 'direction'=>'asc'),
  341. 'price' => array('name'=>'По цене', 'current'=>false, 'direction'=>'asc')
  342. );
  343. //Проставляем ссылки
  344. foreach ($options as $field=>$val) {
  345. $direction = $val['direction'];//=='asc'?'desc':'asc';
  346. $options[$field]['link'] = getget(array('page'=>false, 'order'=>$field, 'orderd'=>$direction));
  347. if($val['current']) $options[$field]['link'] = getget(array('page'=>false, 'order'=>$field, 'orderd'=>$direction=='asc'?'desc':'asc'));
  348. else $options[$field]['link'] = getget(array('page'=>false, 'order'=>$field, 'orderd'=>$direction));
  349. }
  350. //Переопределения
  351. if(isset($_GET['order']) && isset($_GET['orderd'])) {
  352. if(isset($options[$_GET['order']]) && ($_GET['orderd']=='asc'||$_GET['orderd']=='desc')) {
  353. foreach ($options as $field=>$val) {
  354. if($_GET['order'] == $field) {
  355. $direction = $_GET['orderd'];//=='asc'?'desc':'asc';
  356. $options[$field]['current'] = true;
  357. $options[$field]['direction'] = $direction;
  358. $options[$field]['link'] = getget(array('page'=>false, 'order'=>$field, 'orderd'=>$_GET['orderd']=='asc'?'desc':'asc'));
  359. } else {
  360. $options[$field]['current'] = false;
  361. }
  362. }
  363. }
  364. }
  365. $this->sorting = array();
  366. foreach ($options as $field=>$val) {
  367. if($val['current']) {
  368. $this->sorting['field'] = $field;
  369. $this->sorting['direction'] = $val['direction'];
  370. break;
  371. }
  372. }
  373. $this->sorting['html'] = tpl('modules/'.__CLASS__.'/sortpanel', array(
  374. 'options' => $options
  375. ));
  376. return $this->sorting['html'];
  377. }
  378. /**
  379. * Листинг товаров
  380. */
  381. function ProductsList() {
  382. $additional_brand_title = '';
  383. $product_ids = array();
  384. $addGet = array();
  385. $db = db();
  386. //SEO
  387. $this->SEO('products_topics', $this->topic['id']);
  388. //Запрос
  389. if(isset($_GET['addGet'])) {
  390. parse_str($_GET['addGet'], $addGet);
  391. unset($_GET['addGet']);
  392. $_GET = array_merge($_GET, $addGet);
  393. }
  394. //Хар-ки топика
  395. if(empty($this->currentTopicTypes)) $this->currentTopicTypes = unserialize($this->topic['types']);
  396. //Сортировка
  397. $this->GetSorting();
  398. if(isset($this->sorting)) {
  399. $sortField = '`'.$this->sorting['field'].'`';
  400. if($this->sorting['field'] == 'price') {
  401. $sortField = '(`price` * (1 - `discount` / 100))';
  402. }
  403. $sqlOrder = 'ORDER BY `is_exist`, '.$sortField.' '.$this->sorting['direction'];
  404. } else $sqlOrder = 'ORDER BY `rate` DESC';
  405. //Товары
  406. $products = $db->rows("
  407. SELECT p.*, b.name AS `brand_name`, t.singular_name AS `product_singular_name` FROM `prefix_products` AS p
  408. LEFT JOIN `prefix_products_brands` AS b ON b.id = p.brand
  409. LEFT JOIN `prefix_products_topics` AS t ON p.top = t.id
  410. WHERE
  411. p.`deleted` = 'N' AND
  412. p.`show` = 'Y' AND
  413. p.`top` = ".(int)$this->topic['id']."
  414. $sqlOrder
  415. ", MYSQL_ASSOC);
  416. foreach ($products as $k=>$product) {
  417. //Цена
  418. $products[$k]['priceOld'] = $this->Price($product['price']);
  419. $products[$k]['price'] = $this->Price($product['price'], $product['discount']);
  420. //Распаковка характеристик
  421. $products[$k]['types'] = unserialize($product['types']);
  422. //Ссылка
  423. $products[$k]['link'] = $this->Link($product['top'], $product['nav']?$product['nav']:$product['id']);
  424. //Сравнение
  425. $products[$k]['inCompare'] = false;
  426. if(isset($_SESSION['compare']) && is_array($_SESSION['compare'])) {
  427. if(isset($_SESSION['compare'][$product['id']])) {
  428. $products[$k]['inCompare'] = true;
  429. }
  430. }
  431. //Сниппет
  432. $snippet = array();
  433. if(!empty($this->currentTopicTypes) && !empty($products[$k]['types']))
  434. foreach ($products[$k]['types'] as $groupKey=>$group) {
  435. foreach ($group as $typeKey=>$type) {
  436. if(!empty($type)) {
  437. if(isset($this->currentTopicTypes[$groupKey]['types'][$typeKey]) && $this->currentTopicTypes[$groupKey]['types'][$typeKey]['main']) {
  438. switch ($this->currentTopicTypes[$groupKey]['types'][$typeKey]['type']) {
  439. case 'float':
  440. if($type !== '') {
  441. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': '.$type.''.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['unit'];
  442. }
  443. break;
  444. case 'range':
  445. if($type['from'] !== '' && $type['to'] !== '') {
  446. if($type['from'] == $type['to']) {
  447. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': '.$type['from'].''.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['unit'];
  448. } else {
  449. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': '.$type['from'].'—'.$type['to'].''.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['unit'];
  450. }
  451. }
  452. elseif($type['from'] !== '') {
  453. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': от '.$type['from'].''.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['unit'];
  454. }
  455. elseif($type['to'] !== '') {
  456. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': до '.$type['to'].''.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['unit'];
  457. }
  458. break;
  459. case 'yn':
  460. if($type == 'Y') $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'];
  461. break;
  462. case 'select':
  463. if($type !== '' && $type !== 0) {
  464. if(isset($this->currentTopicTypes[$groupKey]['types'][$typeKey]['select'][$type])) {
  465. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': '.$this->currentTopicTypes[$groupKey]['types'][$typeKey]['select'][$type];
  466. }
  467. }
  468. break;
  469. case 'text':
  470. if(!empty($type)) {
  471. $snippet[] = $this->currentTopicTypes[$groupKey]['types'][$typeKey]['name'].': '.$type;
  472. }
  473. break;
  474. }
  475. }
  476. }
  477. }
  478. }
  479. $products[$k]['snippet'] = $snippet;
  480. }
  481. //Бренды
  482. $brands_ids = array();
  483. if(isset($_GET['brands']) && is_array($_GET['brands'])) {
  484. $sBrands = $_GET['brands'];
  485. } else {
  486. $sBrands = array();
  487. }
  488. foreach ($products as $p) $brands_ids[$p['brand']] = true;
  489. $brands_ids = array_keys($brands_ids);
  490. $brands = array();
  491. if(!empty($brands_ids)) {
  492. $brands = $db->rows("
  493. SELECT * FROM `prefix_products_brands`
  494. WHERE
  495. `deleted` = 'N' AND
  496. `show` = 'Y' AND
  497. `id` IN (".implode(',', $brands_ids).")
  498. ORDER BY `order`
  499. ", MYSQL_ASSOC);
  500. foreach ($brands as $k=>$v) {
  501. $brands[$k]['checked'] = false;
  502. if(!empty($sBrands)) {
  503. foreach ($sBrands as $bk=>$bv) {
  504. if($bv == $v['nav']) {
  505. $brands[$k]['checked'] = true;
  506. $additional_brand_title = $brands[$k]['name'];
  507. $this->productsFilter['brands'][] = $brands[$k]['id'];
  508. }
  509. }
  510. }
  511. $brands[$k]['link'] = getget(array('brands'=>array($v['nav']),'page'=>false));
  512. }
  513. }
  514. if(count($sBrands) > 1) $additional_brand_title = '';
  515. //Диапазон цен для слайдера
  516. $price_range = $db->query_first("SELECT MIN(`price`) AS `min`, MAX(`price`) AS `max` FROM `prefix_products` WHERE `deleted` = 'N' AND `show` = 'Y' AND `top` = ".(int)$this->topic['id']."");
  517. //echo "SELECT MIN(`price`) AS `min`, MAX(`price`) AS `max` FROM `prefix_products` WHERE `deleted` = 'N' AND `show` = 'Y' AND `top` = ".(int)$this->topic['id']."";
  518. $discounted_min = $db->query_first("SELECT `price` * (1 - `discount` / 100) AS `dprice` FROM `prefix_products` WHERE `deleted` = 'N' AND `show` = 'Y' AND `top` = ".(int)$this->topic['id']." ORDER BY `dprice` ASC LIMIT 1");
  519. $price_min = $this->Price($discounted_min['dprice']); //Скидка здесь уже содержится, пересчитывать ее не нужно
  520. $price_min = $price_min<0?0:$price_min;
  521. $price_max = $this->Price($price_range['max']);
  522. $price_max = $price_max<0?0:$price_max;
  523. $price_from = isset($_GET['PriceFromValue'])?(int)$_GET['PriceFromValue']:$price_min;
  524. $price_to = isset($_GET['PriceToValue'])?(int)$_GET['PriceToValue']:$price_max;
  525. $slider_vals = array(
  526. 'min' => $price_min,
  527. 'max' => $price_max,
  528. 'from' => $price_from,
  529. 'to' => $price_to,
  530. 'step' => pow(10, abs(getSet('Catalog', 'price_round')))
  531. );
  532. if(isset($_GET['PriceFromValue']) && isset($_GET['PriceToValue'])) {
  533. $this->productsFilter['price'] = array(
  534. 'form' => $price_from,
  535. 'to' => $price_to
  536. );
  537. }
  538. //Только в наличии
  539. if(isset($_GET['exist'])) $this->productsFilter['exist'] = true;
  540. else $this->productsFilter['exist'] = false;
  541. //Блок подбора
  542. $selection = $this->SelectionBlock();
  543. //Фильтр товаров по брендам, цене и характеристикам
  544. $this->SelectionFilter($products);
  545. //Пэйджинг
  546. $products_paged = $this->Paging($products);
  547. $products = $products_paged['products'];
  548. $paging = $products_paged['rendered'];
  549. unset($products_paged);
  550. if($_GET['page'] > 1) $addPageTitle = ' (страница '.abs((int)$_GET['page']).')';
  551. else $addPageTitle = '';
  552. //Тайтл страницы (<head> <title>)
  553. if(isset($this->seo['title'])&&!empty($this->seo['title'])) $head_title = $this->seo['title'];
  554. else {
  555. $backpath = array_reverse($this->path);
  556. $head_title = array();
  557. foreach ($backpath as $i) {
  558. if($i['type'] == 'topic') {
  559. $head_title[] = $i['data']['name'];
  560. }
  561. }
  562. if(!empty($head_title)) $head_title[0] = $head_title[0].(empty($additional_brand_title)?'':' '.$additional_brand_title);
  563. $head_title = implode(' — ', $head_title).' — '.$GLOBALS['config']['site']['title'];
  564. }
  565. $head_title = $head_title.$addPageTitle;
  566. //Финальные приготовления
  567. $page_title = $this->topic['name'].(empty($additional_brand_title)?'':' '.$additional_brand_title).$addPageTitle;
  568. $brand_price_link = getget(array('page'=>false,'brands'=>false,'PriceFromValue'=>false,'PriceToValue'=>false), 1);
  569. //Подготавливаем картинки
  570. foreach ($products as $product) $product_ids[] = $product['id'];
  571. img()->PrepareImages('Catalog', $product_ids);
  572. //Ссылка текущей категории
  573. $link = $this->Link($this->topic['id']);
  574. /*
  575. 'name' => $this->holder['name'],
  576. 'title' => isset($this->seo['title'])&&!empty($this->seo['title'])?$this->seo['title']:$this->holder['name'].' — '.$GLOBALS['config']['site']['title']
  577. */
  578. //Вложенные категории
  579. $subCats = $db->rows("
  580. SELECT `id`, `name`, `anons`
  581. FROM `prefix_products_topics`
  582. WHERE `deleted` = 'N' AND `show` = 'Y' AND `top` = ".(int)$this->topic['id']."
  583. ORDER BY `rate` DESC
  584. ", MYSQLI_ASSOC);
  585. $productsCounts = db()->rows("
  586. SELECT `top`, COUNT(*) AS 'count' FROM `prefix_products` WHERE `deleted` = 'N' AND `show` = 'Y'
  587. GROUP BY `top`
  588. ", MYSQLI_ASSOC, 'top');
  589. foreach ($subCats as $key => $subCat) {
  590. $subCats[$key]['link'] = $this->Link($subCat['id']);
  591. $subCats[$key]['productsCount'] = $productsCounts[$subCat['id']];
  592. }
  593. return tpl('modules/'.__CLASS__.'/list', array(
  594. 'title' => $head_title,
  595. 'name' => $page_title,
  596. 'brands' => $brands,
  597. 'link' => $link,
  598. 'brand_price_link' => $brand_price_link,
  599. 'slider_vals' => $slider_vals,
  600. 'exist' => $this->productsFilter['exist'],
  601. 'selection' => $selection,
  602. 'products' => $products,
  603. 'paging' => $paging,
  604. 'subCats' => $subCats,
  605. 'text' => $this->topic['text']
  606. ));
  607. }
  608. function CustomProductsList($products) {
  609. if(empty($products) || !is_array($products)) return false;
  610. $db = db();
  611. $topics = array();
  612. $brands = array();
  613. $ids = array();
  614. foreach ($products as $k=>$product) {
  615. //$products[$k]['types'] = unserialize($product['types']);
  616. $ids[] = $product['id'];
  617. $topics[$product['top']] = true;
  618. $brands[$product['brand']] = true;
  619. }
  620. $topics = array_keys($topics);
  621. $brands = array_keys($brands);
  622. if(empty($topics)) return false;
  623. img()->PrepareImages('Catalog', $ids, true);
  624. $ptopics = $db->rows("SELECT * FROM `prefix_products_topics` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', $topics).")", MYSQLI_ASSOC);
  625. $topics = array();
  626. foreach ($ptopics as $topic) {
  627. $topic['link'] = $this->Link($topic['id']);
  628. $topics[$topic['id']] = $topic;
  629. }
  630. $pbrands = $db->rows("SELECT * FROM `prefix_products_brands` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', $brands).")", MYSQLI_ASSOC);
  631. $brands = array();
  632. foreach ($pbrands as $brand) $brands[$brand['id']] = $brand;
  633. foreach ($products as $k=>$product) {
  634. if(!isset($topics[$product['top']])) continue;
  635. //Цена
  636. //$products[$k]['price'] = $this->Price($product['price']);
  637. $products[$k]['priceOld'] = $this->Price($product['price']);
  638. $products[$k]['price'] = $this->Price($product['price'], $product['discount']);
  639. //Распаковка характеристик
  640. if(!is_array($products[$k]['types'])) $products[$k]['types'] = unserialize($product['types']);
  641. if(!is_array($topics[$product['top']]['types'])) $topics[$product['top']]['types'] = unserialize($topics[$product['top']]['types']);
  642. //Ссылка
  643. $products[$k]['link'] = $this->Link($product['top'], $product['nav']?$product['nav']:$product['id']);
  644. //Топик
  645. $products[$k]['topic'] = $topics[$product['top']];
  646. //Бренд
  647. if(isset($brands[$product['brand']])) {
  648. $products[$k]['brand'] = $brands[$product['brand']];
  649. } else {
  650. $products[$k]['brand'] = false;
  651. }
  652. //Сниппет
  653. $snippet = array();
  654. if(!empty($topics[$product['top']]['types']) && !empty($products[$k]['types']))
  655. foreach ($products[$k]['types'] as $groupKey=>$group) {
  656. foreach ($group as $typeKey=>$type) {
  657. if(!empty($type)) {
  658. if(isset($topics[$product['top']]['types'][$groupKey]['types'][$typeKey]) && $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['main']) {
  659. switch ($topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['type']) {
  660. case 'float':
  661. if($type !== '') {
  662. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': '.$type.''.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['unit'];
  663. }
  664. break;
  665. case 'range':
  666. if($type['from'] !== '' && $type['to'] !== '') {
  667. if($type['from'] == $type['to']) {
  668. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': '.$type['from'].''.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['unit'];
  669. } else {
  670. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': '.$type['from'].'—'.$type['to'].''.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['unit'];
  671. }
  672. }
  673. elseif($type['from'] !== '') {
  674. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': от '.$type['from'].''.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['unit'];
  675. }
  676. elseif($type['to'] !== '') {
  677. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': до '.$type['to'].''.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['unit'];
  678. }
  679. break;
  680. case 'yn':
  681. if($type == 'Y') $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'];
  682. break;
  683. case 'select':
  684. if($type !== '' && $type !== 0) {
  685. if(isset($topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['select'][$type])) {
  686. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': '.$topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['select'][$type];
  687. }
  688. }
  689. break;
  690. case 'text':
  691. if(!empty($type)) {
  692. $snippet[] = $topics[$product['top']]['types'][$groupKey]['types'][$typeKey]['name'].': '.$type;
  693. }
  694. break;
  695. }
  696. }
  697. }
  698. }
  699. }
  700. $products[$k]['snippet'] = $snippet;
  701. }
  702. //Пэйджинг (сохраняется в $this->paging_rendered)
  703. $products_paged = $this->Paging($products);
  704. $products = $products_paged['products'];
  705. return tpl('modules/'.__CLASS__.'/items', array(
  706. 'products' => $products
  707. ));
  708. }
  709. function CustomLittleProductsList($products) {
  710. if(empty($products) || !is_array($products)) return false;
  711. $db = db();
  712. $topics = array();
  713. $brands = array();
  714. $ids = array();
  715. foreach ($products as $k=>$product) {
  716. //$products[$k]['types'] = unserialize($product['types']);
  717. $ids[] = $product['id'];
  718. $topics[$product['top']] = true;
  719. $brands[$product['brand']] = true;
  720. }
  721. $topics = array_keys($topics);
  722. $brands = array_keys($brands);
  723. if(empty($topics)) return false;
  724. img()->PrepareImages('Catalog', $ids, true);
  725. $ptopics = $db->rows("SELECT * FROM `prefix_products_topics` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', $topics).")", MYSQLI_ASSOC);
  726. $topics = array();
  727. foreach ($ptopics as $topic) {
  728. $topic['link'] = $this->Link($topic['id']);
  729. $topics[$topic['id']] = $topic;
  730. }
  731. $pbrands = $db->rows("SELECT * FROM `prefix_products_brands` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', $brands).")", MYSQLI_ASSOC);
  732. $brands = array();
  733. foreach ($pbrands as $brand) $brands[$brand['id']] = $brand;
  734. foreach ($products as $k=>$product) {
  735. if(!isset($topics[$product['top']])) continue;
  736. //Цена
  737. //$products[$k]['price'] = $this->Price($product['price']);
  738. $products[$k]['priceOld'] = $this->Price($product['price']);
  739. $products[$k]['price'] = $this->Price($product['price'], $product['discount']);
  740. //Ссылка
  741. $products[$k]['link'] = $this->Link($product['top'], $product['nav']?$product['nav']:$product['id']);
  742. //Топик
  743. $products[$k]['topic'] = $topics[$product['top']];
  744. //Бренд
  745. if(isset($brands[$product['brand']])) {
  746. $products[$k]['brand'] = $brands[$product['brand']];
  747. } else {
  748. $products[$k]['brand'] = false;
  749. }
  750. }
  751. return tpl('modules/'.__CLASS__.'/littleItems', array(
  752. 'products' => $products
  753. ));
  754. }
  755. function FeaturedList($limit=0) {
  756. if($limit > 0) $sql_limit = 'LIMIT '.(int)$limit;
  757. else $sql_limit = '';
  758. $products = db()->rows("SELECT * FROM `prefix_products` WHERE `is_featured` = 'Y' AND `deleted` = 'N' AND `show` = 'Y' AND `is_exist` = 'Y' ORDER BY RAND() DESC $sql_limit", MYSQLI_ASSOC);
  759. return $this->CustomProductsList($products);
  760. }
  761. function Seen() {
  762. if(!isset($_SESSION['seen']) || empty($_SESSION['seen'])) page404();
  763. $ids = array_keys($_SESSION['seen']);
  764. $ids = array_reverse($ids);
  765. $prod = db()->rows("SELECT * FROM `prefix_products` WHERE `id` IN (".implode(',', $ids).") AND `deleted` = 'N' AND `show` = 'Y' ", MYSQLI_ASSOC);
  766. $productsById = array();
  767. foreach ($prod as $i) $productsById[$i['id']] = $i;
  768. unset($prod);
  769. $products = array();
  770. foreach ($ids as $id) $products[$id] = $productsById[$id];
  771. unset($productsById);
  772. $text = $this->CustomProductsList($products);
  773. $text .= $this->paging_rendered;
  774. return tpl('page', array(
  775. 'title' => $this->alter_pages['seen']['name'],
  776. 'name' => $this->alter_pages['seen']['name'],
  777. 'text' => $text
  778. ));
  779. }
  780. function SeenBlock($limit=0) {
  781. if(!isset($_SESSION['seen']) || empty($_SESSION['seen'])) return ;
  782. $ids = array_keys($_SESSION['seen']);
  783. $ids = array_reverse($ids);
  784. if($limit > 0) $ids = array_slice($ids, 0, $limit);
  785. $prod = db()->rows("SELECT * FROM `prefix_products` WHERE `id` IN (".implode(',', $ids).") AND `deleted` = 'N' AND `show` = 'Y'", MYSQLI_ASSOC);
  786. $productsById = array();
  787. foreach ($prod as $i) $productsById[$i['id']] = $i;
  788. unset($prod);
  789. $products = array();
  790. foreach ($ids as $id) $products[$id] = $productsById[$id];
  791. unset($productsById);
  792. return tpl('modules/'.__CLASS__.'/promoBlocks/seen', array(
  793. 'littleProductsList' => $this->CustomLittleProductsList($products),
  794. 'limit' => $limit,
  795. 'count' => count($_SESSION['seen'])
  796. ));
  797. }
  798. function AlsoBoughtBlock($limit=0) {
  799. if(!isset($this->product['relations']) || empty($this->product['relations'])) return ;
  800. if($limit > 0) $sql_limit = 'LIMIT '.(int)$limit;
  801. else $sql_limit = '';
  802. $products = db()->rows("SELECT * FROM `prefix_products` WHERE `id` IN (".$this->product['relations'].") AND `deleted` = 'N' AND `show` = 'Y' $sql_limit", MYSQLI_ASSOC);
  803. return tpl('modules/'.__CLASS__.'/promoBlocks/alsoBought', array(
  804. 'littleProductsList' => $this->CustomLittleProductsList($products))
  805. );
  806. }
  807. function addCompare($id) {
  808. $product = db()->query_first("SELECT * FROM `prefix_products` WHERE `id` = ".abs((int)$id)." AND `deleted` = 'N' AND `show` = 'Y'");
  809. if(!empty($product)) $_SESSION['compare'][$id] = true;
  810. }
  811. function delCompare($id) {
  812. if(isset($_SESSION['compare'][$id])) unset($_SESSION['compare'][$id]);
  813. }
  814. function cleanCompare() {
  815. if(isset($_SESSION['compare'])) unset($_SESSION['compare']);
  816. }
  817. function ajaxCompare() {
  818. if(isset($_POST['add'])) $this->addCompare($_POST['add']);
  819. if(isset($_POST['del'])) $this->delCompare($_POST['del']);
  820. if(isset($_POST['clean'])) $this->cleanCompare();
  821. giveJSON(array(
  822. 'block' => $this->CompareBlock()
  823. ));
  824. }
  825. /**
  826. * Блок сравнения
  827. */
  828. function CompareBlock() {
  829. if(!isset($_SESSION['compare']) || empty($_SESSION['compare']))
  830. return tpl('modules/'.__CLASS__.'/promoBlocks/compare', array('products' => array(), 'topics' => array()));
  831. $ids = array_keys($_SESSION['compare']);
  832. $ids = array_reverse($ids);
  833. $prod = db()->rows("SELECT * FROM `prefix_products` WHERE `id` IN (".implode(',', $ids).") AND `deleted` = 'N' AND `show` = 'Y'", MYSQLI_ASSOC, 'id');
  834. foreach ($prod as $k=>$product) {
  835. //$prod[$k]['price'] = $this->Price($product['price']);
  836. $prod[$k]['priceOld'] = $this->Price($product['price']);
  837. $prod[$k]['price'] = $this->Price($product['price'], $product['discount']);
  838. }
  839. $brands = db()->rows("SELECT * FROM `prefix_products_brands` WHERE `deleted` = 'N' AND `show` = 'Y'", MYSQLI_ASSOC, 'id');
  840. $products = array();
  841. foreach ($ids as $id) {
  842. $products [$prod[$id]['top']] [$id] = $prod[$id];
  843. $products [$prod[$id]['top']] [$id] ['link'] = $this->Link($prod[$id]['top'], $prod[$id]['id']);
  844. if(isset($brands[$prod[$id]['brand']])) $products [$prod[$id]['top']] [$id] ['brand'] = $brands[$prod[$id]['brand']];
  845. else $products [$prod[$id]['top']] [$id] ['brand'] = false;
  846. }
  847. $topics = db()->rows("SELECT * FROM `prefix_products_topics` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', array_keys($products)).")", MYSQL_ASSOC, 'id');
  848. foreach ($topics as $id=>$topic) $topics[$id]['link'] = $this->Link($topic['id']);
  849. foreach ($products as $k=>$v) {
  850. $products[$k] = array_slice($v, 0, 3);
  851. }
  852. return tpl('modules/'.__CLASS__.'/promoBlocks/compare', array(
  853. 'products' => $products,
  854. 'topics' => $topics,
  855. 'count' => count($_SESSION['compare'])
  856. ));
  857. }
  858. /**
  859. * Страница сравнения, добавление/удаление товаров в сравнении
  860. */
  861. function Compare() {
  862. // Добавление/удаление товаров сравнения
  863. if(isset($this->path[1]) && isset($this->path[2]) && $this->path[1]['data']=='add') {$this->addCompare($this->path[2]['data']); $backMe=true;}
  864. if(isset($this->path[1]) && isset($this->path[2]) && $this->path[1]['data']=='del') {$this->delCompare($this->path[2]['data']); $backMe=true;}
  865. if(isset($this->path[1]) && $this->path[1]['data']=='clean') {$this->cleanCompare(); $backMe=true;}
  866. if(isset($backMe) && isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER'])) {
  867. header('Location: '.$_SERVER['HTTP_REFERER']);
  868. exit();
  869. }
  870. if(!isset($_SESSION['compare']) || empty($_SESSION['compare'])) page404();
  871. //Подготовка данных для сравнения
  872. $ids = array_keys($_SESSION['compare']);
  873. $ids = array_reverse($ids);
  874. $prod = db()->rows("SELECT * FROM `prefix_products` WHERE `id` IN (".implode(',', $ids).") AND `deleted` = 'N' AND `show` = 'Y'", MYSQLI_ASSOC, 'id');
  875. foreach ($prod as $k=>$product) {
  876. //$prod[$k]['price'] = $this->Price($product['price']);
  877. $prod[$k]['priceOld'] = $this->Price($product['price']);
  878. $prod[$k]['price'] = $this->Price($product['price'], $product['discount']);
  879. }
  880. $brands = db()->rows("SELECT * FROM `prefix_products_brands` WHERE `deleted` = 'N' AND `show` = 'Y'", MYSQLI_ASSOC, 'id');
  881. $products = array();
  882. foreach ($ids as $id) {
  883. $products [$prod[$id]['top']] [$id] = $prod[$id];
  884. $products [$prod[$id]['top']] [$id] ['link'] = $this->Link($prod[$id]['top'], $prod[$id]['id']);
  885. $products [$prod[$id]['top']] [$id] ['types'] = unserialize($prod[$id]['types']);
  886. if(isset($brands[$prod[$id]['brand']])) $products [$prod[$id]['top']] [$id] ['brand'] = $brands[$prod[$id]['brand']];
  887. else $products [$prod[$id]['top']] [$id] ['brand'] = false;
  888. }
  889. $topics = db()->rows("SELECT * FROM `prefix_products_topics` WHERE `deleted` = 'N' AND `show` = 'Y' AND `id` IN (".implode(',', array_keys($products)).")", MYSQL_ASSOC, 'id');
  890. foreach ($topics as $id=>$topic) {
  891. $topics[$id]['link'] = $this->Link($topic['id']);
  892. $topics[$id]['types'] = unserialize($topics[$id]['types']);
  893. //debug($topics[$id]['types']);
  894. }
  895. //Характеристики
  896. foreach ($products as $top_id=>$product_group) {
  897. foreach ($product_group as $prod_id=>$product) {
  898. $types = array();
  899. $pTypes = $product['types'];
  900. if(is_array($topics[$top_id]['types']))
  901. foreach ($topics[$top_id]['types'] as $groupKey=>$group) {
  902. $types[$groupKey]['name'] = $group['name'];
  903. foreach ($group['types'] as $typeKey=>$type) {
  904. switch ($type['type']) {
  905. case 'float':
  906. if($pTypes[$groupKey][$typeKey] !== '') {
  907. $types[$groupKey]['types'][$typeKey] = array(
  908. 'name' => $type['name'],
  909. 'desc' => $type['desc'],
  910. 'val' => $pTypes[$groupKey][$typeKey].$type['unit']
  911. );
  912. }
  913. break;
  914. case 'range':
  915. if(isset($pTypes[$groupKey][$typeKey]['from']) && isset($pTypes[$groupKey][$typeKey]['to']))
  916. if($pTypes[$groupKey][$typeKey]['from'] !== '' || $pTypes[$groupKey][$typeKey]['to'] !== '') {
  917. if($pTypes[$groupKey][$typeKey]['from'] !== '' && $pTypes[$groupKey][$typeKey]['to'] !== '') {
  918. if($pTypes[$groupKey][$typeKey]['from'] == $pTypes[$groupKey][$typeKey]['to']) {
  919. $val = $pTypes[$groupKey][$typeKey]['from'].$type['unit'];
  920. } else {
  921. $val = $pTypes[$groupKey][$typeKey]['from'].'—'.$pTypes[$groupKey][$typeKey]['to'].$type['unit'];
  922. }
  923. }
  924. elseif($pTypes[$groupKey][$typeKey]['from'] !== '') {
  925. $val = 'от '.$pTypes[$groupKey][$typeKey]['from'];
  926. }
  927. elseif($pTypes[$groupKey][$typeKey]['to'] !== '') {
  928. $val = 'до '.$pTypes[$groupKey][$typeKey]['to'];
  929. }
  930. $types[$groupKey]['types'][$typeKey] = array(
  931. 'name' => $type['name'],
  932. 'desc' => $type['desc'],
  933. 'val' => $val
  934. );
  935. }
  936. break;
  937. case 'yn':
  938. if($pTypes[$groupKey][$typeKey] == 'Y') $types[$groupKey]['types'][$typeKey] = array(
  939. 'name' => $type['name'],
  940. 'desc' => $type['desc'],
  941. 'val' => 'Есть'
  942. );
  943. if($pTypes[$groupKey][$typeKey] == 'N') $types[$groupKey]['types'][$typeKey] = array(
  944. 'name' => $type['name'],
  945. 'desc' => $type['desc'],
  946. 'val' => 'Нет'
  947. );
  948. break;
  949. case 'select':
  950. if($pTypes[$groupKey][$typeKey] !== '' && $pTypes[$groupKey][$typeKey] !== 0) {
  951. if(isset($type['select'][ $pTypes[$groupKey][$typeKey] ])) {
  952. $types[$groupKey]['types'][$typeKey] = array(
  953. 'name' => $type['name'],
  954. 'desc' => $type['desc'],
  955. 'val' => $type['select'][ $pTypes[$groupKey][$typeKey] ]
  956. );
  957. }
  958. }
  959. break;
  960. case 'text':
  961. if(!empty($pTypes[$groupKey][$typeKey])) {
  962. $types[$groupKey]['types'][$typeKey] = array(
  963. 'name' => $type['name'],
  964. 'desc' => $type['desc'],
  965. 'val' => $pTypes[$groupKey][$typeKey]
  966. );
  967. }
  968. break;
  969. }
  970. }
  971. if(empty($types[$groupKey]['types'])) unset($types[$groupKey]);
  972. }
  973. $products [$top_id] [$prod_id] ['rtypes'] = $types;
  974. }
  975. //Нахождение различающихся характеристик
  976. if(is_array($topics[$top_id]['types']))
  977. foreach ($topics[$top_id]['types'] as $groupKey=>$types) {
  978. foreach ($types['types'] as $typeKey=>$type) {
  979. $stored = false;
  980. $topics[$top_id]['types'][$groupKey]['types'][$typeKey]['equal'] = true;
  981. foreach ($products[$topic['id']] as $product) {
  982. if($stored !== false && $stored != @$product['types'][$groupKey][$typeKey]) {
  983. $topics[$top_id]['types'][$groupKey]['types'][$typeKey]['equal'] = false;
  984. break;
  985. }
  986. @$stored = $product['types'][$groupKey][$typeKey];
  987. }
  988. $stored = false;
  989. }
  990. }
  991. }
  992. $text = tpl('modules/'.__CLASS__.'/compare', array(
  993. 'products' => $products,
  994. 'topics' => $topics
  995. ));
  996. return tpl('page', array(
  997. 'title' => $this->alter_pages['compare']['name'],
  998. 'name' => $this->alter_pages['compare']['name'],
  999. 'text' => $text
  1000. ));
  1001. }
  1002. /**
  1003. * Простой и незамысловатый поиск
  1004. */
  1005. function Search() {
  1006. $string = trim($_GET['string']);
  1007. $error = '';
  1008. if(empty($string)) $error = '<p>Пустой поисковый запрос, мы так ничего не найдем!</p>';
  1009. if(mb_strlen($string) <= 1) $error = '<p>Очень короткий поисковый запрос, вы сами устанете искать то что нужно из всех совпадений!</p>';
  1010. if(!empty($error)) return tpl('page', array('title' => $this->alter_pages['search']['name'],'name' => $this->alter_pages['search']['name'],'text' => $error));
  1011. $strings = explode(' ', $string);
  1012. $highlight = array();
  1013. //Убираем окончания
  1014. $stemmer = new Lingua_Stem_Ru();
  1015. foreach ($strings as $k=>$v) {
  1016. $trimv = trim($v);
  1017. $strings[$k] = $stemmer->stem_word($trimv);
  1018. $highlight[] = $trimv;
  1019. }
  1020. //Окончательно фильтруем
  1021. $strings = array_filter($strings);
  1022. $like = array();
  1023. foreach ($strings as $v) {
  1024. $like[] = '(t.`name` LIKE \'%'.q($v).'%\' OR p.`name` LIKE \'%'.q($v).'%\' OR b.`name` LIKE \'%'.q($v).'%\')';
  1025. }
  1026. $products = array();
  1027. if(is_array($like) && !empty($like)) {
  1028. $products = db()->rows("
  1029. SELECT p.*, b.name AS `brand_name`, t.singular_name AS `product_singular_name`
  1030. FROM `prefix_products` AS p
  1031. LEFT JOIN `prefix_products_topics` AS t ON t.id = p.top
  1032. LEFT JOIN `prefix_products_brands` AS b ON b.id = p.brand
  1033. WHERE p.`deleted` = 'N' AND p.`show` = 'Y' AND (".implode(' AND ', $like).")
  1034. ORDER BY `rate` DESC
  1035. ");
  1036. if(count($products) == 0) {
  1037. $products = db()->rows("
  1038. SELECT p.*, b.name AS `brand_name`, t.singular_name AS `product_singular_name`
  1039. FROM `prefix_products` AS p
  1040. LEFT JOIN `prefix_products_topics` AS t ON t.id = p.top
  1041. LEFT JOIN `prefix_products_brands` AS b ON b.id = p.brand
  1042. WHERE p.`deleted` = 'N' AND p.`show` = 'Y' AND (".implode(' OR ', $like).")
  1043. ORDER BY `rate` DESC
  1044. ");
  1045. }
  1046. }
  1047. if(count($products) == 0) $error = '<p>Товары не найдены, попробуйте поискать с другим запросом!</p>';
  1048. if(!empty($error)) return tpl('page', array('title' => $this->alter_pages['search']['name'],'name' => $this->alter_pages['search']['name'],'text' => $error));
  1049. $text = $this->CustomProductsList($products);
  1050. $text .= $this->paging_rendered;
  1051. return tpl('page', array(
  1052. 'title' => $this->alter_pages['search']['name'],
  1053. 'name' => $this->alter_pages['search']['name'],
  1054. 'text' => $text
  1055. ));
  1056. }
  1057. function SearchForExample() {
  1058. $example = db()->query_first("
  1059. SELECT p.`name` AS `pname`, b.`name` AS `bname` FROM `prefix_products` AS p
  1060. LEFT JOIN `prefix_products_brands` AS b ON b.`id` = p.`brand`
  1061. WHERE
  1062. p.`deleted` = 'N' AND
  1063. p.`show` = 'Y'
  1064. ORDER BY RAND()
  1065. LIMIT 1
  1066. ");
  1067. $exampleString = trim($example['pname'].' '.$example['bname']);
  1068. return $exampleString;
  1069. }
  1070. function Paging($products) {
  1071. $products_count = count($products);
  1072. $products_onpage = getSet('Catalog', 'onpage', 8);
  1073. $pages_count = ceil($products_count/$products_onpage);
  1074. if(isset($_GET['page'])) $page_current = abs((int)$_GET['page']);
  1075. else $page_current = 1;
  1076. $products_from = ($page_current-1)*$products_onpage;
  1077. if($products_count <= $products_onpage) {
  1078. $rendered = '';
  1079. } else {
  1080. $rendered = tpl('modules/'.__CLASS__.'/paging', array(
  1081. 'pages_count' => $pages_count,
  1082. 'page_current' => $page_current,
  1083. 'products_count' => $products_count,
  1084. 'products_from' => $products_from + 1,
  1085. 'products_to' => $products_onpage*$page_current>$products_count?$products_count:$products_onpage*$page_current,
  1086. 'topicLink' => $this->Link($this->topic['id'])
  1087. ));
  1088. }
  1089. $this->paging_rendered = $rendered;
  1090. return array(
  1091. 'products' => array_slice($products, $products_from, $products_onpage),
  1092. 'rendered' => $rendered
  1093. );
  1094. }
  1095. function GetPaging() {
  1096. if(isset($this->paging_rendered)) {
  1097. return $this->paging_rendered;
  1098. } else {
  1099. return false;
  1100. }
  1101. }
  1102. private function SelectionBlock() {
  1103. if(empty($this->currentTopicTypes)) $this->currentTopicTypes = unserialize($this->topic['types']);
  1104. if(empty($this->currentTopicTypes)) return ;
  1105. //Сортировка групп
  1106. usort($this->currentTopicTypes, function($a,$b) {
  1107. if ($a['order'] == $b['order']) return 0;
  1108. return ($a['order'] < $b['order']) ? -1 : 1;
  1109. });
  1110. //Подготовка списка характеристик
  1111. $readyTypes = array();
  1112. foreach ($this->currentTopicTypes as $groupKey=>$group) {
  1113. foreach ($group['types'] as $typeKey=>$type) {
  1114. if($type['main']) {
  1115. $type['groupKey'] = $groupKey;
  1116. $type['typeKey'] = $typeKey;
  1117. if(isset($_GET['select'][$groupKey][$typeKey])) {
  1118. switch ($type['type']) {
  1119. case 'float': case 'range':
  1120. if(isset($_GET['select'][$groupKey][$typeKey]['from']) && isset($_GET['select'][$groupKey][$typeKey]['to'])) {
  1121. //Не задано ОТ
  1122. if(empty($_GET['select'][$groupKey][$typeKey]['from']) && !empty($_GET['select'][$groupKey][$typeKey]['to'])) {
  1123. $type['val']['to'] = (float)$_GET['select'][$groupKey][$typeKey]['to'];
  1124. $this->productsFilter['select'][$groupKey][$typeKey]['to'] = $type['val']['to'];
  1125. }
  1126. //Не задано ДО
  1127. elseif(!empty($_GET['select'][$groupKey][$typeKey]['from']) && empty($_GET['select'][$groupKey][$typeKey]['to'])) {
  1128. $type['val']['from'] = (float)$_GET['select'][$groupKey][$typeKey]['from'];
  1129. $this->productsFilter['select'][$groupKey][$typeKey]['from'] = $type['val']['from'];
  1130. }
  1131. //Все задано
  1132. elseif(!empty($_GET['select'][$groupKey][$typeKey]['from']) && !empty($_GET['select'][$groupKey][$typeKey]['to'])) {
  1133. $type['val']['from'] = (float)$_GET['select'][$groupKey][$typeKey]['from'];
  1134. $type['val']['to'] = (float)$_GET['select'][$groupKey][$typeKey]['to'];
  1135. $this->productsFilter['select'][$groupKey][$typeKey]['from'] = $type['val']['from'];
  1136. $this->productsFilter['select'][$groupKey][$typeKey]['to'] = $type['val']['to'];
  1137. }
  1138. }
  1139. break;
  1140. case 'yn':
  1141. if($_GET['select'][$groupKey][$typeKey] == 'Y') {
  1142. $type['val'] = 'Y';
  1143. $this->productsFilter['select'][$groupKey][$typeKey] = $type['val'];
  1144. }
  1145. break;
  1146. case 'select':
  1147. if(in_array($_GET['select'][$groupKey][$typeKey], array_keys($type['select']))) {
  1148. $type['val'] = $_GET['select'][$groupKey][$typeKey];
  1149. $this->productsFilter['select'][$groupKey][$typeKey] = $type['val'];
  1150. }
  1151. break;
  1152. }
  1153. }
  1154. $readyTypes[] = $type;
  1155. }
  1156. }
  1157. }
  1158. if(empty($readyTypes)) return ;
  1159. //Добавочный URL
  1160. $link = getget(array('page'=>false, 'select'=>false), 1);
  1161. //Очищающий URL
  1162. $cleanLink = getget(array('page'=>false, 'select'=>false));
  1163. return tpl('modules/'.__CLASS__.'/selection', array(
  1164. 'types' => $readyTypes,
  1165. 'link' => $link,
  1166. 'cleanLink' => $cleanLink
  1167. ));
  1168. }
  1169. function SelectionFilter(&$products) {
  1170. foreach ($products as $k=>$product) {
  1171. //Бренды
  1172. if(isset($this->productsFilter['brands']) && !in_array($product['brand'], $this->productsFilter['brands'])) {
  1173. unset($products[$k]);
  1174. }
  1175. //Цена
  1176. if(isset($this->productsFilter['price']) && ($product['price'] < $this->productsFilter['price']['form'] || $product['price'] > $this->productsFilter['price']['to'])) {
  1177. unset($products[$k]);
  1178. }
  1179. //Наличие
  1180. if($this->productsFilter['exist'] && $product['is_exist'] != 'Y') {
  1181. unset($products[$k]);
  1182. }
  1183. //Характеристики
  1184. if(!empty($this->currentTopicTypes)) $tTypes = $this->currentTopicTypes;
  1185. else $tTypes = $this->currentTopicTypes = unserialize($this->topic['types']);
  1186. if(isset($this->productsFilter['select'])) {
  1187. if(empty($product['types'])) { unset($products[$k]); continue; }
  1188. foreach($product['types'] as $group

Large files files are truncated, but you can click here to view the full file