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


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

[Оптимизация] 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   689.22К   0 Количество загрузок:
  • Прикрепленный файл  clipboard.png   537.93К   0 Количество загрузок:
  • Прикрепленный файл  clipboard2.png   694.56К   0 Количество загрузок:

Сообщение отредактировал 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

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

 

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


  • 0

#5 grickov84

grickov84

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

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


  • 0

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

Шингисович

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

 

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

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

 

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

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

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

 

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

 

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

administrator/components/com_zoo/tables/item.php

<?php
/**
 * @package   com_zoo
 * @author    YOOtheme http://www.yootheme.com
 * @copyright Copyright (C) YOOtheme GmbH
 * @license   http://www.gnu.org/licenses/gpl.html GNU/GPL
 */

/*
	Class: ItemTable
		The table class for items.
*/
class ItemTable extends AppTable {

	public function __construct($app) {
		parent::__construct($app, ZOO_TABLE_ITEM);
	}

	protected function _initObject($object) {

		parent::_initObject($object);

		// workaround for php bug, which calls constructor before filling values
		if (is_string($object->params) || is_null($object->params)) {
			// decorate data as object
			$object->params = $this->app->parameter->create($object->params);
		}

		if (is_string($object->elements) || is_null($object->elements)) {
			// decorate data as object
			$object->elements = $this->app->data->create($object->elements);
		}

		// add to cache
		$key_name = $this->key;

		if ($object->$key_name && !key_exists($object->$key_name, $this->_objects)) {
			$this->_objects[$object->$key_name] = $object;
		}

		// trigger init event
		$this->app->event->dispatcher->notify($this->app->event->create($object, 'item:init'));

		return $object;
	}

	/*
		Function: save
			Override. Save object to database table.

		Returns:
			Boolean.
	*/
	public function save($object) {

		if (!($application = $object->getApplication())) {
			throw new ItemTableException('Invalid application id');
		}

		if (!is_string($object->type) || empty($object->type)) {
			throw new ItemTableException('Invalid type id');
		}

		if ($object->name == '') {
			throw new ItemTableException('Invalid name');
		}

		if ($object->alias == '' || $object->alias != $this->app->string->sluggify($object->alias)) {
			throw new ItemTableException('Invalid slug');
		}

		if ($this->app->alias->item->checkAliasExists($object->alias, $object->id)) {
			throw new ItemTableException('Alias already exists, please choose a unique alias');
		}

		$new = !(bool) $object->id;

		// trigger save event
		$this->app->event->dispatcher->notify($this->app->event->create($object, 'item:save', compact('new')));

		$result = parent::save($object);

		// init vars
		$db           = $this->database;
		$search_data  = array();

		foreach ($object->getElements() as $id => $element) {
			// get search data
			if ($data = $element->getSearchData()) {
				$search_data[] = "(".$object->id.", ".$db->quote($id).", ".$db->quote($data).")";
			}
		}

		// delete old search data
		$query = "DELETE FROM ".ZOO_TABLE_SEARCH
				." WHERE item_id = ".(int) $object->id;
		$db->query($query);

		// insert new search data
		if (count($search_data)) {
			$query = "INSERT INTO ".ZOO_TABLE_SEARCH
					." VALUES ".implode(", ", $search_data);
			$db->query($query);
		}

		// save tags
		$this->app->table->tag->save($object);

		// trigger saved event
		$this->app->event->dispatcher->notify($this->app->event->create($object, 'item:saved', compact('new')));

		return $result;
	}

