Кактус по имени opencart

Тема в разделе "Мегафлуд", создана пользователем alexsofdev, 24 апр 2013.

  1. alexsofdev

    alexsofdev

    Регистрация:
    13 янв 2013
    Сообщения:
    239
    Симпатии:
    46
    Каждый раз когда я нахожу очередной баг, я снова и снова удивляюсь почему я до сих пор не слез с опенкарта. Причем баги настолько глупые, что я не понимаю почему сам по себе опен приобрел такую безумную популярность. И пока удивляюсь, продолжаю снова и снова жевать этот кактус, как легендарные мыши.

    Сейчас наткнулся на очередную проблему, которая просто взорвала мозг.

    В самом опенкарте нет нормального редактирования заказа ( почему? ) и это кое-как компенсирует модуль beop_create_edit_order, написанный неизвестным, но очень уважаемым мною, автором. Ссылку на него приложить не могу, потому что не могу найти, а пришел ко мне модуль от всеми уважаемого товарища ****.

    Модуль действительно хорош, позволяет не только управлять списком товара, но и добавлять всякие там дисконты, и нормально реагирует на смену типа доставки и т.д. И все работало замечательно, пока я не убрал один лишний товар с витрины, но добавил его в заказ. Цены тут же сошли с ума O_O.

    Моему изумлению не было предела, когда я дотрассировал до строчки-виновника проблемы:

    Код:
      $this->cart->add($order_product['product_id'], $order_product['quantity'], $order_product['option']);
    
    Я пока совершенно не знаю как, но opencart удаляет все ранее добавленные товары, если в корзину был добавлен выключенный товар. Это просто охренеть :Smile: И это официальное API :Smile: Если конечно можно его считать официальным, учитывая полное отсутствие документации.

    А теперь, как любит говорить Задорнов, наберите в грудь воздуха. Набрали? Так вот, если после этой строчки добавить следующую, то корзина снова пашет:

    Код:
       $test = count($this->cart->getProducts());
    
    Казалось бы, какая тут может быть связь? Понятия не имею! Впрочем, пашет корзина не идеально - невидимый на витрине товар все равно там не появится, но по крайней мере будут все остальные.

    Прямо интересно что такого можно было курить при создании...
     
    MaXdi нравится это.
  2. cobalt

    cobalt Команда форума

    Регистрация:
    18 окт 2012
    Сообщения:
    278
    Симпатии:
    127
    Разработчик опенкарта не любит прислушиваться к чужим советам. Ему неоднократно предлагали внести различные полезности, которые есть в сборке ocStore. Причём, уже готовые. Просто возьми и внеси. Он что-то там мычал, типа, "большое спасибо, подумаю" и на этом всё заканчивалось. Предполагаю, что он цены себе не сложит и все замечания и предложения считает чуть ли не личным оскорблением. Ну и ещё могу с уверенностью сказать, что он бесконечно далёк от торговли. Поэтому столько глупостей в функционале. Если бы хоть слушал умных людей - давно бы сделал шикарнейший продукт. А так, имеем то, что имеем.
     
  3. alexsofdev

    alexsofdev

    Регистрация:
    13 янв 2013
    Сообщения:
    239
    Симпатии:
    46
    Ну, почему есть так как есть - это даже не вопрос. Понятно что реакция нулевая на фидбэк. Непонятно почему опенкарт при всех своих проблемах является топ-1 движком. Возможно потому что, как говорит женя петросян "вы еще остальных не видели" :Smile: Я пытался резко перескочить на престу. В чем-то она лучше, но пока не будет редактора тем - это лишь отполированный опен. А под симплу только энтузиасты кодят. Других движков и вообще не нашлось
     
  4. cobalt

    cobalt Команда форума

    Регистрация:
    18 окт 2012
    Сообщения:
    278
    Симпатии:
    127
    Видимо потому, что он считается самым быстрым из бесплатных.
     
  5. alex_storm

    alex_storm дизайн, CSS Команда форума

    Регистрация:
    11 дек 2012
    Сообщения:
    1.120
    Симпатии:
    560
    На счет его быстродействия легенды ходят.. Говорят, что тот же Prestoshop или тот же Magento опережает OC, когда пользователь находится в каталоге продукции и залито около 50000 товаров.. Опенкарт начинает прикалываться.. Но везде по разному говорят.. Лично еще не тестировал.
     
  6. nix

    nix php, MySQL, UNIX, MikroTik ROSAPI

    Регистрация:
    16 янв 2013
    Сообщения:
    1.000
    Симпатии:
    889
    опенкарт не самый быстрый. Быстро он будет работать с огромным к-вом товаров и категорий только тогда, когда категории будут максимум второго уровня вложенности родителя
     
  7. cobalt

    cobalt Команда форума

    Регистрация:
    18 окт 2012
    Сообщения:
    278
    Симпатии:
    127
    Ну, для больших количеств товаров он не предназначен, конечно. Хотя, Юра настраивает свой сервак, что и при больших кол-вах отлично работает. Обычно, большие магазины заказывают самописы под такие количества товаров.
    А Prestoshop и Magento не юзал, поэтому основываюсь только на том, что читал об этом.
     
  8. Baco

    Baco Антихронофаг Команда форума

    Регистрация:
    9 окт 2012
    Сообщения:
    648
    Симпатии:
    327
    Ха, внесу свои 5 карбованцев... опен, если не смотреть на внешнюю обёртку красивости, внутренне довольно неграмотен, конкретно не буду описывать моменты, но такое впечатление, что классы корзины, писал один кулибин, а классы подключения - другой, а рендёринг - вообще 3-й... недавно, как ставил валидатор, перед выпуском своей сборки, охренел, сколько переменных дрейфуют по движку незадефайненых, и лишь предположить могу, сколько может быть ненужных редиректов, запросов, и лишней нагрузки... в общем, стремление сделать "правильный" двиг для торговли не иссякло, думаю общими усилиями, сможем довести до ума сей сыроватый продукт.
     
  9. nix

    nix php, MySQL, UNIX, MikroTik ROSAPI

    Регистрация:
    16 янв 2013
    Сообщения:
    1.000
    Симпатии:
    889
    А че тут описывать, на все можно закрить спокойно глаза а вот на модель продукта catalog/model/catalog/product.php НЕТ!
    функция getProduct
    запрос
    PHP:
    $query $this->db->query("SELECT DISTINCT *, pd.name AS name, p.image, m.name AS manufacturer, (SELECT price FROM " DB_PREFIX "product_discount pd2 WHERE pd2.product_id = p.product_id AND pd2.customer_group_id = '" . (int)$customer_group_id "' AND pd2.quantity = '1' AND ((pd2.date_start = '0000-00-00' OR pd2.date_start < NOW()) AND (pd2.date_end = '0000-00-00' OR pd2.date_end > NOW())) ORDER BY pd2.priority ASC, pd2.price ASC LIMIT 1) AS discount, (SELECT price FROM " DB_PREFIX "product_special ps WHERE ps.product_id = p.product_id AND ps.customer_group_id = '" . (int)$customer_group_id "' AND ((ps.date_start = '0000-00-00' OR ps.date_start < NOW()) AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW())) ORDER BY ps.priority ASC, ps.price ASC LIMIT 1) AS special, (SELECT points FROM " DB_PREFIX "product_reward pr WHERE pr.product_id = p.product_id AND customer_group_id = '" . (int)$customer_group_id "') AS reward, (SELECT ss.name FROM " DB_PREFIX "stock_status ss WHERE ss.stock_status_id = p.stock_status_id AND ss.language_id = '" . (int)$this->config->get('config_language_id') . "') AS stock_status, (SELECT wcd.unit FROM " DB_PREFIX "weight_class_description wcd WHERE p.weight_class_id = wcd.weight_class_id AND wcd.language_id = '" . (int)$this->config->get('config_language_id') . "') AS weight_class, (SELECT lcd.unit FROM " DB_PREFIX "length_class_description lcd WHERE p.length_class_id = lcd.length_class_id AND lcd.language_id = '" . (int)$this->config->get('config_language_id') . "') AS length_class, (SELECT AVG(rating) AS total FROM " DB_PREFIX "review r1 WHERE r1.product_id = p.product_id AND r1.status = '1' GROUP BY r1.product_id) AS rating, (SELECT COUNT(*) AS total FROM " DB_PREFIX "review r2 WHERE r2.product_id = p.product_id AND r2.status = '1' GROUP BY r2.product_id) AS reviews, p.sort_order FROM " DB_PREFIX "product p LEFT JOIN " DB_PREFIX "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN " DB_PREFIX "product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN " DB_PREFIX "manufacturer m ON (p.manufacturer_id = m.manufacturer_id) WHERE p.product_id = '" . (int)$product_id "' AND pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'");
    А до конца там еще много запросов которые делаются даже на главной страннице или по несколько раз
     
    alexsofdev нравится это.
  10. alexsofdev

    alexsofdev

    Регистрация:
    13 янв 2013
    Сообщения:
    239
    Симпатии:
    46
    Я смотрю конкретно задел больной мозоль. Васо, +1 про разных людей.

    Возвращаемся к началу топика, getProducts() отдавал только часть товаров. Почему так? Берем модуль карты, и смотрим код:

    Код:
    	  public function getProducts() {
    		if (!$this->data) {
    			foreach ($this->session->data['cart'] as $key => $quantity) {
    				$product = explode(':', $key);
    				$product_id = $product[0];
    				$stock = true;
    
    ...
    
    				$product_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id) WHERE p.product_id = '" . (int)$product_id . "' AND pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p.date_available <= NOW() AND p.status = '1'");
    
    				if ($product_query->num_rows) {
    ...
    				} else {
    					$this->remove($key);
    				}
    			}
    		}
    
    		return $this->data;
    	  }
    
    	  public function add($product_id, $qty = 1, $option = array()) {
    		if (!$option) {
    			  $key = (int)$product_id;
    		} else {
    			  $key = (int)$product_id . ':' . base64_encode(serialize($option));
    		}
    
    		if ((int)$qty && ((int)$qty > 0)) {
    			if (!isset($this->session->data['cart'][$key])) {
    				  $this->session->data['cart'][$key] = (int)$qty;
    			} else {
    				  $this->session->data['cart'][$key] += (int)$qty;
    			}
    		}
    
    		$this->data = array();
    	  }
    
    	  public function remove($key) {
    		if (isset($this->session->data['cart'][$key])) {
    			 unset($this->session->data['cart'][$key]);
    		  }
    
    		$this->data = array();
    	}
    
    Я умышленно троеточием заменил бессмысленный спам. Что мы тут видим. Мы видим что
    а) $this->cart->add() добавляет товары не в массив, а в сессию;
    б) $this->cart->getProducts() формирует $this->data из сессии, который и возвращает как результат.

    Ну вроде все логично, складно... Только совершенно непонятно куда и почему пропадают все товары ДО отсутствующего на витрине сабжа. Затем видим что для товара со статусом 0 вызывается $this->cart->remove() а там - ранний пикассо :smile:

    Из сессии удаляется только тот товар, что нужен ( ну или не нужен, как глянуть ). Но при этом $this->data почему-то очищается полностью. В итоге все что было нажито непосильным трудом в процессе работы getProducts() удаляется при первом же вызове $this->remove(). Было 10 товаров, 8-й в списке оказался левым, на выдачу ушли 9-й и 10-й.

    Аналогичным образом организована функция $this->update().

    Фиксится весь этот бедлам относительно просто - достаточно убрать AND status = '1' в выборке продукта, который хз почему там стоит :smile: Но это "просто" из серии 1 бакс за удар кувалдой, а 4,999 баксов за то что знал куда ударить :smile:
    --- добавлено: Apr 24, 2013 12:02 AM ---
    P.S. Я тут подумал и нашел ответ на свой вопрос о том, почему я на опенкарте. Мне проще потратить день на адаптацию модуля, чем несколько недель на его написание с нуля. А у опена все же достаточно много готовых, пусть и кривеньких, модулей.