Вход Регистрация
Файл: mg-core/models/catalog.php
Строк: 377
<?php

/**
 * Модель: Catalog
 *
 * Класс Models_Catalog реализует логику работы с каталогом.
 * - Проверяет данные из формы авторизации;
 * - Получает параметры пользователя по его логину.
 *
 * @author Авдеев Марк <mark-avdeev@mail.ru>
 * @package moguta.cms
 * @subpackage Model
 */
class Models_Catalog {

  
/**
   * @var type @var mixed Массив с категориями продуктов.
   */
  
public $categoryId = array();

  
/**
   * @var type @var mixed Массив текущей категории.
   */
  
public $currentCategory = array();

  
/**
   * @var type @var mixed Фильтр пользователя..
   */
  
public $userFilter = array();

  
/**
   * Получает ссылку и название текущей категории.
   * @return bool
   */
  
protected function getCurrentCategory() {
    
$result false;

    
$sql '
      SELECT *
      FROM `'
.PREFIX.'category`
      WHERE id = %d
    '
;

    if (
end($this->categoryId)) {
      
$result DB::query($sqlend($this->categoryId));
      if (
$this->currentCategory DB::fetchAssoc($result)) {
        
$result true;
      }
    } else {
      
$this->currentCategory['url'] = 'catalog';
      
$this->currentCategory['title'] = 'Каталог';
      
$result true;
    }

    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }

  
/**
   * Возвращает список товаров и пейджер для постраничной навигации.
   * @param int $countRows - количество возвращаемых записей для одной страницы.
   * @param boolean $mgadmin - откуда вызван метод, из публичной части или панели управления.
   * @param boolean $onlyActive - учитывать только активные продукты.
   * @return type
   */
  
public function getList($countRows 20$mgadmin false$onlyActive false) {
    
// Если не удалось получить текущую категорию.    
    
if (!$this->getCurrentCategory()) {
      echo 
'Ошибка получения данных!';
      exit;
    }
    
    
// Если используется плагин фильтров, то сразу передаем управление ему.
    
if(MG::get('pluginFilter') && !URL::isSection('catalog') && !$mgadmin){
      
      
// если не переданы параметры для фильтрации, и страница открывается без фильтрации
      
MG::get('pluginFilter')->setCategoryId($this->categoryId);
      if(!
$_GET['filter']){      
        
//пытаемся достать объект из кэша        
        
$result Storage::get(md5('getList'.URL::getUrl()));  
        if(
$result == null){           
          
$result MG::get('pluginFilter')->getFilteredItems(null);  
        
          
//сохраняем объект в кэш
          
Storage::save(md5('getList'.URL::getUrl()),$result);
       
        }        
      }else{
        
//  если есть параметры для фильтрации, то не кэшируем результат      
        
$result MG::get('pluginFilter')->getFilteredItems(null);
   
      }      
       
      
$args func_get_args();      
      return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
    }


    
// Страница.
    
$page URL::get("page");
    
    
$sql .= '
        SELECT
          DISTINCT p.id,
          CONCAT(c.parent_url,c.url) as category_url,
          p.url as product_url,
          p.*, pv.product_id as variant_exist, rate,(p.price_course + p.price_course * (IFNULL(rate,0))) as `price_course` 
        FROM `'
.PREFIX.'product` p
        LEFT JOIN `'
.PREFIX.'category` c
          ON c.id = p.cat_id
        LEFT JOIN `'
.PREFIX.'product_variant` pv
          ON p.id = pv.product_id
        LEFT JOIN (
          SELECT pv.product_id, SUM( pv.count ) AS varcount
          FROM  `'
.PREFIX.'product_variant` AS pv
          GROUP BY pv.product_id
        ) AS temp ON p.id = temp.product_id'
;   
    

    
// Формируем фильтр для продуктов, по имеющимся категориям, внутри выбранной.
    
if ('catalog' == $this->currentCategory['url']) {
      
// Запрос вернет все товары внутри выбраной категории, а также внутри вложеных в нее категорий.    
      
if ($onlyActive) {
        
$sql .= ' WHERE p.activity = 1';
        if (
MG::getSetting('printProdNullRem') == "true") {
          
$sql .=" AND (temp.`varcount` > 0 OR temp.`varcount` < 0 OR p.count>0 OR p.count<0)";
        }
      } else {
        if (
MG::getSetting('printProdNullRem') == "true") {
          
$sql .= ' WHERE (temp.`varcount` > 0 OR temp.`varcount` < 0 OR p.count>0 OR p.count<0)';
        }
      }      
      
    } else {
   
      
// FIND_IN_SET - учитывает товары, в настройках которых, указано в каких категориях следует их покзывать.
      
$filter '(c.id IN ('.implode(','$this->categoryId).') or FIND_IN_SET('.$this->currentCategory['id'].',p.`inside_cat`))';
     
      
// Запрос вернет общее кол-во продуктов в выбранной категории.
      
$sql .='  WHERE  '.$filter;
      if (
$onlyActive) {
        
$sql .= ' AND p.activity = 1';
      }
      if (
MG::getSetting('printProdNullRem') == "true") {
        
$sql .=" AND (temp.`varcount` > 0 OR temp.`varcount` < 0 OR p.count>0 OR p.count<0)";
      } 
      
    }
    
$sql .= ' ORDER BY sort DESC';
    
    
$result Storage::get(md5($sql.$page));    
 
    if(
$result == null){
   
      
$navigator = new Navigator($sql$page$countRows); //определяем класс
      
$this->products $navigator->getRowsSql();
  
   
      
/**
       * Достаем пользовательские характеристики для каждого товара.
       */
      
$idsProduct = array();
      
$currencyRate MG::getSetting('currencyRate');
      
$currencyShort MG::getSetting('currencyShort');
      
$currencyShopIso MG::getSetting('currencyShopIso');
      foreach (
$this->products as $key => $product) {
        
$idsProduct[$product['id']] = $key;
        
// Назначаем для продукта позьзовательские характеристики по умолчанию, заданные категорией.
        
$this->products[$key]['thisUserFields'] = MG::get('category')->getUserPropertyCategoryById($product['cat_id']);       
        
// Формируем ссылки подробнее и в корзину.
        
$this->products[$key]['actionBuy'] = '<a href="'.SITE.'/catalog?inCartProductId='.$product["id"].'" class="addToCart product-buy" data-item-id="'.$product["id"].'">В корзину</a>';
        
$this->products[$key]['actionCompare'] = '<a href="'.SITE.'/compare?inCompareProductId='.$product["id"].'" class="addToCompare" data-item-id="'.$product["id"].'">Сравнить</a>';
        
$this->products[$key]['actionView'] = '<a href="'.SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"].'" class="product-info">Подробнее</a>';
        
$this->products[$key]['link'] = SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"];      
        if(empty(
$this->products[$key]['currency_iso'])){
          
$this->products[$key]['currency_iso'] = $currencyShopIso;
        }      
        
$this->products[$key]['old_price'] *= $currencyRate[$this->products[$key]['currency_iso']];     
        
$this->products[$key]['price'] = MG::priceCourse($this->products[$key]['price_course']); 
      }

      
// Собираем все ID продуктов в один запрос.
      
if ($prodSet trim(DB::quote(implode(','array_keys($idsProduct))), "'")) {
        
// формируем список id продуктов к которым нужно найти пользовательские характеристики.
        
$where ' IN ('.$prodSet.')';
      } else {
        
$where ' IN (0)';
      }

      
$res DB::query("          
        SELECT pup.property_id, pup.value, pup.product_id, prop.*
        FROM `"
.PREFIX."product_user_property` as pup
        LEFT JOIN `"
.PREFIX."property` as prop
          ON pup.property_id = prop.id
        WHERE pup.`product_id` "
.$where);

      while (
$userFields DB::fetchAssoc($res)) {
        
// Дописываем в массив пользовательских характеристик, все переопределенные для каждого тоавара, оставляя при этом не измененные характеристики по умолчанию.
        
$this->products[$idsProduct[$userFields['product_id']]]['thisUserFields'][$userFields['property_id']] = $userFields;
      }

      if (
$mgadmin) {
        
$this->pager $navigator->getPager('forAjax');
      } else {
        
$this->pager $navigator->getPager();
      }

      
$result = array('catalogItems' => $this->products'pager' => $this->pager);  
      
Storage::save(md5($sql.$page), array('catalogItems' => $this->products'pager' => $this->pager)); 
    }
   
    
    
$args func_get_args();
   
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }

  
/**
   * Получает список продуктов в соответствии с выбранными параметрами фильтра.
   * @param type $countRows - количество записей;
   * @param type $userfilter - пользовательская составляющая для запроса;
   * @param type $mgadmin - админка;
   * @return array
   */
  
public function getListByUserFilter($countRows 20$userfilter$mgadmin false) {

    
// Вычисляет общее количество продуктов.
    
$page URL::get("page");

    
// Запрос вернет общее кол-во продуктов в выбранной категории.
    
$sql '
      SELECT DISTINCT p.id,
        CONCAT(c.parent_url,c.url) as category_url,
        p.url as product_url,
        p.*,pv.product_id as variant_exist, rate,(p.price_course + p.price_course * (IFNULL(rate,0))) as `price_course` 
      FROM `'
.PREFIX.'product` p
      LEFT JOIN `'
.PREFIX.'category` c
        ON c.id = p.cat_id
      LEFT JOIN `'
.PREFIX.'product_variant` pv
        ON p.id = pv.product_id
     WHERE  '
.$userfilter;

    
$navigator = new Navigator($sql$page$countRows); //определяем класс.
    
$this->pages $navigator->getRowsSql();
    
$model = new Models_Product();

    
/**
     * Достаем пользовательские характеристики для каждого товара.
     */
    
$idsProduct = array();

    foreach (
$this->pages as $key => $product) {
      
$idsProduct[$product['id']] = $key;

      
// Назначаем для продукта позьзовательские характеристики по умолчанию, заданные категорией.
      
$this->pages[$key]['thisUserFields'] = MG::get('category')->getUserPropertyCategoryById($product['cat_id']);

      
// Формируем ссылки подробнее и в корзину.
      
$this->pages[$key]['actionBuy'] = '<a href="'.SITE.'/catalog?inCartProductId='.$product["id"].'" class="addToCart product-buy" data-item-id="'.$product["id"].'">В корзину</a>';
      
$this->pages[$key]['actionCompare'] = '<a href="'.SITE.'/compare?inCompareProductId='.$product["id"].'" class="addToCompare" data-item-id="'.$product["id"].'">Сравнить</a>';
      
$this->pages[$key]['actionView'] = '<a href="'.SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"].'" class="product-info">Подробнее</a>';
      
$this->pages[$key]['link'] = SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"];
      
    }

    
$arrayVariants $model->getBlocksVariantsToCatalog(array_keys($idsProduct), true);

    foreach (
array_keys($idsProduct) as $id) {
      
$this->pages[$idsProduct[$id]]['variants'] = $arrayVariants[$id];
    }

    
// Собираем все ID продуктов в один запрос.
    
if ($prodSet trim(DB::quote(implode(','array_keys($idsProduct))), "'")) {
      
// Формируем список id продуктов, к которым нужно найти пользовательские характеристики.
      
$where ' IN ('.$prodSet.')';
    } else {
      
$where ' IN (0)';
    }

    
$res DB::query("          
      SELECT pup.property_id, pup.value, pup.product_id, prop.*, pup.type_view
      FROM `"
.PREFIX."product_user_property` as pup
      LEFT JOIN `"
.PREFIX."property` as prop
        ON pup.property_id = prop.id
      WHERE pup.`product_id` "
.$where);

    while (
$userFields DB::fetchAssoc($res)) {
      
// дописываем в массив пользовательских характеристик, все переопределенные для каждого тоавара, оставляя при этом не измененные характеристики по умолчанию
      
$this->pages[$idsProduct[$userFields['product_id']]]['thisUserFields'][$userFields['property_id']] = $userFields;
    }

    if (
$mgadmin) {
      
$this->pager $navigator->getPager('forAjax');
    } else {

      
$this->pager $navigator->getPager();
    }

    
$result = array('catalogItems' => $this->pages'pager' => $this->pager);
    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }

  
/**
   * Возвращает список найденных продуктов соответствующих поисковой фразе.
   * @param string $keyword - поисковая фраза.
   * @param string $allRows - получить сразу все записи.
   * @param string $onlyActive - учитывать только активные продукты.
   * @param boolean $adminPanel - запрос из публичной части или админки.
   * @return array
   */
  
public function getListProductByKeyWord($keyword$allRows false$onlyActive false$adminPanel false) {
    
$result = array();
    
$keyword trim($keyword);
    if(empty(
$keyword)){
      return 
$result;
    }
    
$currencyRate MG::getSetting('currencyRate');   
    
$currencyShopIso MG::getSetting('currencyShopIso');
    
// Поиск по точному соответствию.
    
$model = new Models_Catalog();

    if (!isset(
$_GET["page"])) {
      
$result $model->getListByUserFilter(1" p.title =".DB::quote(trim($keyword))." OR p.code =".DB::quote(trim($keyword)));
    }

    if (
count($result['catalogItems']) !== 0) {
      foreach (
$result['catalogItems'] as &$item) {
        
$imagesUrl explode("|"$item["image_url"]);
        
$item["image_url"] = "";
        if (!empty(
$imagesUrl[0])) {
          
$item["image_url"] = $imagesUrl[0];
        }
        
$item['currency'] = MG::getSetting('currency');
        
$item['currency_iso'] = $item['currency_iso']?$item['currency_iso']:$currencyShopIso;
        
$item['old_price'] *= $currencyRate[$item['currency_iso']];
        
$item['price'] = MG::priceCourse($item['price_course']);        
     
      }
      
$args func_get_args();
      return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
    };

    
// Пример $keyword = " 'красный',   зеленый "
    // Убираем начальные пробелы и конечные.
    
$keyword trim($keyword); //$keyword = "'красный',   зеленый"    
    // Вырезаем спец символы из поисковой фразы.
    
$keyword preg_replace('/[`~!#$%^&*()=+\\|\/\[\]{};:"',<>?]+/', '', $keyword); //$keyword = "красный   зеленый"
    // Замена повторяющихся пробелов на на один.
    $keyword = preg_replace('
/ +/', ' ', $keyword); //$keyword = "красный зеленый"
    // Обрамляем каждое слово в звездочки, для расширенного поиска.
    $keyword = str_replace(' ', '
* *', $keyword); //$keyword = "красный* *зеленый"
    // Добавляем по краям звездочки.
    $keyword = '
*'.$keyword.'*'; //$keyword = "*красный* *зеленый*"
        
    $sql = "
      SELECT distinct p.code, CONCAT(c.parent_url,c.url) AS category_url, 
        p.url AS product_url, p.*, pv.product_id as variant_exist, pv.id as variant_id, rate,(p.price_course + p.price_course * (IFNULL(rate,0))) as `price_course` 
      FROM  `".PREFIX."product` AS p
      LEFT JOIN  `".PREFIX."category` AS c ON c.id = p.cat_id
      LEFT JOIN  `".PREFIX."product_variant` AS pv ON p.id = pv.product_id";

    if (!$adminPanel) {
      $sql .=" LEFT JOIN (
        SELECT pv.product_id, SUM( pv.count ) AS varcount
        FROM  `".PREFIX."product_variant` AS pv
        GROUP BY pv.product_id
      ) AS temp ON p.id = temp.product_id";
    }

    $prod = new Models_Product();
    $fulltext = "";
    
    // Проверяем наличие записей в вариантах если их нет, то не включаем 
    // в поиск полнотекстовые индесты таблицы вариантов.
/*
    $sql .=
      "WHERE MATCH (
          p.`title`, p.`code`, pv.`code`, pv.`title_variant`
        )
        AGAINST (
        '".
$keyword."'
        IN BOOLEAN
        MODE
        ) ";
    */
   
      DB::query("SELECT id FROM `".PREFIX."product_variant` LIMIT 1");
      //Если есть варианты товаров то будеи искать и в них.
      if(DB::numRows(DB::query("SELECT id FROM `".PREFIX."product_variant` LIMIT 1"))){
        $fulltextInVar = '
pv.`title_variant`, pv.`code';
      }

    
        $sql .=
        " WHERE MATCH (
        p.`title` , p.`code` ".$fulltextInVar." ".$fulltext."
        )
        AGAINST (
        '".
$keyword."'
        IN BOOLEAN
        MODE
        ) ";
    
  
    // Проверяем чтобы в вариантах была хотябы одна единица.
    if (!$adminPanel) {
      $sql .=" AND (temp.`varcount` > 0 OR temp.`varcount` < 0 OR p.count>0 OR p.count<0)";
    }

    if ($onlyActive) {
      $sql .= ' 
AND p.`activity` = 1';
    }

    $page = URL::get("page");

    $settings = MG::get('
settings');
    $navigator = new Navigator($sql, $page, $settings['
countСatalogProduct'], $linkCount = 6, $allRows); // Определяем класс.
    $this->pages = $navigator->getRowsSql();
    $idsProduct = array();
 
    if (!empty($this->pages)) {
      foreach ($this->pages as $key => $product) { 
        if($product['
variant_exist']){
          $variants = $prod->getVariants($product['
id']);
          $variant = $variants[$product['
variant_id']];
          $this->pages[$key]['
title'] = $product['title'].' '.$variant['title_variant'];
          $this->pages[$key]['
price_course'] =  $variant['price_course'];
          $this->pages[$key]['
price'] =  $variant['price'];
        }
        $idsProduct[$product['
id']] = $key;
        // Назначаем для продукта позьзовательские характеристики по умолчанию, заданные категорией.
        $this->pages[$key]['
thisUserFields'] = MG::get('category')->getUserPropertyCategoryById($product['cat_id']);
        $this->pages[$key]['
currency'] = $settings['currency'];

        $this->pages[$key]['
actionBuy'] = '<a href="'.SITE.'/catalog?inCartProductId='.$product["id"].'" class="addToCart product-buy" data-item-id="'.$product["id"].'">В корзину</a>';
        $this->pages[$key]['
actionCompare'] = '<a href="'.SITE.'/compare?inCompareProductId='.$product["id"].'" class="addToCompare" data-item-id="'.$product["id"].'">Сравнить</a>';
        $this->pages[$key]['
actionView'] = '<a href="'.SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"].'" class="product-info">Подробнее</a>';
        $this->pages[$key]['
link'] = SITE.'/'.(isset($product["category_url"]) ? $product["category_url"] : 'catalog').'/'.$product["product_url"];
      
        $imagesUrl = explode("|", $this->pages[$key]['
image_url']);
        $this->pages[$key]["image_url"] = "";
        if (!empty($imagesUrl[0])) {
          $this->pages[$key]["image_url"] = $imagesUrl[0];
        }
        $this->pages[$key]['
currency_iso'] = $this->pages[$key]['currency_iso']?$this->pages[$key]['currency_iso']:$currencyShopIso;
       // $this->pages[$key]['
price'] *= $currencyRate[$this->pages[$key]['currency_iso']];    
        $this->pages[$key]['
price'] = MG::priceCourse($this->pages[$key]['price_course']);
      }
    }

    if ($findPart = trim(DB::quote(implode('
,', array_keys($idsProduct))), "'")) {
      // Формируем список id продуктов к которым нужно найти пользовательские характеристики.
      
$where = ' IN ('.$findPart.')';
    } else {
      
$findPart = ' IN (0)';
    }

    
$res = DB::query("
      
SELECT pup.property_idpup.valuepup.product_idpup.type_viewprop.*, pup.type_view
      FROM 
`".PREFIX."product_user_property` as pup
      LEFT JOIN 
`".PREFIX."property` as prop
        ON pup
.property_id prop.id
      WHERE pup
.`product_id".$where);
    while (
$userFields = DB::fetchAssoc($res)) {
      if (!empty(
$this->pages)) {
        
$this->pages[$idsProduct[$userFields['product_id']]]['thisUserFields'][$userFields['property_id']] = $userFields;
      }
    }

    
$this->pager = $navigator->getPager();

    
$result = array(
      'catalogItems' => 
$this->pages
      'pager' => 
$this->pager
      'numRows' => 
$navigator->getNumRowsSql()
    );

    if (count(
$result['catalogItems']) == 0) {
      //примитивный поиск по названию. 100% соответствие
      
$sql = " 
        
SELECT id
        FROM  
`".PREFIX."product` AS p
        WHERE title 
".DB::quote($keyword)." OR code ".DB::quote($keyword);
      if (
$row = DB::fetchAssoc($sql)) {
        
$product = new Models_Product();      
      }
    }else{    
        // упорядочивание списка найденых  продуктов
        // первыми в списке будут стоять те товары, у которых полностью совпала поисковая фраза
        //
        
$keyword = str_replace('*', '', $keyword);
        
$resultTemp = $result['catalogItems'];
        
$prioritet1 = array();
        
$prioritet2 = array();
        foreach(
$resultTemp as $key => $item){    
          if (preg_match('/'.
$keyword.'/iu', $item['title'])) {
            
$prioritet1[] = $item;        
          }else{
            
$prioritet2[] = $item;
          }
        }        
        
$result['catalogItems'] = $prioritet1;
    }
    
$args = func_get_args();
    return MG::createHook(__CLASS__."
_".__FUNCTION__, $result$args);
  }
  
  /**
   * Выгружает содержание всего каталога в CSV файл.
   * @return array
   */
  public function exportToCsv() {

    header("
Content-Typeapplication/force-download");
    header("
Content-Typeapplication/octet-stream;");
    header("
Content-Typeapplication/download");
    header("
Content-Dispositionattachment;filename=data.csv");
    header("
Content-Transfer-Encodingbinary ");
   
    
$csvText = '';
    
$csvText .= "Категория;Товар;Вариант;Описание;Цена;URL;Изображение;Артикул;Количество;Активность;Заголовок [SEO];Ключевые слова [SEO];Описание [SEO];Старая цена;Рекомендуемый;Новый;Сортировка;Вес;Связанные артикулы;Ссылка на товар;Свойства;n";
    
$import = new Import();
    
$product = new Models_Product();
    
$catalog = new Models_Catalog();
         
    Storage::
$noCache = true;
    
$catalog->getList(9999999, true);
  
   
    
  
    foreach (
$catalog->products as $row) {
     
      
$parent = $row['category_url'];
      
      // Подставляем всесто URL названия разделов.
      
$resultPath = '';

      while (
$parent) {
        
$url = URL::parsePageUrl($parent);
        
$parent = URL::parseParentUrl($parent);
        
$parent = $parent != '/' ? $parent : '';
        
$alreadyParentCat = MG::get('category')->getCategoryByUrl(
          
$url$parent
        );
    
        
$resultPath = $alreadyParentCat['title'].'/'.$resultPath;
      }
         
         
      
$resultPath = trim($resultPath, '/');
      
$variants = $product->getVariants($row['id']);

      if (!empty(
$variants)) {
        foreach (
$variants as $key => $variant) {
          foreach (
$variant as $k => $v) {
            
$row[$k] = $v;
          }
          
$row['category_url'] = $resultPath;
          
$csvText .= $this->addToCsvLine($row, 1);
        }
      } else {
        
$row['category_url'] = $resultPath;
        
$csvText .= $this->addToCsvLine($row);
      }
      
    }

    echo mb_convert_encoding(
$csvText, "WINDOWS-1251", "UTF-8");  
    exit;
  }
  
  /**
   * Добавляет продукт в CSV выгрузку.
   * @param type 
$row - продукт.
   * @param type 
$variant - есть ли варианты этого продукта.
   * @return string
   */  
  public function addToCsvLine(
$row$variant = false) {
    
$row['category_url'] = '"'.str_replace(""", """", $row['category_url']).'"';
    
$row['title'] = '"'.str_replace(""", """", $row['title']).'"';
    
$row['description'] = '"'.str_replace(""", """", $row['description']).'"';
    
$row['price'] = '"'.str_replace(""", """", $row['price']).'"';
    
$row['url'] = '"'.str_replace(""", """", $row['url']).'"';
    
$row['image_url'] = '"'.str_replace(""", """", $row['image_url']).'"';
    
$row['code'] = '"'.str_replace(""", """", $row['code']).'"';
    
$row['count'] = '"'.str_replace(""", """", $row['count']).'"';
    
$row['activity'] = '"'.str_replace(""", """", $row['activity']).'"';
    
$row['meta_title'] = '"'.str_replace(""", """", $row['meta_title']).'"';
    
$row['meta_keywords'] = '"'.str_replace(""", """", $row['meta_keywords']).'"';
    
$row['meta_desc'] = '"'.str_replace(""", """", $row['meta_desc']).'"';
    
$row['old_price'] = '"'.str_replace(""", """", $row['old_price']).'"';
    
$row['recommend'] = '"'.str_replace(""", """", $row['recommend']).'"';
    
$row['new'] = '"'.str_replace(""", """", $row['new']).'"';
    
$row['sort'] = '"'.str_replace(""", """", $row['sort']).'"';
    
$row['description'] = str_replace("r", "", $row['description']);
    
$row['description'] = str_replace("n", "", $row['description']);
    
$row['meta_desc'] = str_replace("r", "", $row['meta_desc']);
    
$row['meta_desc'] = str_replace("n", "", $row['meta_desc']);
    
$row['related'] = '"'.str_replace(""", """", $row['related']).'"';    
    
    //получаем строку со связанными продуктами
   
     
    // формируем строку с характеристиками
    
$property = '';
    if(!empty(
$row['thisUserFields'])){  
      foreach (
$row['thisUserFields'] as $item) {
        if(
$item['type']=='string'){
          
$property .= '&'.$item['name'].'='.$item['value'];
        }
      }    
    }    
    
$property = substr($property, 1);  
    
$row['property'] = $property;
    
$row['property'] = str_replace("r", "", $row['property']);
    
$row['property'] = str_replace("n", "", $row['property']);
        
    
    
$csvText = $row['category_url'].";".
      
$row['title'].";";
    if (
$variant) {
      
$csvText .= $row['title_variant'].";";
    } else {
      
$csvText .= ";";
    }
    
$csvText .= $row['description'].";".
      
$row['price'].";".
      
$row['url'].";".
      
$row['image_url'].";".
      
$row['code'].";".
      
$row['count'].";".
      
$row['activity'].";".
      
$row['meta_title'].";".
      
$row['meta_keywords'].";".
      
$row['meta_desc'].";".
      
$row['old_price'].";".
      
$row['recommend'].";".
      
$row['new'].";".
      
$row['sort'].";".
      
$row['weight'].";".
      
$row['related'].";".
      
$row['link_electro'].";".
      
$row['currency_iso'].";".  
      
$row['property']."n";

    return 
$csvText;
  }

  /**
   * Получает массив категорий.
   * @return mixed - ассоциативный массив id => категория.
   */
  public function getCategoryArray() {
    
$res = DB::query('
      SELECT *
      FROM `'.PREFIX.'category`');
    while (
$row = DB::fetchAssoc($res)) {
      
$result[$row['id']] = $row;
    }
    return 
$result;
  }

  /**
   * Получает минимальную цену из всех сстоимостей продуктов.
   * @return float.
   */
  public function getMinPrice() {
    
$res = DB::query('SELECT MIN(`price_course`) as price FROM `'.PREFIX.'product`');
    if (
$row = DB::fetchObject($res)) {
      
$result = $row->price;
    }
    return 
$result;
  }

  /**
   * Получает максимальную цену из всех стоимостей продуктов.
   * @return float.
   */
  public function getMaxPrice() {
    
$res = DB::query('SELECT MAX(`price_course`) as price FROM `'.PREFIX.'product`');
    if (
$row = DB::fetchObject($res)) {
      
$result = $row->price;
    }
    return 
$result;
  }

  /**
   * Возвращает пример загружаемого каталога.
   * @return array
   */
  public function getExampleCSV() {

    header("
Content-Typeapplication/force-download");
    header("
Content-Typeapplication/octet-stream;");
    header("
Content-Typeapplication/download");
    header("
Content-Dispositionattachment;filename=data.csv");
    header("
Content-Transfer-Encodingbinary ");

    
$csvText .='Категория;Товар;Вариант;Описание;Цена;URL;Изображение;Артикул;Количество;Активность;Заголовок [SEO];Ключевые слова [SEO];Описание [SEO];Старая цена;Рекомендуемый;Новый;Сортировка;Вес;Связанные артикулы;Ссылка на товар;Свойства;
"
Сборный товар";"Пицца";Маленькая;"<p><strong>Собери свою пицу на любой вкус!</strong></p><p>Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.</p>";"200";"pizza";"1302360827_835pizza.jpg";"P_SMAL";"-1";"1";"Пицца";"Пицца";"Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.";"";"0";"1";"1";0.2;"FUBW3,FUBB5,COL3";;RUR;Страна производитель=Китай&Материал=
"
Сборный товар";"Пицца";Средняя;"<p><strong>Собери свою пицу на любой вкус!</strong></p><p>Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.</p>";"300";"pizza";"1302360827_835pizza.jpg";"P_MID";"-1";"1";"Пицца";"Пицца";"Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.";"";"0";"1";"2";0.5;"FUBW3,FUBB5,COL3";;RUR;Страна производитель=Китай&Материал=
"
Сборный товар";"Пицца";Большая;"<p><strong>Собери свою пицу на любой вкус!</strong></p><p>Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.</p>";"500";"pizza";"1302360827_835pizza.jpg";"P_BIG";"-1";"1";"Пицца";"Пицца";"Пицца (италpizza от италpizzicare быть острым— итальянское национальное блюдо в виде круглой открытой лепешкипокрытой в классическом варианте томатами и расплавленным сыром.";"";"0";"1";"3";1;"FUBW3,FUBB5,COL3";;RUR;Страна производитель=Китай&Материал=
"
Ювелирные украшения";"Кольцо для помолвки";;"<p>Помолвка – это событиеЭто маленький праздник любвиВедь получив согласиетеперь вы будете зваться женихом и невестойа все мысли и поступки будет направлены на приятную и суматошную подготовку к свадьбеИменно все эти хлопоты и приготовления приведут к томучто после свадебного обряда вы сможете назвать ее своей женой.</p>";"6000";"kolco-dlya-pomolvki";"1364756189.jpg";"COL3";"-1";"1";"Кольцо для помолвки";"Кольцо для помолвки";"Помолвка – это событиеЭто маленький праздник любвиВедь получив согласиетеперь вы будете зваться женихом и невестойа все мысли и поступки будет направлены на приятную и суматошную по";"";"0";"0";"14";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Китай&Материал=серебро
"
Ювелирные украшения";"Кольцо со вставками";;"<p>Колечкоукрашенное драгоценными камнямипорадует любую девушкуКольцо с бриллиантом является лучшим средством демонстрации серьезности чувств...</p>";"11000";"kol-co-so-vstavkami";"1364756044.jpg";"COL2";"-1";"1";"Обручальные кольца";"Обручальные кольцакольцо";"Колечкоукрашенное драгоценными камнямипорадует любую девушкуКольцо с бриллиантом является лучшим средством демонстрации серьезности чувств...";"";"0";"0";"13";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Китай&Материал=Серебро
"
Ювелирные украшения";"Обручальные кольца";;"<p><strong>Обручальное кольцо</strong— кольцо из драгоценного металлакоторое носят на безымянном пальце левой или правой руки (по-разному в разных странах). Обручальное кольцо символизирует брачные узысупруги носят его как знак верности друг другу.</p>";"3400";"obruchal-nye-kol-ca";"1364756100.jpg";"COL1";"8";"1";"Обручальные кольца";"Обручальные кольцакольцо";"Обручальное кольцо — кольцо из драгоценного металлакоторое носят на безымянном пальце левой или правой руки (по-разному в разных странах). Обручальное кольцо символизирует брачные узысупруги носят его как знак верности друг другу.";"";"0";"1";"12";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Китай&Материал=Золото
"
Женские сумки";"Сумка RT4";;"<p>Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный</p>";"4200";"sumka-rt4";"1364756351.jpg|1364756525.jpg|1364756319.jpg";"RT4";"7";"1";"Сумка RT4";"Сумка RT4";"Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный";"5000";"0";"1";"11";0;"RT1,RT2,RT4,P_SMAL";;RUR;Страна производитель=Китай&Материал=Кожа
"
Женские сумки";"Сумка RT2";Без аксессуара;"<p>Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный</p>";"3990";"sumka-rt2";"1364756319.jpg|1364756525.jpg|1364756351.jpg";"RT2";"7";"1";"Сумка RT2";"Сумка RT2";"Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный";"6000";"1";"0";"1";0;"RT1,RT2,RT4,P_SMAL";;RUR;Страна производитель=Китай&Материал=Кожа
"
Женские сумки";"Сумка RT2";С аксессуаром;"<p>Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный</p>";"4230";"sumka-rt2";"1364756319.jpg|1364756525.jpg|1364756351.jpg";"RTF2";"-1";"1";"Сумка RT2";"Сумка RT2";"Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный";"7000";"1";"0";"2";0;"RT1,RT2,RT4,P_SMAL";;RUR;Страна производитель=Китай&Материал=Кожа
"
Женские сумки";"Сумка RT1";;"<p>Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный</p>";"1100";"sumka-rt1";"1364756525.jpg|1364756319.jpg|1364756351.jpg";"RT1";"7";"1";"Сумка RT1";"Сумка RT1";"Сумка большого размера с одним отделением на молнии.На задней стенке один горизонтальный карман на молнии.Подкладка из качественного синтетического материала.Внутри накладной средник на молнии,два кармана,один из которых на молнии и под мобильный";"5000";"0";"0";"9";0;"RT1,RT2,RT4,P_SMAL";;RUR;Страна производитель=Китай&Материал=Кож. зам.
"
Одежда/Для женщин";"Футболка спорт S2";;"<p>Футболка сочетание комфорта и стиляСочный зеленый цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"2300";"futbolka-sport-s2";"1364756694.jpg|1364754799.jpg|1364754670.jpg|1364754612.jpg|1364754870.jpg";"FUBL22";"-1";"1";"Футболка спорт S2";"Футболка спорт S2";"Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"0";"1";"1";"8";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Индия&Материал=Синтетика
"
Одежда/Для женщин";"Футболка спорт S1";;"<p>Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"200";"futbolka-sport-s1";"1364754670.jpg|1364754799.jpg|1364754612.jpg|1364754870.jpg|1364756694.jpg";"FUBL1";"12";"1";"Футболка спорт S1";"Футболка спорт S1";"Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"";"1";"0";"7";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Китай&Материал=Шелк
"
Одежда/Для женщин";"Футболка спорт S3";;"<p>Футболка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"800";"futbolka-sport-s3";"1364754870.jpg|1364754799.jpg|1364756694.jpg|1364754670.jpg|1364754612.jpg";"FUBL23";"-1";"1";"Футболка спорт S3";"Футболка спорт S3";"Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"1700";"0";"0";"6";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=США&Материал=Шелк
"
Одежда/Для женщин";"Футболка спорт W1";;"<p>Футболка сочетание комфорта и стиляСочный розовый&nbsp;цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"1600";"futbolka-sport-w1";"1364754799.jpg|1364754670.jpg|1364754612.jpg|1364754870.jpg|1364756694.jpg";"FUBW1";"30";"1";"Футболка спорт W1";"Футболка спорт W1";"Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"1700";"0";"0";"5";0;"FUBL22,FUBW3,RT1,P_SMAL";;RUR;Страна производитель=Китай&Материал=Хлопок
"
Одежда/Для мужчин";"Толстовка B2";;"<p>Толстовка сочетание комфорта и стиляСочный розовый&nbsp;цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"1580";"tolstovka-b2";"13647546911379243079.jpg|1364754714.jpg|13647546911379243096.jpg|13647546911379242935.jpg";"FUBW3";"30";"1";"Толстовка B2";"Толстовка B2";"Толстовка сочетание комфорта и стиляСочный розовый цвет притягивает вниманиеПрямой крой не сковывает движений";"";"0";"0";"4";0;"FUBL22,FUBW3,RT1,P_SMAL";;RUR;Страна производитель=Вьетнам&Материал=Мех
"
Одежда/Для мужчин";"Толстовка B3";Без рисунка;"<p>Толстовка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движений.&nbsp;&nbsp;</p><p><strong>Доступно нескололько вариантов толстовок!</strong></p>";"1490";"tolstovka-b3";"13647546911379243096.jpg|1364754714.jpg";"FUBL2";"-1";"1";"Толстовка B3";"Толстовка B3";"Толстовка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движений";"";"1";"0";"1";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Россия&Материал=Хлопок
"
Одежда/Для мужчин";"Толстовка B3";С рисунком;"<p>Толстовка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движений.&nbsp;&nbsp;</p><p><strong>Доступно нескололько вариантов толстовок!</strong></p>";"1390";"tolstovka-b3";"13647546911379243096.jpg|1364754714.jpg";"FUBL4";"-1";"1";"Толстовка B3";"Толстовка B3";"Толстовка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движений";"";"1";"0";"2";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Россия&Материал=Хлопок
"
Одежда/Для мужчин";"Толстовка B4";;"<p>Толстовка сочетание комфорта и стиляСочный синий цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"3120";"tolstovka-b4";"250_hoodie_red.png|13647546911379243096.jpg|1364754714.jpg";"FUBW34";"10";"1";"Толстовка B4";"Толстовка B4";"Футболка сочетание комфорта и стиляСочный красный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"";"0";"0";"2";0;"FUBW3,FUBB5,COL3";;RUR;Страна производитель=Италия&Материал=Синтетика
"
Одежда/Для мужчин";"Толстовка B5";;"<p>Толстовка сочетание комфорта и стиляСочный черный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.</p>";"990";"tolstovka-b5";"1364754714.jpg|13647546911379243096.jpg";"FUBB5";"10";"1";"Толстовка B5";"Толстовка B5";"Толстовка сочетание комфорта и стиляСочный черный цвет притягивает вниманиеПрямой крой не сковывает движенийНатуральный трикотаж позволяет кожу дышатьдаря чувство комфортаПриведенные измерения соответствуют размеру M.";"";"0";"1";"1";0;"FUBL22,FUBW1,COL1,RT1";;RUR;Страна производитель=Турция&Материал=Хлопок';
    echo iconv("
UTF-8", "WINDOWS-1251", $csvText);
    exit;
  }

}
Онлайн: 2
Реклама