	/*
		Function: delete
			Override. Delete object from database table.

		Returns:
			Boolean.
	*/
	public function delete($object) {

		// get database
		$db = $this->database;

		// delete item to category relations
		$query = "DELETE FROM ".ZOO_TABLE_CATEGORY_ITEM
			    ." WHERE item_id = ".(int) $object->id;
		$db->query($query);

		// delete related comments
		$query = "DELETE FROM ".ZOO_TABLE_COMMENT
			    ." WHERE item_id = ".(int) $object->id;
		$db->query($query);

		// delete related search data rows
		$query = "DELETE FROM ".ZOO_TABLE_SEARCH
				." WHERE item_id = ". (int) $object->id;
		$db->query($query);

		// delete related rating data rows
		$query = "DELETE FROM ".ZOO_TABLE_RATING
				." WHERE item_id = ". (int) $object->id;
		$db->query($query);

		// delete related tag data rows
		$query = "DELETE FROM ".ZOO_TABLE_TAG
				." WHERE item_id = ". (int) $object->id;
		$db->query($query);

		$result = parent::delete($object);

		// trigger deleted event
		$this->app->event->dispatcher->notify($this->app->event->create($object, 'item:deleted'));

		return $result;
	}

	/*
		Function: hit
			Increment item hits.

		Returns:
			Boolean.
	*/
	public function hit($object) {

		// get database
		$db  = $this->database;
		$key = $this->key;

		// increment hits
		if ($object->$key) {
			$query = "UPDATE ".$this->name
				." SET hits = (hits + 1)"
				." WHERE $key = ".(int) $object->$key;
			$db->query($query);
			$object->hits++;
			return true;
		}

		return false;
	}

	/*
		Function: getApplicationItemCount
			Method to get application related item count.

		Parameters:
			$application_id - Application id

		Returns:
			Int
	*/
	public function getApplicationItemCount($application_id) {
 		$query = "SELECT count(a.id) AS item_count"
		        ." FROM ".$this->name." AS a"
		        ." WHERE a.application_id = ".(int) $application_id;

		return (int) $this->_queryResult($query);
	}

	/*
		Function: getTypeItemCount
			Method to get types related item count.

		Parameters:
			$type - Type

		Returns:
			Int
	*/
	public function getTypeItemCount($type){

		// get database
		$db = $this->database;

		$group = $type->getApplication()->getGroup();
 		$query = "SELECT count(a.id) AS item_count"
		        ." FROM ".$this->name." AS a"
		        ." JOIN ".ZOO_TABLE_APPLICATION." AS b ON a.application_id = b.id"
		        ." WHERE a.type = ".$db->Quote($type->id)
       			." AND b.application_group = ".$db->Quote($group);

		return (int) $this->_queryResult($query);

	}

	/*
		@deprecated version 2.5 beta
	*/
	public function findAll($application_id = false, $published = false, $user = null, $options = array()) {

		// get database
		$db = $this->database;

		// get date
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// set query options
		$conditions =
		     ($application_id !== false ? "application_id = ".(int) $application_id : "")
			." AND ".$this->app->user->getDBAccessString($user)
			.($published == true ? " AND state = 1"
			." AND (publish_up = ".$null." OR publish_up <= ".$now.")"
			." AND (publish_down = ".$null." OR publish_down >= ".$now.")": "");

		return $this->all(array_merge(compact('conditions'), $options));
	}

