Перейти к содержимому


Фотография
- - - - -

[Оптимизация] Zoo под большие контентные сайты и не только ¯\_(ツ)_/¯

zoo оптимизация костыль денис_молодец женя_тоже_ничего forumlvlup likeaboss никто_не_читает_теги

Сообщений в теме: 12

#1 CB9TOIIIA

CB9TOIIIA

Отправлено 06 February 2017 - 17:23

*
Популярное сообщение!

Всем привет! Хочу рассказать и поделиться решением которое мы нашли на одном незаурядном большом контентном сайте на JBZoo. #8к
 
Сайт периодически падал, чем вызывал негодование всех пользователей и владельцев. Железо мощное - тем самым профилированием сайта давно не занимались. В итоге о причинах падениях почти всегда были внешние факторы: то сетевой кабель в ДЦ тупит, то апгрейд оборудования, то HDD сгорит... много чего было ¯\_(ツ)_/¯
 
После перехода на php7 - сайт стал шустрее работать, но и это не спасло - т.е. меньше оперативки стал есть сайт - шустрее работать и БД просто в ах..  шоке была от всего этого 300-500% нагрузка и зависала.
 
Нашли специалиста по БД из наших чатов в Telegram:

Протюнил БД, вынес кеши в отдельные папки, настроил конекты и прочее - в общем сервер работал но все равно очень туго.
 
В этот момент я занимался профилированием с JBDump - и о чудо - я смог найти место - точнее определить уровень возникновения тормозов. На страницах full все было чудесно, но на категориях и главной странице все ужасно... просто тихий ужас. На каком нибудь shared хостинге вообще бы ничего не работало.
 
Замеры под openserver (windows) показало - от 10 до 35 секунд на render страницы (ЖЕСТЬ да?)
На сервере linux и железо мощное - поэтому там занимало наверное раз 2-3 меньше.
 
Выпив валерьянки - скоординировались с Денисом (главным бармалеем JBZoo), за пару часов нашли где возникала пропасть и попробовали устранить, но решение на ночь глядя не нашли.
 
Проблема была в том, что таблица элементов (там где все хранится - тексты, адреса на фото и прочее) - была нереально тяжелой. 
 
Например на сайте каталоге 15 тыс. товаров: https://kadi-trade.ru/catalog.html  - всего до 50 кб это все дело занимает.
А на контентном сайте у нас оно занимало внимание: примерно 2 МБ. И каждый запрос от пользователя (кеш не в счет) - делал выборку из нее.
 
Проблема была в запросе ZOO - он выбирал все ячейки строил объекты.
 
Благодаря смекалке и конечно же уму Дениса  :-*  - переписал запрос на выбор id и построение объектов.
 
Вот пруф: https://github.com/J...0fd17d4e0abc313

 

Пользуйтесь!  8) 
 

0_ab0f3_b9771541_orig.png
 

 
Результаты профилирования до и после:
 

0_ab0f4_922a1cc2_orig.png
 
0_ab0f5_6182239b_orig.png
 

 
В итоге правка отлично работает и уже 3-е суток тьфу-тьфу без сбоя, load avareage стал примерно 0.7-1.2.  O0 
 
И мы счастливы... в общем как буду в МСК на #JD в июне с меня разные ништячки Денису за помощь   ¯\_(ツ)_/¯

 

Пользуйтесь замечательным дебагером - jbdump,

который есть в JBZoo - и оптимизируйте свои проекты  :)

Прикрепленные изображения

  • 061131.png
  • clipboard.png
  • clipboard2.png

Сообщение отредактировал CB9TOIIIA: 06 February 2017 - 18:50

  • 6

#2 CB9TOIIIA

CB9TOIIIA

Отправлено 06 February 2017 - 22:23

----------------------------------------------------------

Для примера взял региональный новостник

 

 
370 -> 260 ms  // главная 
720 ms - > 175 ms - категории
1050 ms - 540 ms - item full
 
Прирост до 3-х раз
----------------------------------------------------------

  • 3

#3 grickov84

grickov84

Отправлено 06 February 2017 - 23:00

Попробуемс ))), а то есть тоже тормозной проект на 20 тыс товаров, рекламу запускаю и местами тормозит


  • 1

#4 CB9TOIIIA

CB9TOIIIA

Отправлено 06 February 2017 - 23:00

grickov84 сказал(а) 06 Фев 2017 - 22:00:

Попробуемс ))), а то есть тоже тормозной проект на 20 тыс товаров, рекламу запускаю и местами тормозит

 

Профилировать :)


  • 0

#5 grickov84

grickov84

Отправлено 06 February 2017 - 23:16

