Доброго времени суток!
Есть сайт (интернет-магазин), который был написан сторонним разработчиком на yii. Сам не соображаю в yii, да и в программировании в общем туго. Но страницы каталога ужасно долго грузятся. Я уже устал видеть в webmaster.yandex.ru критичные ошибки "Долгий ответ сервера". Каталог выглядит стандартно: вывод слева фильтра по товарам и справа сами товары. Я не буду приводить здесь таблицу mysql, как устроены характеристики, атрибуты товаров (хотя полагаю, что надо бы конечно).
Вопрос такой. Фильтр подключается как я понимаю как виджет $this->widget('widget.filters.AFilters');
Сам виджет выглядит так:
class AFilters extends CWidget {
private function _publishAssets()
{
$assets = dirname(__FILE__).'/assets';
$baseUrl = Yii::app()->assetManager->publish($assets);
$cs=Yii::app()->getClientScript();
$cs->registerScriptFile("{$baseUrl}/js/attr_filter.js", CClientScript::POS_HEAD);
$cs->registerScriptFile("{$baseUrl}/js/jquery-ui.min.js", CClientScript::POS_HEAD);
$cs->registerCssFile("{$baseUrl}/css/jquery-ui.css");
# $cs->registerCssFile("http://code.jquery.com/ui/1.10.3/themes/south-street/jquery-ui.css");
}
public function run(){
$this->_publishAssets();
$attributes = $attributeValues = [];
$categoryID = Yii::app()->request->getParam('id');
if (Yii::app()->controller->action->id == 'category'){
if (Yii::app()->controller->id == 'shop') {
$max_price = Category::model()->getMaxPrice();
$min_price = Category::model()->getMinPrice();
/** @var $category Category */
$category = Category::model()->findByPk($categoryID);
$criteria = $category->getProductsCriteria();
} else {
$sql = 'SELECT MAX(price) FROM product WHERE 1';
$connection = Yii::app()->db;
$command = $connection->createCommand($sql);
$max_price = $command->queryScalar();;
$min_price = 0;
$model = AdviceCategory::model()->findByPk($categoryID);
$newCriteria = new CDbCriteria();
$newCriteria->select = 't.id';
$newCriteria->index = 'id';
$criteria = $model->getProductsCriteriaByCondition($newCriteria, false);
}
$criteria->index = 'id';
foreach ($_GET as $paramName => $paramValue) {
if (strpos($paramName, 'attr_') === 0) {
$paramParts = explode('_', $paramName);
$counter = 1;
$paramCriteria = new CDbCriteria();
$conditions[] = '(productAttributes.value = "' . $paramValue . '" AND productAttributes.id_attrs = "' . intval(end($paramParts)) . '")';
$paramCriteria->addCondition(implode(' OR ', $conditions), 'OR');
$paramCriteria->group = 'id_product';
$paramCriteria->having = 'count(id_product)=' . $counter;
$paramCriteria->with = array('productAttributes');
$paramCriteria->index = 'id';
$paramCriteria->select = 't.id';
$paramCriteria->together = true;
$criteria->mergeWith($paramCriteria);
}
}
$products = Product::model()->cache(CACHE_TIME)->findAll($criteria);
$productIDs = array_keys($products);
if ($productIDs) {
$criteria = new CDbCriteria();
$criteria->index = 'id_attrs';
$criteria->group = 'id_attrs';
$criteria->addInCondition('id_product', $productIDs);
$criteria->addCondition('value <> ""');
$attributeValues = EavValue::model()->findAll($criteria);
if ($attributeValues) {
$criteria = new CDbCriteria();
$criteria->addInCondition('id', array_keys($attributeValues));
$criteria->addCondition('use_filter = 1');
$criteria->index = 'id';
$attributes = EavAttribute::model()->findAll($criteria);
}
}
$values = [];
foreach ($attributes as $attribute) {
$criteria = new CDbCriteria();
$criteria->group = 't.id_attrs, t.value';
$criteria->addInCondition('id_product', $productIDs);
$criteria->addCondition('t.id_attrs = :id_attrs');
$criteria->params[':id_attrs'] = $attribute->id;
$criteria->addCondition('t.value <> ""');
$criteria->order = 't.enum, t.value';
$values[$attribute->id]['type'] = $attribute->type;
$values[$attribute->id]['name'] = $attribute->name;
// $values[$attribute->id]['values'] = EavValue::model()->findAll($criteria);
if ($attribute->type != 2) {
$values[$attribute->id]['values'] = EavValue::model()->cache(CACHE_TIME)->findAll($criteria);
} else {
$criteria->limit = 1;
$criteria->order = 't.enum DESC, t.value';
$values[$attribute->id]['values'] = EavValue::model()->cache(CACHE_TIME)->findAll($criteria);
}
}
$this->render('attr_list', compact('values', 'max_price', 'min_price'));
}
}
}
Если виджет (фильтр) отключить, ну попросту убрать $this->widget('widget.filters.AFilters');, то скорость загрузки вырастает в разы. Я понимаю, что из-за множества атрибутов товаров, там неимоверное количество записей в базе и он по этим записям делает поиск. Как можно решить проблему скорости, может с кодом виджета косяк и можно сделать гораздо лучше? Может, что-то в mysql можно сделать волшебное? Если здесь есть разработчики на yii и готовы сделать это за какое-то денежное вознаграждение, то пишите предложения тоже! А вопрос в первую очередь задал, чтобы понимать в какую сторону акцентировать свое внимание.