	/*
		Function: getByCharacter
			Method to retrieve all items starting with a certain character.

		Parameters:
			$application_id - Application id
			$char - Character(s)
			$not_in - Use not in for matching multiple characters

		Returns:
			Array - Array of items
	*/
	public function getByIds($ids, $published = false, $user = null, $orderby = '', $ignore_order_priority = false){

		$ids = (array) $ids;

		if (empty($ids)) {
			return array();
		}

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT a.*"
			." FROM ".$this->name." AS a"
			.($join ? $join : "")
			." WHERE a.id IN (".implode(",", $ids).")"
			." AND a.".$this->app->user->getDBAccessString($user)
			.($published == true ? " AND a.state = 1"
			." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
			." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
			.($order ? " ORDER BY " . $order : "");

		return $this->_queryObjectList($query);
	}

	/*
		Function: getByCharacter
			Method to retrieve all items starting with a certain character.

		Parameters:
			$application_id - Application id
			$char - Character(s)
			$not_in - Use not in for matching multiple characters
			$published
			$user
			$orderby
			$offset
			$limit

		Returns:
			Array - Array of items
	*/
	public function getByCharacter($application_id, $char, $not_in = false, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// escape and quote character array
		if (is_array($char)) {
			foreach ($char as $key => $val) {
				$char[$key] = "'".$db->escape($val)."'";
			}
		}

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT a.*"
			." FROM ".ZOO_TABLE_CATEGORY_ITEM." AS ci"
			." JOIN ".$this->name." AS a ON a.id = ci.item_id"
			.($join ? $join : "")
			." WHERE a.application_id = ".(int) $application_id
			." AND a.".$this->app->user->getDBAccessString($user)
			.($published == true ? " AND a.state = 1"
			." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
			." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
			." AND BINARY LOWER(LEFT(a.name, 1)) ".(is_array($char) ? ($not_in ? "NOT" : null)." IN (".implode(",", $char).")" : " = '".$db->escape($char)."'")
			.($order ? " ORDER BY " . $order : "")
			.($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");

		return $this->_queryObjectList($query);
	}

	/*
		Function: getByTag
			Method to retrieve all items matching a certain tag.

		Parameters:
			$tag - Tag name
			$application_id - Application id

		Returns:
			Array - Array of items
	*/
	public function getByTag($application_id, $tag, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){
		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT a.*"
				." FROM ".$this->name." AS a "
				." LEFT JOIN ".ZOO_TABLE_TAG." AS b ON a.id = b.item_id"
				.($join ? $join : "")
				." WHERE a.application_id = ".(int) $application_id
				." AND b.name = '".$db->escape($tag)."'"
				." AND a.".$this->app->user->getDBAccessString($user)
				.($published == true ? " AND a.state = 1"
				." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
				." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
				." GROUP BY a.id"
				.($order ? " ORDER BY " . $order : "")
				.($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");

		return $this->_queryObjectList($query);
	}

	/*
		Function: getByType
			Method to get types related items.

		Parameters:
			$type_id - Type

		Returns:
			Array - Items
	*/
	public function getByType($type_id, $application_id = false, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false){

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT a.*"
			." FROM ".$this->name." AS a"
			.($join ? $join : "")
			." WHERE a.type = ".$db->Quote($type_id)
			.($application_id !== false ? " AND a.application_id = ".(int) $application_id : "")
			." AND a.".$this->app->user->getDBAccessString($user)
			.($published == true ? " AND a.state = 1"
			." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
			." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
			." GROUP BY a.id"
			.($order ? " ORDER BY " . $order : "")
			.($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");

		return $this->_queryObjectList($query);
	}

	/*
		Function: getByCategory
			Method to retrieve all items of a category.

		Parameters:
			$category_id - Category id(s)

		Returns:
			Array - Array of items
	*/
	public function getByCategory($application_id, $category_id, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0, $ignore_order_priority = false) {

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT a.id"
 			." FROM ".$this->name." AS a"
 			." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
 			.($join ? $join : "")

 			.($order ? " ORDER BY " . $order : "")
 			.($limit ? " LIMIT ".(int) $offset.",".(int) $limit : "");
 

			$list = $this->app->database->queryAssocList($query);
			$itemOrig = array_reduce($list, function($acc, $item){
					$acc[] = $item['id'];
					return $acc;
			}, []);

			$list = JBModelItem::model()->getZooItemsByIds($itemOrig);

			$list = $this->app->jbarray->sortByArray($list, $itemOrig);

			return $list;
 	}

	/**
	 * Gets adjacent items
	 *
	 * @return array first value is previous item, second value is next item
	 */
	public function getPrevNext($application_id, $category_id, $item_id, $published = false, $user = null, $orderby = "", $ignore_order_priority = false) {

		// init vars
		$prev = null;
		$next = null;

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		// get item ordering
		list($join, $order) = $this->_getItemOrder($orderby, $ignore_order_priority);

		$query = "SELECT ROWNUM"
				." FROM ("
					."SELECT @rownum:= @rownum+1 ROWNUM, id"
					." FROM"
					." (SELECT @rownum:=0) r,"
					." (SELECT id"
						." FROM ".$this->name." AS a"
						." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
						.($join ? $join : "")
						." WHERE a.application_id = ".(int) $application_id
						." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
						." AND a.".$this->app->user->getDBAccessString($user)
						.($published == true ? " AND a.state = 1"
						." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
						." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
						." GROUP BY a.id"
						.($order ? " ORDER BY " . $order : "")
					.") t1"
				.") t2"
				." WHERE id = ".(int) $item_id;

		if ($row = $this->_queryResult($query)) {

			$query = "SELECT ROWNUM, id"
					." FROM ("
						."SELECT @rownum:= @rownum+1 ROWNUM, id"
						." FROM"
						." (SELECT @rownum:=0) r,"
						." (SELECT id"
							." FROM ".$this->name." AS a"
							." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
							.($join ? $join : "")
							." WHERE a.application_id = ".(int) $application_id
							." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
							." AND a.".$this->app->user->getDBAccessString($user)
							.($published == true ? " AND a.state = 1"
							." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
							." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
							." GROUP BY a.id"
							.($order ? " ORDER BY " . $order : "")
						.") t1"
					.") t2"
					." WHERE ROWNUM = ".((int) $row-1) ." OR ROWNUM = ".((int) $row+1);

			if ($objects = $db->queryObjectList($query)) {
				foreach ($objects as $object) {
					if ($object->ROWNUM > $row) {
						$next = $this->get($object->id);
					} else {
						$prev = $this->get($object->id);
					}
				}
			}
		}

		return array($prev, $next);

	}

	public function getByUser($application_id, $user_id, $type = null, $search = null, $order = null, $offset = null, $limit = null, $published = false) {

		$options = $this->_getByUserOptions($application_id, $user_id, $type, $search, $published);

		// Order
		$orders = array(
			'date'   => 'a.created ASC',
			'rdate'  => 'a.created DESC',
			'alpha'  => 'a.name ASC',
			'ralpha' => 'a.name DESC',
			'hits'   => 'a.hits DESC',
			'rhits'  => 'a.hits ASC');

		$options['order'] = ($order && isset($orders[$order])) ? $orders[$order] : $orders['rdate'];

		$options = $limit ? array_merge($options, array('offset' => $offset, 'limit' => $limit)) : $options;

		return $this->all($options);
	}

	public function getItemCountByUser($application_id, $user_id, $type = null, $search = null, $published = false) {
		return $this->count(array_merge($this->_getByUserOptions($application_id, $user_id, $type, $search, $published), array('select' => 'a.id')));
	}

	protected function _getByUserOptions($application_id, $user_id, $type = null, $search = null, $published = false) {

		// select
		$select = 'a.*';

		// get from
		$from = $this->name.' AS a';

        // get data from the table
        $where = array();

        // application filter
        $where[] = 'a.application_id = ' . (int) $application_id;

        // author filter
        $where[] = 'a.created_by = ' . (int) $user_id;

        // user rights
        $where[] = 'a.'.$this->app->user->getDBAccessString($this->app->user->get((int) $user_id));

		// published
		if ($published) {

			$db = $this->database;

			// get dates
			$date = $this->app->date->create();
			$now  = $db->Quote($date->toSQL());
			$null = $db->Quote($db->getNullDate());

			// Add filters for publishing
			$where[] = 'a.state = 1';
			$where[] = "(a.publish_up = ".$null." OR a.publish_up <= ".$now.")";
			$where[] = "(a.publish_down = ".$null." OR a.publish_down >= ".$now.")";
		}

        // Type
        if ($type) {
        	if (is_array($type)) {
            	$where[] = 'a.type IN ("' . implode('", "', array_keys($type)) . '")';
        	} else {
            	$where[] = 'a.type = "' . (string) $type . '"';
        	}
		}

		// Search
		if ($search) {
			$from   .= ' LEFT JOIN '.ZOO_TABLE_TAG.' AS t ON a.id = t.item_id';
			$where[] = '(LOWER(a.name) LIKE '.$this->app->database->Quote('%'.$this->app->database->escape($search, true).'%', false)
				. ' OR LOWER(t.name) LIKE '.$this->app->database->Quote('%'.$this->app->database->escape($search, true).'%', false).')';
		}

		// conditions
		$conditions = array(implode(' AND ', $where));

		return compact('select', 'from', 'conditions');

	}

	/*
		@deprecated ZOO version 2.5 beta, use getByCategory instead
	*/
	public function getFromCategory($application_id, $category_id, $published = false, $user = null, $orderby = "", $offset = 0, $limit = 0) {
		return $this->getByCategory($application_id, $category_id, $published, $user, $orderby, $offset, $limit);
	}

	/*
		Function: getItemCountFromCategory
			Method to retrieve items count of a category.

		Parameters:
			$category_id - Category id(s)

		Returns:
			Array - Array of items
	*/
	public function getItemCountFromCategory($application_id, $category_id, $published = false, $user = null){

		// get database
		$db = $this->database;

		// get dates
		$date = $this->app->date->create();
		$now  = $db->Quote($date->toSQL());
		$null = $db->Quote($db->getNullDate());

		$query = "SELECT a.id"
			." FROM ".$this->name." AS a"
			." LEFT JOIN ".ZOO_TABLE_CATEGORY_ITEM." AS b ON a.id = b.item_id"
			." WHERE a.application_id = ".(int) $application_id
			." AND b.category_id ".(is_array($category_id) ? " IN (".implode(",", $category_id).")" : " = ".(int) $category_id)
			." AND a.".$this->app->user->getDBAccessString($user)
			.($published == true ? " AND a.state = 1"
			." AND (a.publish_up = ".$null." OR a.publish_up <= ".$now.")"
			." AND (a.publish_down = ".$null." OR a.publish_down >= ".$now.")": "")
			." GROUP BY a.id";

		$db->query($query);

		return $db->getNumRows();

	}

	/*
		Function: search
			Method to retrieve all items matching search data.

		Parameters:
			$search_string - the search string
			$app_id - specify an application id to limit the search scope

		Returns:
			Array - Array of items
	*/
	public function search($search_string, $app_id = 0) {

		// get database
		$db = $this->database;
		$db_search = $db->Quote('%'.$db->escape( $search_string, true ).'%', false);

		$query = "SELECT a.*"
				." FROM ".$this->name." AS a"
				." LEFT JOIN ".ZOO_TABLE_SEARCH." AS b ON a.id = b.item_id"
				." WHERE (LOWER(b.value) LIKE LOWER(" . $db_search . ")"
				." OR LOWER(a.name) LIKE LOWER(" . $db_search . "))"
				. (empty($app_id) ? "" : " AND application_id = " . $app_id)
				." AND a.searchable=1"
				." GROUP BY a.id";

		return $this->_queryObjectList($query);
	}

	/*
		Function: searchElements
			Method to retrieve all items matching search data.

		Parameters:
			$elements_array - key = element_name, value = search string
			$app_id - specify an application id to limit the search scope

		Returns:
			Array - Array of items
	*/
	public function searchElements($elements_array, $app_id = 0) {

		// get database
		$db = $this->database;

		$i = 0;
		$join = array();
		$where = array();
		foreach ($elements_array as $name => $search_string) {
			$as = "table" . $i;
			$db_name = $db->Quote($db->escape( $name, true ), false);
			$db_search = $db->Quote('%'.$db->escape( $search_string, true ).'%', false);
			$join[] = " LEFT JOIN ".ZOO_TABLE_SEARCH." AS " . $as . " ON a.id = " . $as . ".item_id";
			$where[] = $as.".element_id = ".$db_name." AND LOWER(".$as.".value) LIKE LOWER(".$db_search.")";
			$i++;
		}

		$query = "SELECT a.*"
				." FROM ".$this->name." AS a "
				. implode(" ", $join)
				." WHERE "
				. implode(" AND ", $where)
				. (empty($app_id) ? "" : " AND application_id = " . $app_id)
				." AND a.searchable=1"
				." GROUP BY a.id";

		return $this->_queryObjectList($query);
	}

	/*
		Function: getUsers
			Method to get users of items

		Parameters:
			$app_id - Application id

		Returns:
			Array - Array of items
	*/
	public function getUsers($app_id) {
		$query = 'SELECT DISTINCT u.id, u.name'
			    .' FROM '.$this->name.' AS i'
			    .' JOIN #__users AS u ON i.created_by = u.id'
			    . ((empty($app_id)) ? "" : " WHERE i.application_id = ".$app_id);

		return $this->database->queryObjectList($query, 'id');
	}

	/*
		@deprecated version 2.5.5, use parents has() function
	*/
	public function isInitialized($key) {
		return $this->has($key);
	}

	protected function _getItemOrder($order, $ignore_order_priority = false) {

		// if string, try to convert ordering
		if (is_string($order)) {
			$order = $this->app->itemorder->convert($order);
		}

		$result = array(null, null);
		$order = (array) $order;

		if (in_array('_ignore_priority', $order)) {
			$ignore_order_priority = true;
			unset($order['_ignore_priority']);
		}

		// trigger order event
		$this->app->event->dispatcher->notify($this->app->event->create($order, 'item:changeorder'));

		// remove empty and duplicate values
		$order = array_unique(array_filter($order));

		// if random return immediately
		if (in_array('_random', $order)) {
			$result[1] = 'RAND()';
			return $result;
		}

		// get order dir
		if (($index = array_search('_reversed', $order)) !== false) {
			$reversed = 'DESC';
			unset($order[$index]);
		} else {
			$reversed = 'ASC';
		}

		// get ordering type
		$alphanumeric = false;
		if (($index = array_search('_alphanumeric', $order)) !== false) {
			$alphanumeric = true;
			unset($order[$index]);
		}

		// set default ordering attribute
		if (empty($order)) {
			$order[] = '_itemname';
		}

		// if there is a none core element present, ordering will only take place for those elements
		if (count($order) > 1) {
			$order = array_filter($order, create_function('$a', 'return strpos($a, "_item") === false;'));
		}

		// order by core attribute
		foreach ($order as $element) {

			if (strpos($element, '_item') === 0) {
				$var = str_replace('_item', '', $element);
				if ($alphanumeric) {
					$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";
				} else {
					$result[1] = $reversed == 'ASC' ? "a.$var" : "a.$var DESC";
				}

			}
		}

		// else order by elements
		if (!isset($result[1])) {
			$result[0] = " LEFT JOIN ".ZOO_TABLE_SEARCH." AS s ON a.id = s.item_id AND s.element_id IN ('".implode("', '", $order)."')";
			if ($alphanumeric) {
				$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";
			} else {
				$result[1] = $reversed == 'ASC' ? "s.value" : "s.value DESC";
			}
		}

		// If there wasn't _ignore_priority in the order array, prefix priority
		if (!$ignore_order_priority) {
			$result[1] = $result[1] ? 'a.priority DESC, ' . $result[1] : 'a.priority DESC';
		}

		// trigger init event
		$this->app->event->dispatcher->notify($this->app->event->create($order, 'item:orderquery', array('result' => &$result)));

		return $result;

	}

}

/*
	Class: ItemTableException
*/
class ItemTableException extends AppException {}

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

  • 0

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


#7 CB9TOIIIA

CB9TOIIIA

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

 

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

 

 

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

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

 

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


  • 0

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

Шингисович

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

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

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

 

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

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

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

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


  • 0

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


#9 CB9TOIIIA

CB9TOIIIA

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

На проекте

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

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

  • 1

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

Шингисович

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

На проекте

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

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


  • 0

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






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

Click to return to top of page in style!