Дык и с БД выстегивал, в настройке БД зубы поломал, не первый год. Свой хостинг маленький держу. Остальное курочил, потом плюнул)). Дел и так по горло хватает. А тут хлоп и вылезла трабла. Попробуемс )))


  • 0

#6 Шингисович

Шингисович

Отправлено 13 March 2017 - 05:48

CB9TOIIIA сказал(а) 06 Фев 2017 - 16:23:

 

Пользуйтесь замечательным дебагером - jbdump,

который есть в JBZoo - и оптимизируйте свои проекты  :)

 

На мультиязычном сайте хак нарушил работу выборки айтемов в разных языковых каталогах. Поэтому вынужден был отказаться от него. :(

Видимо, еще кое-что нужно переделать. 

Хотя, возможно, я составил не совсем правильный код и поэтому у меня выборка порушилась...

 

Может, укажете на ошибку?

 

Ниже представляю версию файла, который изменил по рецепту с гитхаба:

administrator/components/com_zoo/tables/item.php

  1. <?php
  2. /**
  3. * @package com_zoo
  4. * @author YOOtheme http://www.yootheme.com
  5. * @copyright Copyright (C) YOOtheme GmbH
  6. * @license http://www.gnu.org/licenses/gpl.html GNU/GPL
  7. */
  8.  
  9. /*
  10. Class: ItemTable
  11. The table class for items.
  12. */
  13. class ItemTable extends AppTable {
  14.  
  15. public function __construct($app) {
  16. parent::__construct($app, ZOO_TABLE_ITEM);
  17. }
  18.  
  19. protected function _initObject($object) {
  20.  
  21. parent::_initObject($object);
  22.  
  23. // workaround for php bug, which calls constructor before filling values
  24. if (is_string($object->params) || is_null($object->params)) {
  25. // decorate data as object
  26. $object->params = $this->app->parameter->create($object->params);
  27. }
  28.  
  29. if (is_string($object->elements) || is_null($object->elements)) {
  30. // decorate data as object
  31. $object->elements = $this->app->data->create($object->elements);
  32. }
  33.  
  34. // add to cache
  35. $key_name = $this->key;
  36.  
  37. if ($object->$key_name && !key_exists($object->$key_name, $this->_objects)) {
  38. $this->_objects[$object->$key_name] = $object;
  39. }
  40.  
  41. // trigger init event
  42. $this->app->event->dispatcher->notify($this->app->event->create($object, 'item:init'));
  43.  
  44. return $object;
  45. }
  46.  
  47. /*
  48. Function: save
  49. Override. Save object to database table.
  50.  
  51. Returns:
  52. Boolean.
  53. */
  54. public function save($object) {
  55.  
  56. if (!($application = $object->getApplication())) {
  57. throw new ItemTableException('Invalid application id');
  58. }
  59.  
  60. if (!is_string($object->type) || empty($object->type)) {
  61. throw new ItemTableException('Invalid type id');
  62. }
  63.  
  64. if ($object->name == '') {
  65. throw new ItemTableException('Invalid name');
  66. }
  67.  
  68. if ($object->alias == '' || $object->alias != $this->app->string->sluggify($object->alias)) {
  69. throw new ItemTableException('Invalid slug');
  70. }
  71.  
  72. if ($this->app->alias->item->checkAliasExists($object->alias, $object->id)) {
  73. throw new ItemTableException('Alias already exists, please choose a unique alias');
  74. }
  75.  
  76. $new = !(bool) $object->id;
  77.  
  78. // trigger save event
  79. $this->app->event->dispatcher->notify($this->app->event->create($object, 'item:save', compact('new')));
  80.  
  81. $result = parent::save($object);
  82.  
  83. // init vars
  84. $db = $this->database;
  85. $search_data = array();
  86.  
  87. foreach ($object->getElements() as $id => $element) {
  88. // get search data
  89. if ($data = $element->getSearchData()) {
  90. $search_data[] = "(".$object->id.", ".$db->quote($id).", ".$db->quote($data).")";
  91. }
  92. }
  93.  
  94. // delete old search data
  95. $query = "DELETE FROM ".ZOO_TABLE_SEARCH
  96. ." WHERE item_id = ".(int) $object->id;
  97. $db->query($query);
  98.  
  99. // insert new search data
  100. if (count($search_data)) {
  101. $query = "INSERT INTO ".ZOO_TABLE_SEARCH
  102. ." VALUES ".implode(", ", $search_data);
  103. $db->query($query);
  104. }
  105.  
  106. // save tags
  107. $this->app->table->tag->save($object);
  108.  
  109. // trigger saved event
  110. $this->app->event->dispatcher->notify($this->app->event->create($object, 'item:saved', compact('new')));
  111.  
  112. return $result;
  113. }
  114.  
  115. /*
  116. Function: delete
  117. Override. Delete object from database table.
  118.  
  119. Returns:
  120. Boolean.
  121. */
  122. public function delete($object) {
  123.  
  124. // get database
  125. $db = $this->database;
  126.  
  127. // delete item to category relations
  128. $query = "DELETE FROM ".ZOO_TABLE_CATEGORY_ITEM
  129. ." WHERE item_id = ".(int) $object->id;
  130. $db->query($query);
  131.  
  132. // delete related comments
  133. $query = "DELETE FROM ".ZOO_TABLE_COMMENT
  134. ." WHERE item_id = ".(int) $object->id;
  135. $db->query($query);
  136.  
  137. // delete related search data rows
  138. $query = "DELETE FROM ".ZOO_TABLE_SEARCH
  139. ." WHERE item_id = ". (int) $object->id;
  140. $db->query($query);
  141.  
  142. // delete related rating data rows
  143. $query = "DELETE FROM ".ZOO_TABLE_RATING
  144. ." WHERE item_id = ". (int) $object->id;
  145. $db->query($query);
  146.  
  147. // delete related tag data rows
  148. $query = "DELETE FROM ".ZOO_TABLE_TAG
  149. ." WHERE item_id = ". (int) $object->id;
  150. $db->query($query);
  151.  
  152. $result = parent::delete($object);
  153.  
  154. // trigger deleted event
  155. $this->app->event->dispatcher->notify($this->app->event->create($object, 'item:deleted'));
  156.  
  157. return $result;
  158. }
  159.  
  160. /*
  161. Function: hit
  162. Increment item hits.
  163.  
  164. Returns:
  165. Boolean.
  166. */
  167. public function hit($object) {
  168.  
  169. // get database
  170. $db = $this->database;
  171. $key = $this->key;
  172.  
  173. // increment hits
  174. if ($object->$key) {
  175. $query = "UPDATE ".$this->name
  176. ." SET hits = (hits + 1)"
  177. ." WHERE $key = ".(int) $object->$key;
  178. $db->query($query);
  179. $object->hits++;
  180. return true;
  181. }
  182.  
  183. return false;
  184. }
  185.  
  186. /*
  187. Function: getApplicationItemCount
  188. Method to get application related item count.
  189.  
  190. Parameters:
  191. $application_id - Application id
  192.  
  193. Returns:
  194. Int
  195. */
  196. public function getApplicationItemCount($application_id) {
  197. $query = "SELECT count(a.id) AS item_count"
  198. ." FROM ".$this->name." AS a"
  199. ." WHERE a.application_id = ".(int) $application_id;
  200.  
  201. return (int) $this->_queryResult($query);
  202. }
  203.  
  204. /*
  205. Function: getTypeItemCount
  206. Method to get types related item count.
  207.  
  208. Parameters:
  209. $type - Type
  210.  
  211. Returns:
  212. Int
  213. */
  214. public function getTypeItemCount($type){
  215.  
  216. // get database
  217. $db = $this->database;
  218.  
  219. $group = $type->getApplication()->getGroup();
  220. $query = "SELECT count(a.id) AS item_count"
  221. ." FROM ".$this->name." AS a"
  222. ." JOIN ".ZOO_TABLE_APPLICATION." AS b ON a.application_id = b.id"
  223. ." WHERE a.type = ".$db->Quote($type->id)
  224. ." AND b.application_group = ".$db->Quote($group);
  225.  
  226. return (int) $this->_queryResult($query);
  227.  
  228. }
  229.  
  230. /*
  231. @deprecated version 2.5 beta
  232. */
  233. public function findAll($application_id = false, $published = false, $user = null, $options = array()) {
  234.  
  235. // get database
  236. $db = $this->database;
  237.  
  238. // get date
  239. $date = $this->app->date->create();
  240. $now = $db->Quote($date->toSQL());
  241. $null = $db->Quote($db->getNullDate());
  242.  
  243. // set query options
  244. $conditions =
  245. ($application_id !== false ? "application_id = ".(int) $application_id : "")
  246. ." AND ".$this->app->user->getDBAccessString($user)
  247. .($published == true ? " AND state = 1"
  248. ." AND (publish_up = ".$null." OR publish_up <= ".$now.")"
  249. ." AND (publish_down = ".$null." OR publish_down >= ".$now.")": "");
  250.  
  251. return $this->all(array_merge(compact('conditions'), $options));
  252. }
  253.  
  254. /*
  255. Function: getByCharacter
  256. Method to retrieve all items starting with a certain character.
  257.  
  258. Parameters:
  259. $application_id - Application id
  260. $char - Character(s)
  261. $not_in - Use not in for matching multiple characters
  262.  
  263. Returns:
  264. Array - Array of items
  265. */
  266. public function getByIds($ids, $published = false, $user = null, $orderby = '', $ignore_order_priority = false){
  267.  
  268. $ids = (array) $ids;
  269.  
  270. if (empty($ids)) {
  271. return array();
  272. }
  273.  
  274. // get database
  275. $db = $this->database;
  276.  
  277. // get dates
  278. $date = $this->app->date->create();
  279. $now = $db->Quote($date->toSQL());
  280. $null = $db->Quote($db->getNullDate());
  281.  
  282. // get item ordering
  283. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  284.  
  285. $query = "SELECT a.*"
  286. ." FROM ".$this->name." AS a"
  287. .($join ? $join : "")
  288. ." WHERE a.id IN (".implode(",", $ids).")"
  289. ." AND a.".$this->app->user->getDBAccessString($user)
  290. .($published == true ? " AND a.state = 1"
  291. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  292. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  293. .($order ? " ORDER BY " . $order : "");
  294.  
  295. return $this->_queryObjectList($query);
  296. }
  297.  
  298. /*
  299. Function: getByCharacter
  300. Method to retrieve all items starting with a certain character.
  301.  
  302. Parameters:
  303. $application_id - Application id
  304. $char - Character(s)
  305. $not_in - Use not in for matching multiple characters
  306. $published
  307. $user
  308. $orderby
  309. $offset
  310. $limit
  311.  
  312. Returns:
  313. Array - Array of items
  314. */
  315. public function getByCharacter($application_id, $char, $not_in = false, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){
  316.  
  317. // get database
  318. $db = $this->database;
  319.  
  320. // get dates
  321. $date = $this->app->date->create();
  322. $now = $db->Quote($date->toSQL());
  323. $null = $db->Quote($db->getNullDate());
  324.  
  325. // escape and quote character array
  326. if (is_array($char)) {
  327. foreach ($char as $key => $val) {
  328. $char[$key] = "'".$db->escape($val)."'";
  329. }
  330. }
  331.  
  332. // get item ordering
  333. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  334.  
  335. $query = "SELECT a.*"
  336. ." FROM ".ZOO_TABLE_CATEGORY_ITEM." AS ci"
  337. ." JOIN ".$this->name." AS a ON a.id = ci.item_id"
  338. .($join ? $join : "")
  339. ." WHERE a.application_id = ".(int) $application_id
  340. ." AND a.".$this->app->user->getDBAccessString($user)
  341. .($published == true ? " AND a.state = 1"
  342. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  343. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  344. ." AND BINARY LOWER(LEFT(a.name, 1)) ".(is_array($char) ? ($not_in ? "NOT" : null)." IN (".implode(",", $char).")" : " = '".$db->escape($char)."'")
  345. .($order ? " ORDER BY " . $order : "")
  346. .($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");
  347.  
  348. return $this->_queryObjectList($query);
  349. }
  350.  
  351. /*
  352. Function: getByTag
  353. Method to retrieve all items matching a certain tag.
  354.  
  355. Parameters:
  356. $tag - Tag name
  357. $application_id - Application id
  358.  
  359. Returns:
  360. Array - Array of items
  361. */
  362. public function getByTag($application_id, $tag, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){
  363. // get database
  364. $db = $this->database;
  365.  
  366. // get dates
  367. $date = $this->app->date->create();
  368. $now = $db->Quote($date->toSQL());
  369. $null = $db->Quote($db->getNullDate());
  370.  
  371. // get item ordering
  372. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  373.  
  374. $query = "SELECT a.*"
  375. ." FROM ".$this->name." AS a "
  376. ." LEFT JOIN ".ZOO_TABLE_TAG." AS b ON a.id = b.item_id"
  377. .($join ? $join : "")
  378. ." WHERE a.application_id = ".(int) $application_id
  379. ." AND b.name = '".$db->escape($tag)."'"
  380. ." AND a.".$this->app->user->getDBAccessString($user)
  381. .($published == true ? " AND a.state = 1"
  382. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  383. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  384. ." GROUP BY a.id"
  385. .($order ? " ORDER BY " . $order : "")
  386. .($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");
  387.  
  388. return $this->_queryObjectList($query);
  389. }
  390.  
  391. /*
  392. Function: getByType
  393. Method to get types related items.
  394.  
  395. Parameters:
  396. $type_id - Type
  397.  
  398. Returns:
  399. Array - Items
  400. */
  401. public function getByType($type_id, $application_id = false, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){
  402.  
  403. // get database
  404. $db = $this->database;
  405.  
  406. // get dates
  407. $date = $this->app->date->create();
  408. $now = $db->Quote($date->toSQL());
  409. $null = $db->Quote($db->getNullDate());
  410.  
  411. // get item ordering
  412. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  413.  
  414. $query = "SELECT a.*"
  415. ." FROM ".$this->name." AS a"
  416. .($join ? $join : "")
  417. ." WHERE a.type = ".$db->Quote($type_id)
  418. .($application_id !== false ? " AND a.application_id = ".(int) $application_id : "")
  419. ." AND a.".$this->app->user->getDBAccessString($user)
  420. .($published == true ? " AND a.state = 1"
  421. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  422. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  423. ." GROUP BY a.id"
  424. .($order ? " ORDER BY " . $order : "")
  425. .($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");
  426.  
  427. return $this->_queryObjectList($query);
  428. }
  429.  
  430. /*
  431. Function: getByCategory
  432. Method to retrieve all items of a category.
  433.  
  434. Parameters:
  435. $category_id - Category id(s)
  436.  
  437. Returns:
  438. Array - Array of items
  439. */
  440. public function getByCategory($application_id, $category_id, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false) {
  441.  
  442. // get database
  443. $db = $this->database;
  444.  
  445. // get dates
  446. $date = $this->app->date->create();
  447. $now = $db->Quote($date->toSQL());
  448. $null = $db->Quote($db->getNullDate());
  449.  
  450. // get item ordering
  451. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  452.  
  453. $query = "SELECT a.id"
  454. ." FROM ".$this->name." AS a"
  455. ." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
  456. .($join ? $join : "")
  457.  
  458. .($order ? " ORDER BY " . $order : "")
  459. .($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");
  460.  
  461. $list = $this->app->database->queryAssocList($query);
  462. $itemOrig = array_reduce($list, function($acc, $item){
  463. $acc[] = $item['id'];
  464. return $acc;
  465. }, []);
  466.  
  467. $list = JBModelItem::model()->getZooItemsByIds($itemOrig);
  468.  
  469. $list = $this->app->jbarray->sortByArray($list, $itemOrig);
  470.  
  471. return $list;
  472. }
  473.  
  474. /**
  475. * Gets adjacent items
  476. *
  477. * @return array first value is previous item, second value is next item
  478. */
  479. public function getPrevNext($application_id, $category_id, $item_id, $published = false, $user = null, $orderby = "", $ignore_order_priority = false) {
  480.  
  481. // init vars
  482. $prev = null;
  483. $next = null;
  484.  
  485. // get database
  486. $db = $this->database;
  487.  
  488. // get dates
  489. $date = $this->app->date->create();
  490. $now = $db->Quote($date->toSQL());
  491. $null = $db->Quote($db->getNullDate());
  492.  
  493. // get item ordering
  494. list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);
  495.  
  496. $query = "SELECT ROWNUM"
  497. ." FROM ("
  498. ."SELECT @rownum:= @rownum+1 ROWNUM, id"
  499. ." FROM"
  500. ." (SELECT @rownum:=0) r,"
  501. ." (SELECT id"
  502. ." FROM ".$this->name." AS a"
  503. ." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
  504. .($join ? $join : "")
  505. ." WHERE a.application_id = ".(int) $application_id
  506. ." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
  507. ." AND a.".$this->app->user->getDBAccessString($user)
  508. .($published == true ? " AND a.state = 1"
  509. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  510. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  511. ." GROUP BY a.id"
  512. .($order ? " ORDER BY " . $order : "")
  513. .") t1"
  514. .") t2"
  515. ." WHERE id = ".(int) $item_id;
  516.  
  517. if ($row = $this->_queryResult($query)) {
  518.  
  519. $query = "SELECT ROWNUM, id"
  520. ." FROM ("
  521. ."SELECT @rownum:= @rownum+1 ROWNUM, id"
  522. ." FROM"
  523. ." (SELECT @rownum:=0) r,"
  524. ." (SELECT id"
  525. ." FROM ".$this->name." AS a"
  526. ." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
  527. .($join ? $join : "")
  528. ." WHERE a.application_id = ".(int) $application_id
  529. ." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
  530. ." AND a.".$this->app->user->getDBAccessString($user)
  531. .($published == true ? " AND a.state = 1"
  532. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  533. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  534. ." GROUP BY a.id"
  535. .($order ? " ORDER BY " . $order : "")
  536. .") t1"
  537. .") t2"
  538. ." WHERE ROWNUM = ".((int) $row-1) ." OR ROWNUM = ".((int) $row+1);
  539.  
  540. if ($objects = $db->queryObjectList($query)) {
  541. foreach ($objects as $object) {
  542. if ($object->ROWNUM > $row) {
  543. $next = $this->get($object->id);
  544. } else {
  545. $prev = $this->get($object->id);
  546. }
  547. }
  548. }
  549. }
  550.  
  551. return array($prev, $next);
  552.  
  553. }
  554.  
  555. public function getByUser($application_id, $user_id, $type = null, $search = null, $order = null, $offset = null, $limit = null, $published = false) {
  556.  
  557. $options = $this->_getByUserOptions($application_id, $user_id, $type, $search, $published);
  558.  
  559. // Order
  560. $orders = array(
  561. 'date' => 'a.created ASC',
  562. 'rdate' => 'a.created DESC',
  563. 'alpha' => 'a.name ASC',
  564. 'ralpha' => 'a.name DESC',
  565. 'hits' => 'a.hits DESC',
  566. 'rhits' => 'a.hits ASC');
  567.  
  568. $options['order'] = ($order && isset($orders[$order])) ? $orders[$order] : $orders['rdate'];
  569.  
  570. $options = $limit ? array_merge($options, array('offset' => $offset, 'limit' => $limit)) : $options;
  571.  
  572. return $this->all($options);
  573. }
  574.  
  575. public function getItemCountByUser($application_id, $user_id, $type = null, $search = null, $published = false) {
  576. return $this->count(array_merge($this->_getByUserOptions($application_id, $user_id, $type, $search, $published), array('select' => 'a.id')));
  577. }
  578.  
  579. protected function _getByUserOptions($application_id, $user_id, $type = null, $search = null, $published = false) {
  580.  
  581. // select
  582. $select = 'a.*';
  583.  
  584. // get from
  585. $from = $this->name.' AS a';
  586.  
  587. // get data from the table
  588. $where = array();
  589.  
  590. // application filter
  591. $where[] = 'a.application_id = ' . (int) $application_id;
  592.  
  593. // author filter
  594. $where[] = 'a.created_by = ' . (int) $user_id;
  595.  
  596. // user rights
  597. $where[] = 'a.'.$this->app->user->getDBAccessString($this->app->user->get((int) $user_id));
  598.  
  599. // published
  600. if ($published) {
  601.  
  602. $db = $this->database;
  603.  
  604. // get dates
  605. $date = $this->app->date->create();
  606. $now = $db->Quote($date->toSQL());
  607. $null = $db->Quote($db->getNullDate());
  608.  
  609. // Add filters for publishing
  610. $where[] = 'a.state = 1';
  611. $where[] = "(a.publish_up = ".$null." OR a.publish_up <= ".$now.")";
  612. $where[] = "(a.publish_down = ".$null." OR a.publish_down >= ".$now.")";
  613. }
  614.  
  615. // Type
  616. if ($type) {
  617. if (is_array($type)) {
  618. $where[] = 'a.type IN ("' . implode('", "', array_keys($type)) . '")';
  619. } else {
  620. $where[] = 'a.type = "' . (string) $type . '"';
  621. }
  622. }
  623.  
  624. // Search
  625. if ($search) {
  626. $from .= ' LEFT JOIN '.ZOO_TABLE_TAG.' AS t ON a.id = t.item_id';
  627. $where[] = '(LOWER(a.name) LIKE '.$this->app->database->Quote('%'.$this->app->database->escape($search, true).'%', false)
  628. . ' OR LOWER(t.name) LIKE '.$this->app->database->Quote('%'.$this->app->database->escape($search, true).'%', false).')';
  629. }
  630.  
  631. // conditions
  632. $conditions = array(implode(' AND ', $where));
  633.  
  634. return compact('select', 'from', 'conditions');
  635.  
  636. }
  637.  
  638. /*
  639. @deprecated ZOO version 2.5 beta, use getByCategory instead
  640. */
  641. public function getFromCategory($application_id, $category_id, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0) {
  642. return $this->getByCategory($application_id, $category_id, $published, $user, $orderby, $offset, $limit);
  643. }
  644.  
  645. /*
  646. Function: getItemCountFromCategory
  647. Method to retrieve items count of a category.
  648.  
  649. Parameters:
  650. $category_id - Category id(s)
  651.  
  652. Returns:
  653. Array - Array of items
  654. */
  655. public function getItemCountFromCategory($application_id, $category_id, $published = false, $user = null){
  656.  
  657. // get database
  658. $db = $this->database;
  659.  
  660. // get dates
  661. $date = $this->app->date->create();
  662. $now = $db->Quote($date->toSQL());
  663. $null = $db->Quote($db->getNullDate());
  664.  
  665. $query = "SELECT a.id"
  666. ." FROM ".$this->name." AS a"
  667. ." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
  668. ." WHERE a.application_id = ".(int) $application_id
  669. ." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
  670. ." AND a.".$this->app->user->getDBAccessString($user)
  671. .($published == true ? " AND a.state = 1"
  672. ." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  673. ." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  674. ." GROUP BY a.id";
  675.  
  676. $db->query($query);
  677.  
  678. return $db->getNumRows();
  679.  
  680. }
  681.  
  682. /*
  683. Function: search
  684. Method to retrieve all items matching search data.
  685.  
  686. Parameters:
  687. $search_string - the search string
  688. $app_id - specify an application id to limit the search scope
  689.  
  690. Returns:
  691. Array - Array of items
  692. */
  693. public function search($search_string, $app_id = 0) {
  694.  
  695. // get database
  696. $db = $this->database;
  697. $db_search = $db->Quote('%'.$db->escape( $search_string, true ).'%', false);
  698.  
  699. $query = "SELECT a.*"
  700. ." FROM ".$this->name." AS a"
  701. ." LEFT JOIN ".ZOO_TABLE_SEARCH." AS b ON a.id = b.item_id"
  702. ." WHERE (LOWER(b.value) LIKE LOWER(" . $db_search . ")"
  703. ." OR LOWER(a.name) LIKE LOWER(" . $db_search . "))"
  704. . (empty($app_id) ? "" : " AND application_id = " . $app_id)
  705. ." AND a.searchable=1"
  706. ." GROUP BY a.id";
  707.  
  708. return $this->_queryObjectList($query);
  709. }
  710.  
  711. /*
  712. Function: searchElements
  713. Method to retrieve all items matching search data.
  714.  
  715. Parameters:
  716. $elements_array - key = element_name, value = search string
  717. $app_id - specify an application id to limit the search scope
  718.  
  719. Returns:
  720. Array - Array of items
  721. */
  722. public function searchElements($elements_array, $app_id = 0) {
  723.  
  724. // get database
  725. $db = $this->database;
  726.  
  727. $i = 0;
  728. $join = array();
  729. $where = array();
  730. foreach ($elements_array as $name => $search_string) {
  731. $as = "table" . $i;
  732. $db_name = $db->Quote($db->escape( $name, true ), false);
  733. $db_search = $db->Quote('%'.$db->escape( $search_string, true ).'%', false);
  734. $join[] = " LEFT JOIN ".ZOO_TABLE_SEARCH." AS " . $as . " ON a.id = " . $as . ".item_id";
  735. $where[] = $as.".element_id = ".$db_name." AND LOWER(".$as.".value) LIKE LOWER(".$db_search.")";
  736. $i++;
  737. }
  738.  
  739. $query = "SELECT a.*"
  740. ." FROM ".$this->name." AS a "
  741. . implode(" ", $join)
  742. ." WHERE "
  743. . implode(" AND ", $where)
  744. . (empty($app_id) ? "" : " AND application_id = " . $app_id)
  745. ." AND a.searchable=1"
  746. ." GROUP BY a.id";
  747.  
  748. return $this->_queryObjectList($query);
  749. }
  750.  
  751. /*
  752. Function: getUsers
  753. Method to get users of items
  754.  
  755. Parameters:
  756. $app_id - Application id
  757.  
  758. Returns:
  759. Array - Array of items
  760. */
  761. public function getUsers($app_id) {
  762. $query = 'SELECT DISTINCT u.id, u.name'
  763. .' FROM '.$this->name.' AS i'
  764. .' JOIN #__users AS u ON i.created_by = u.id'
  765. . ((empty($app_id)) ? "" : " WHERE i.application_id = ".$app_id);
  766.  
  767. return $this->database->queryObjectList($query, 'id');
  768. }
  769.  
  770. /*
  771. @deprecated version 2.5.5, use parents has() function
  772. */
  773. public function isInitialized($key) {
  774. return $this->has($key);
  775. }
  776.  
  777. protected function _getItemOrder($order, $ignore_order_priority = false) {
  778.  
  779. // if string, try to convert ordering
  780. if (is_string($order)) {
  781. $order = $this->app->itemorder->convert($order);
  782. }
  783.  
  784. $result = array(null, null);
  785. $order = (array) $order;
  786.  
  787. if (in_array('_ignore_priority', $order)) {
  788. $ignore_order_priority = true;
  789. unset($order['_ignore_priority']);
  790. }
  791.  
  792. // trigger order event
  793. $this->app->event->dispatcher->notify($this->app->event->create($order, 'item:changeorder'));
  794.  
  795. // remove empty and duplicate values
  796. $order = array_unique(array_filter($order));
  797.  
  798. // if random return immediately
  799. if (in_array('_random', $order)) {
  800. $result[1] = 'RAND()';
  801. return $result;
  802. }
  803.  
  804. // get order dir
  805. if (($index = array_search('_reversed', $order)) !== false) {
  806. $reversed = 'DESC';
  807. unset($order[$index]);
  808. } else {
  809. $reversed = 'ASC';
  810. }
  811.  
  812. // get ordering type
  813. $alphanumeric = false;
  814. if (($index = array_search('_alphanumeric', $order)) !== false) {
  815. $alphanumeric = true;
  816. unset($order[$index]);
  817. }
  818.  
  819. // set default ordering attribute
  820. if (empty($order)) {
  821. $order[] = '_itemname';
  822. }
  823.  
  824. // if there is a none core element present, ordering will only take place for those elements
  825. if (count($order) > 1) {
  826. $order = array_filter($order, create_function('$a', 'return strpos($a, "_item") === false;'));
  827. }
  828.  
  829. // order by core attribute
  830. foreach ($order as $element) {
  831.  
  832. if (strpos($element, '_item') === 0) {
  833. $var = str_replace('_item', '', $element);
  834. if ($alphanumeric) {
  835. $result[1] = $reversed == 'ASC' ? "a.$var+0<>0 DESC, a.$var+0, a.$var" : "a.$var+0<>0, a.$var+0 DESC, a.$var DESC";
  836. } else {
  837. $result[1] = $reversed == 'ASC' ? "a.$var" : "a.$var DESC";
  838. }
  839.  
  840. }
  841. }
  842.  
  843. // else order by elements
  844. if (!isset($result[1])) {
  845. $result[0] = " LEFT JOIN ".ZOO_TABLE_SEARCH." AS s ON a.id = s.item_id AND s.element_id IN ('".implode("', '", $order)."')";
  846. if ($alphanumeric) {
  847. $result[1] = $reversed == 'ASC' ? "ISNULL(s.value), s.value+0<>0 DESC, s.value+0, s.value" : "s.value+0<>0, s.value+0 DESC, s.value DESC";
  848. } else {
  849. $result[1] = $reversed == 'ASC' ? "s.value" : "s.value DESC";
  850. }
  851. }
  852.  
  853. // If there wasn't _ignore_priority in the order array, prefix priority
  854. if (!$ignore_order_priority) {
  855. $result[1] = $result[1] ? 'a.priority DESC, ' . $result[1] : 'a.priority DESC';
  856. }
  857.  
  858. // trigger init event
  859. $this->app->event->dispatcher->notify($this->app->event->create($order, 'item:orderquery', array('result' => &$result)));
  860.  
  861. return $result;
  862.  
  863. }
  864.  
  865. }
  866.  
  867. /*
  868. Class: ItemTableException
  869. */
  870. class ItemTableException extends AppException {}

Сообщение отредактировал Шингисович: 13 March 2017 - 06:17

  • 0

Делаю сайты в Казахстане, Астане, webmarka.kz


#7 CB9TOIIIA

CB9TOIIIA

Отправлено 13 March 2017 - 06:52

Шингисович сказал(а) 13 Мар 2017 - 04:48:

 

На мультиязычном сайте хак нарушил работу выборки айтемов в разных языковых каталогах. Поэтому вынужден был отказаться от него. :(

 

 

В теории он делает тоже самое - т.е. ID отдает.

diff: https://github.com/J...0fd17d4e0abc313

 

Возможно что-то не так, но не могу знать.


  • 0

#8 Шингисович

Шингисович

Отправлено 13 March 2017 - 13:29

CB9TOIIIA сказал(а) 13 Мар 2017 - 05:52:

В теории он делает тоже самое - т.е. ID отдает.

diff: https://github.com/J...0fd17d4e0abc313

 

Возможно что-то не так, но не могу знать.

А можете выложить свой вариант файла сюда именно с изменением одного пункта только, без включения других хаков, которые здесь например есть, в этом файле:

  1. / zoo_hack_start
  2. //." AND a.".$this->app->user->getDBAccessString($user)
  3. .($published == true ? " AND a.state = 1" : "")
  4. //." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
  5. //." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
  6. // zoo_hack_end

ну и других изменения, касающихся переиндексации и прочих моментов.


  • 0

Делаю сайты в Казахстане, Астане, webmarka.kz


#9 CB9TOIIIA

CB9TOIIIA

Отправлено 13 March 2017 - 13:39

На проекте

Прикрепленные файлы

  • Прикрепленный файл  item.php   24.84К   235 Количество загрузок:

  • 1

#10 Шингисович

Шингисович

Отправлено 13 March 2017 - 14:14

CB9TOIIIA сказал(а) 13 Мар 2017 - 12:39:

На проекте

Теперь с вашим файлом заработало без ошибок с выборкой айтемов!!! Значит где-то в коде была в моем файле ошибка!

Спасибо огромное!! Сайт гораздо быстрее работать стал!


  • 0

Делаю сайты в Казахстане, Астане, webmarka.kz






Темы с аналогичным тегами zoo, оптимизация, костыль, денис_молодец, женя_тоже_ничего, forumlvlup, likeaboss, никто_не_читает_теги

Click to return to top of page in style!