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

/**
 * Модель: Product
 *
 * Класс Models_Product реализует логику взаимодействия с товарами магазина.
 * - Добавляет товар в базу данных;
 * - Изменяет данные о товаре;
 * - Удаляет товар из базы данных;
 * - Получает информацию о запрашиваемом товаре;
 * - Получает продукт по его URL;
 * - Получает цену запрашиваемого товара по его id.
 *
 * @author Авдеев Марк <mark-avdeev@mail.ru>
 * @package moguta.cms
 * @subpackage Model
 */
class Models_Product {

  
/**
   * Добавляет товар в базу данных. 
   * @param array $array массив с данными о товаре.
   * @return bool|int в случае успеха возвращает id добавленного товара.
   */
  
public function addProduct($array$clone false) {

    if (empty(
$array['title'])) {
      return 
false;
    }
    


    
$userProperty $array['userProperty'];
    
$variants = !empty($array['variants']) ? $array['variants'] : array(); // варианты товара
    
unset($array['userProperty']);
    unset(
$array['variants']);
    unset(
$array['id']);

    
$result = array();

    
$array['url'] = empty($array['url']) ? MG::translitIt($array['title']) : $array['url'];
    
$array['title'] = htmlspecialchars($array['title']);
    if (!empty(
$array['url'])) {
      
$array['url'] = URL::prepareUrl($array['url']);
    }

    
// Исключает дублирование.
    
$dublicatUrl false;
    
$tempArray $this->getProductByUrl($array['url']);
    if (!empty(
$tempArray)) {
      
$dublicatUrl true;
    }

    if (
DB::buildQuery('INSERT INTO `'.PREFIX.'product` SET '$array)) {
      
$id DB::insertId();

      
// Если url дублируется, то дописываем к нему id продукта.
      
if ($dublicatUrl) {
        
$this->updateProduct(array('id' => $id'url' => $array['url'].'_'.$id));
      } else {
        
$this->updateProduct(array('id' => $id'url' => $array['url'], 'sort' => $id));
      }

      
$array['id'] = $id;
      
$array['userProperty'] = $userProperty;
      
$userProp = array();

      if (
$clone) {
        if (!empty(
$userProperty)) {
          foreach (
$userProperty as $property) {
            
$userProp[$property['property_id']] = $property['value'];
            if (!empty(
$property['product_margin']) && $property['product_margin'] != 'product_margin') {
              
$userProp[("margin_".$property['property_id'])] = $property['product_margin'];
            }
          }
          
$userProperty $userProp;
        }
      }

      if (!empty(
$userProperty)) {
        
$this->saveUserProperty($userProperty$id);
      }

      
// Обновляем и добавляем варианты продукта.      
      
$this->saveVariants($variants$id);
      
$variants $this->getVariants($id);
      foreach (
$variants as $variant) {
        
$array['variants'][] = $variant;
      }

      
$tempProd $this->getProduct($id);
      
$array['category_url'] = $tempProd['category_url'];
      
$array['product_url'] = $tempProd['product_url'];

      
$result $array;
    }
    
    
$this->updatePriceCourse($currencyShopIso, array($result['id']));  

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

  
/**
   * Преобразует  массив характеристик в удобный для работы вид.
   * @param type $array
   * @return array
   */
  
public function preProcessUserProperty($userProperty) {
    
$prefixs = array("margin""type");

    foreach (
$userProperty as $propertyId => $value) {
      foreach (
$prefixs as $prefix) {
        if (
strpos($propertyId$prefix."_") !== false) {
          
$propertyId str_replace($prefix."_"""$propertyId);
          if (
is_array($userProperty[$propertyId])) {
            
$userProperty[$propertyId][$prefix] = $value;
          } else {
            
$userProperty[$propertyId] = array(
              
'value' => $userProperty[$propertyId],
              
$prefix => $value,
            );
          }
        }
      }
    }
    return 
$userProperty;
  }

  
/**
   * Изменяет данные о товаре.
   * @param array $array массив с данными о товаре.
   * @param int $id  id изменяемого товара.
   * @return bool
   */
  
public function updateProduct($array) {

    
$id $array['id'];
    
$userProperty = !empty($array['userProperty']) ? $array['userProperty'] : null//свойства товара
    
$variants = !empty($array['variants']) ? $array['variants'] : array(); // варианты товара
    
$updateFromModal = !empty($array['updateFromModal']) ? true false// варианты товара

    
unset($array['userProperty']);
    unset(
$array['variants']);
    unset(
$array['updateFromModal']);

    if (!empty(
$array['url'])) {
      
$array['url'] = URL::prepareUrl($array['url']);
    }
    
    if (!empty(
$array['title'])) {
      
$array['title'] = htmlspecialchars($array['title']);
    }
    
    
$result false;

    
// Если происходит обновление параметров.
    
if (!empty($id)) {
      unset(
$array['delete_image']);

      
// Обновляем стандартные  свойства продукта.
      
if (DB::query('
          UPDATE `'
.PREFIX.'product`
          SET '
.DB::buildPartQuery($array).'
          WHERE id = '
.DB::quote($id))) {

        
// Обновляем пользовательские свойства продукта.
        
if (!empty($userProperty)) {
          
$this->saveUserProperty($userProperty$id);
        }

        
// Эта проверка нужна только для того, чтобы исключить удаление 
        //вариантов при обновлении продуктов не из карточки товара в админке, 
        //например по нажатию на "лампочку".
        
if (!empty($variants) || $updateFromModal) {

          
// обновляем и добавляем варианты продукта.
          
if ($variants === null) {
            
$variants = array();
          }
          
$this->saveVariants($variants$id);
        }

        
$result true;
      }
    } else {
      
$result $this->addProduct($array);
    }
    
    
$currencyShopIso MG::getSetting('currencyShopIso');  
    
    
$this->updatePriceCourse($currencyShopIso, array($id));   

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

  
/**
   * Обновляет поле в варианте и синхронизирует привязку первого варианта с продуктом.
   * @param type $id - id варианта.
   * @param type $array - ассоциативный массив поле=>значение.
   * @param type $product_id - id продукта.
   * @return boolean
   */
  
public function fastUpdateProductVariant($id$array$product_id) {
    if (!
DB::query('
       UPDATE `'
.PREFIX.'product_variant`
       SET '
.DB::buildPartQuery($array).'
       WHERE id = %d
     '
$id)) {
      return 
false;
    };

    
// Следующие действия выполняются для синхронизации  значений первого 
    // варианта со значениями записи продукта из таблицы product.
    // Перезаписываем в $array новое значение от первого в списке варианта,
    // и получаем id продукта от этого варианта
    
$variants $this->getVariants($product_id);
    
$field array_keys($array);
    foreach (
$variants as $key => $value) {
      
$array[$field[0]] = $value[$field[0]];
      break;
    }

    
// Обновляем продукт в соответствии с первым вариантом.
    
$this->fastUpdateProduct($product_id$array);
    return 
true;
  }

  
/**
   * Аналогичная fastUpdateProductVariant функция, но с поправками для
   * процесса импорта вариантов.
   * @param type $id - id варианта.
   * @param type $array - массив поле=значение.
   * @param type $product_id - id продукта.
   * @return boolean
   */
  
public function importUpdateProductVariant($id$array$product_id) {

    if (!
$id || !DB::query('
       UPDATE `'
.PREFIX.'product_variant`
       SET '
.DB::buildPartQuery($array).'
       WHERE id = %d
     '
$id)) {

      
DB::query('
       INSERT INTO `'
.PREFIX.'product_variant`
       SET '
.DB::buildPartQuery($array)
      );
    };

    return 
true;
  }

  
/**
   * Обновление заданного поля продукта.
   * @param type $id - id продукта.
   * @param type $array - параметры для обновления.
   * @return boolean
   */
  
public function fastUpdateProduct($id$array) {
    if (!
DB::query('
      UPDATE `'
.PREFIX.'product`
      SET '
.DB::buildPartQuery($array).'
      WHERE id = %d
    '
$id)) {
      return 
false;
    };
    
    
$currencyShopIso MG::getSetting('currencyShopIso');  
    
$this->updatePriceCourse($currencyShopIso, array($id));   
    
    return 
true;
  }

  
/**
   * Сохраняет пользовательские характеристики для товара.
   * @param int $id - id товара.
   * @param array $userProperty набор характеристик.
   * @return boolean
   */
  
public function saveUserProperty($userProperty$id$type 'select') {
    
$userProperty $this->preProcessUserProperty($userProperty);

    foreach (
$userProperty as $propertyId => $value) {

      
// Проверяем существует ли запись в базе о текущем свойстве.
      
$res DB::query("
        SELECT * FROM `"
.PREFIX."product_user_property`
        WHERE property_id = "
.DB::quote($propertyId)."
          AND product_id = "
.DB::quote($id)
      );

      
// Обновляем значение свойства если оно существовало.
      
if (DB::numRows($res)) {
        if (!
is_array($value)) {
          
DB::query("
            UPDATE `"
.PREFIX."product_user_property`
            SET value = "
.DB::quote($value)."
            WHERE property_id = "
.DB::quote($propertyId)."
              AND product_id = "
.DB::quote($id)
          );
        } else {
          
DB::query("
            UPDATE `"
.PREFIX."product_user_property`
            SET value = "
.DB::quote($value['value']).",
              product_margin = "
.DB::quote($value['margin']).",
              type_view = "
.DB::quote($value['type'])."
            WHERE property_id = "
.DB::quote($propertyId)."
              AND product_id = "
.DB::quote($id)
          );
        }
      } else {

        
// Создаем новую запись со значением свойства
        // если его небыло сохранено ранее.
        
if (!is_array($value)) {
          
DB::query("
            INSERT INTO `"
.PREFIX."product_user_property`
            VALUES (
            "
.DB::quote($id).",
            "
.DB::quote($propertyId).",
            "
.DB::quote($value).",'', ".DB::quote($type).")");
        } else {
          
DB::query("
            INSERT INTO `"
.PREFIX."product_user_property`
            VALUES (
            "
.DB::quote($id).",
            "
.DB::quote($propertyId).",
            "
.DB::quote($value['value']).",
            "
.DB::quote($value['margin']).",
            "
.DB::quote($value['type'])."
            )"
);
        }
      }
    }
  }

  
/**
   * Сохраняет варианты товара.
   * @param int $id  id товара
   * @param array $variants набор вариантов
   * @return bool
   */
  
public function saveVariants($variants = array(), $id) {
    
// Удаляем все имеющиеся товары.
    
$res DB::query("
      DELETE FROM `"
.PREFIX."product_variant` WHERE product_id = ".DB::quote($id)
    );

    
// Если вариантов как минимум два.
    
if (count($variants) > 1) {
      
// Сохраняем все отредактированные варианты.
      
$i 1;
      foreach (
$variants as $variant) {
        
$variant['sort'] = $i++;
        
DB::query(
          INSERT  INTO `'
.PREFIX.'product_variant` 
          SET product_id= '
.DB::quote($id).", ".DB::buildPartQuery($variant)
        );
      }
    }
  }

  
/**
   * Клонируем товар.
   * @param int $id  id клонируемого товара.
   * @return bool
   */
  
public function cloneProduct($id) {
    
$result false;

    
$arr $this->getProduct($id);
    
$image_url $arr['image_url'];
    
$arr['image_url'] = implode("|"$arr['images_product']);
    
$userProperty $arr['thisUserFields'];
    unset(
$arr['thisUserFields']);
    unset(
$arr['category_url']);
    unset(
$arr['product_url']);
    unset(
$arr['images_product']);
    unset(
$arr['images_title']);
    unset(
$arr['images_alt']);
    unset(
$arr['rate']);
    
$arr['userProperty'] = $userProperty;
    
$variants $this->getVariants($id);

    foreach (
$variants as &$item) {
      unset(
$item['id']);
      unset(
$item['product_id']);
      unset(
$item['rate']);
    }

    
$arr['variants'] = $variants;
    
$result $this->addProduct($arrtrue);
    
$result['image_url'] = $image_url;
    
$result['currency'] = MG::getSetting('currency');

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

  
/**
   * Удаляет товар из базы данных.
   *
   * @param int $id  id удаляемого товара
   * @return bool
   */
  
public function deleteProduct($id) {
    
$result false;

    
// Удаляем продукт из базы.
    
DB::query('
      DELETE
      FROM `'
.PREFIX.'product`
      WHERE id = %d
    '
$id);

    
// Удаляем все значения пользовательских характеристик даного продукта.
    
DB::query('
      DELETE
      FROM `'
.PREFIX.'product_user_property`
      WHERE product_id = %d
    '
$id);

    
// Удаляем все варианты данного продукта.
    
DB::query('
      DELETE
      FROM `'
.PREFIX.'product_variant`
      WHERE product_id = %d
    '
$id);

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

  
/**
   * Получает информацию о запрашиваемом товаре.
   * @patam string $where необезательный пераметр, формирующий условия поиска, например: id = 1
   * @return array массив заказов
   */
  
public function getProductByUserFilter($where '') {
    
$result = array();
    if (
$where) {
      
$where ' WHERE '.$where;
    }
    
    
$res DB::query('
     SELECT  CONCAT(c.parent_url,c.url) as category_url,
       p.url as product_url, p.*, 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
     '
.$where);
    
    while (
$order DB::fetchAssoc($res)) {
      
$result[$order['id']] = $order;
    }
    return 
$result;
  }

  
/**
   * Получает информацию о запрашиваемом товаре по его ID.
   * @param int $id id запрашиваемого товара.
   * @return array массив с данными о товаре.
   */
  
public function getProduct($id) {
    
$result = array();
    
$res DB::query('
      SELECT  CONCAT(c.parent_url,c.url) as category_url,
        p.url as product_url, p.*, 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
      WHERE p.id = %d
    '
$id);

    if (!empty(
$res)) {
      if (
$product DB::fetchAssoc($res)) {
        
$result $product;

        
// Запрос делает следующее 
        // 1. Вычисляет список пользовательских характеристик для категории товара, 
        // 2. Присваивает всем параметрам значания по умолчанию, 
        // 3. Находит заполненные характеристики товара, заменяет ими значения по умолчанию.
        // В результате получаем набор всех пользовательских характеристик включая те, что небыли определены явно.

        
$res DB::query("
          SELECT p.id AS  `property_id` , p.`default` AS  `value` , 'product_margin', 'type_view', p.* 
          FROM  `"
.PREFIX."property` AS p    
          WHERE p.id IN (
            SELECT p.id AS `property_id` 
            FROM `"
.PREFIX."category_user_property` AS c, `".PREFIX."property` AS p
            WHERE c.category_id = "
.DB::quote($result['cat_id'])."
            AND p.id = c.property_id )          
          
          UNION 
          
          SELECT pup.property_id, pup.value, pup.product_margin, pup.type_view, prop.*
          FROM `"
.PREFIX."product_user_property` as pup
          LEFT JOIN `"
.PREFIX."property` as prop
            ON pup.property_id = prop.id
          WHERE pup.`product_id` = "
.DB::quote($id)."
            
          UNION 
          
          SELECT prop.id, prop.default, 'product_margin', 'type_view', prop.*         
          FROM `"
.PREFIX."property` as prop 
          WHERE prop.`all_category` = 1
            
          ORDER BY `sort` DESC;
        "
);

        while (
$userFields DB::fetchAssoc($res)) {
          
// Заполняет каждый товар его характеристиками.
          
if (isset($result['thisUserFields'][$userFields['property_id']])) {
            
// если товар существует и у него type_view == 'type_view', то он будет перезаписан.
            
if ($result['thisUserFields'][$userFields['property_id']]['type_view'] == 'type_view') {
              
$result['thisUserFields'][$userFields['property_id']] = $userFields;
            }
          } else {
            
$result['thisUserFields'][$userFields['property_id']] = $userFields;
          }
        }

        
$imagesConctructions $this->imagesConctruction($result['image_url'],$result['image_title'],$result['image_alt']);
        
$result['images_product'] = $imagesConctructions['images_product']; 
        
$result['images_title'] = $imagesConctructions['images_title']; 
        
$result['images_alt'] = $imagesConctructions['images_alt']; 
        
$result['image_url'] = $imagesConctructions['image_url']; 
        
$result['image_title'] = $imagesConctructions['image_title']; 
        
$result['image_alt'] = $imagesConctructions['image_alt']; 
     
      }
    }
   
    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }
  
  
/**
   * Создает массивы данных для картинок товара, возвращает три массива со ссылками, заголовками и альт, текстами.
   * @param string $imageUrl строка с разделителями | мезжду ссылок 
   * @param string $imageTitle строка с разделителями | мезжду заголовков 
   * @param string $imageAlt строка с разделителями | мезжду тестов 
   */
  
public function imagesConctruction($imageUrl$imageTitle$imageAlt) {
    
$result = array(
      
'images_product'=>array(),
      
'images_title'=>array(),
      
'images_alt'=>array()
    );
    
    
// Получаем массив картинок для продукта, при этом первую в наборе делаем основной.
    
$arrayImages explode("|"$imageUrl);
    if (!empty(
$arrayImages)) {
      
$result['image_url'] = $arrayImages[0];
    }

    
$result['images_product'] = $arrayImages;  
    
// Получаем массив title для картинок продукта, при этом первый в наборе делаем основной.
    
$arrayTitles explode("|"$imageTitle);
    if (!empty(
$arrayTitles)) {
      
$result['image_title'] = $arrayTitles[0];
    }

    
$result['images_title'] = $arrayTitles;  

    
// Получаем массив alt для картинок продукта, при этом первый в наборе делаем основной.
    
$arrayAlt explode("|"$imageAlt);
    if (!empty(
$arrayAlt)) {
      
$result['image_alt'] = $arrayAlt[0];
    }

    
$result['images_alt'] = $arrayAlt;  
    
    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }
  
  
  
/**
   * Обновляет остатки продукта, увеличивая их на заданное количество
   * @param type $id - номер продукта.
   * @param type $count - прибавляемое значение к остатку.
   * @param type $code - артикул.
   */
  
public function increaseCountProduct($id$code$count) {

    
$sql "
      UPDATE `"
.PREFIX."product_variant` as pv 
      SET pv.`count`= pv.`count`+"
.DB::quote($count).
      WHERE pv.`product_id`="
.DB::quote($id).
        AND pv.`code`="
.DB::quote($code).
        AND pv.`count`>=0
    "
;

    
DB::query($sql);

    
$sql "
      UPDATE `"
.PREFIX."product` as p 
      SET p.`count`= p.`count`+"
.DB::quote($count).
      WHERE p.`id`="
.DB::quote($id).
        AND p.`code`="
.DB::quote($code).
        AND  p.`count`>=0
    "
;

    
DB::query($sql);
  }

  
/**
   * Обновляет остатки продукта, уменьшая их количество,
   * при смене статуса заказа с "отменент" на любой другой.
   * 
   * @param type $id - Номер продукта.
   * @param type $count - Прибавляемое значение к остатку.
   * @param type $code - Артикул.
   */
  
public function decreaseCountProduct($id$code$count) {

    
$product $this->getProduct($id);
    
$variants $this->getVariants($product['id']);
    foreach (
$variants as $idVar => $variant) {
      if (
$variant['code'] == $code) {
        
$variantCount = ($variant['count'] * $count 1) >= $variant['count'] - $count 0;
        
$sql "
          UPDATE `"
.PREFIX."product_variant` as pv 
          SET pv.`count`= "
.DB::quote($variantCounttrue).
          WHERE pv.`id`="
.DB::quote($idVar).
            AND pv.`code`="
.DB::quote($code).
            AND  pv.`count`>0"
;
        
DB::query($sql);
      }
    }

    
$product['count'] = ($product['count'] * $count 1) >= $product['count'] - $count 0;
    
$sql "
      UPDATE `"
.PREFIX."product` as p 
      SET p.`count`= "
.DB::quote($product['count'], true).
      WHERE p.`id`="
.DB::quote($id).
        AND p.`code`="
.DB::quote($code)."
        AND  p.`count`>0"
;
    
DB::query($sql);
  }

  
/**
   * Удаляет все миниатюры и оригинал изображения товара из папки upload.
   * @return bool
   */
  
public function deleteImageProduct($arrayDelImages) {
    if (!empty(
$arrayDelImages)) {
      foreach (
$arrayDelImages as $value) {
        if (!empty(
$value)) {

          
// Удаление картинки с сервера.
          
$documentroot str_replace('mg-core'.DIRECTORY_SEPARATOR.'models'''__DIR__);
          if (
is_file($documentroot."uploads/".basename($value))) {
            
unlink($documentroot."uploads/".basename($value));

            if (
is_file($documentroot."uploads/thumbs/30_".basename($value))) {
              
unlink($documentroot."uploads/thumbs/30_".basename($value));
            }
            if (
is_file($documentroot."uploads/thumbs/70_".basename($value))) {
              
unlink($documentroot."uploads/thumbs/70_".basename($value));
            }
          }
        }
      }
    }

    return 
true;
  }

  
/**
   * Возвращает общее количество продуктов каталога.
   * @param int $id id запрашиваемого товара.
   * @return array массив с данными о товаре.
   */
  
public function getProductsCount() {
    
$result 0;
    
$res DB::query('
      SELECT count(id) as count
      FROM `'
.PREFIX.'product`
    '
);

    if (
$product DB::fetchAssoc($res)) {
      
$result $product['count'];
    }

    return 
$result;
  }

  
/**
   * Получает продукт по его URL.
   * @param string $url запрашиваемого товара.
   * @param int $catId id-категории, т.к. в разных категориях могут быть одинаковые url.
   * @return array массив с данными о товаре.
   *
   */
  
public function getProductByUrl($url$catId false) {
    
$result = array();
    if (
$catId !== false) {
      
$where ' and cat_id='.DB::quote($catId);
    }

    
$res DB::query('
      SELECT *
      FROM `'
.PREFIX.'product`
      WHERE url = "%s" 
    '
.$where$url);

    if (!empty(
$res)) {
      if (
$product DB::fetchArray($res)) {
        
$result $product;
      }
    }

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

  
/**
   * Получает цену запрашиваемого товара по его id.
   * @param int $id id изменяемого товара.
   * @return bool|float $error в случаи ошибочного запроса.
   */
  
public function getProductPrice($id) {
    
$result false;
    
$res DB::query('
      SELECT price
      FROM `'
.PREFIX.'product`
      WHERE id = %d
    '
$id);

    if (
$row DB::fetchObject($res)) {
      
$result $row->price;
    }

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

  
/**
   * Создает форму пользовательских характеристик для товара.
   * В качестве входящего параметра получает массив:
   * <code>
   * $param = array(
   * 'id' => null, // id товара.
   * 'maxCount' => null, // максимальное количество товара на складе.
   * 'productUserFields' => null, // массив пользовательских полей для данного продукта.
   * 'action' => "/catalog", // ссылка для метода формы.
   * 'method' => "POST", // тип отправки данных на сервер.
   * 'ajax' => true, // использовать ajax для пересчета стоимости товаров.
   * 'blockedProp' => array(), // массив из ID свойств, которые ненужно выводить в форме.
   * 'noneAmount' => false, // не выводить  input для количества.
   * 'titleBtn' => "В корзину", // название кнопки.
   * 'blockVariants' => '', // блок вариантов.
   * 'classForButton' => 'addToCart buy-product buy', // классы для кнопки.
   * 'noneButton' => false, // не выводить кнопку отправки.
   * 'addHtml' => '' // добавить HTML в содержимое формы.
   * )
   * </code>
   * @param int $param - массив параметров.
   * @return string html форма.
   */
  
public function createPropertyForm(
  
$param = array(
    
'id' => null,
    
'maxCount' => null,
    
'productUserFields' => null,
    
'action' => "/catalog",
    
'method' => "POST",
    
'ajax' => true,
    
'blockedProp' => array(),
    
'noneAmount' => false,
    
'titleBtn' => "В корзину",
    
'blockVariants' => '',
    
'classForButton' => 'addToCart buy-product buy',
    
'noneButton' => false,
    
'addHtml' => '',
    
'printStrProp' => null,
    
'printCompareButton' => null,
    
'buyButton' => '',
  )
  ) {
    
extract($param);
    if (empty(
$classForButton)) {
      
$classForButton 'addToCart buy-product buy';
    }
    if (
$id === null || $maxCount === null) {
      return 
"error param!";
    }
    if (empty(
$printStrProp)) {
      
$printStrProp MG::getSetting('printStrProp');    
    }
   
    
// если используется аяксовый метод выбора, то подключаем доп класс для работы с формой. 
    
$marginPrice 0// добавочная цена, в зависимости от выбраных автоматом характеристик
    
$secctionCartNoDummy = array(); //Не подставной массив характеристик, все характеристики с настоящими #ценами#
    //в сессию записать реальные значения, в паблик подмену, с привязкой в конце #№
    
$html '<form action="'.SITE.$action.'" method="'.$method.'" class="property-form" data-product-id='.$id.'>';
    
//if ($ajax) {
    //  mgAddMeta("<script type="text/javascript" src="".SITE."/mg-core/script/jquery.form.js"></script>");
    //}

    
if (!empty($productUserFields)) {
      
// массив со строковыми характеристиками
      
$stringsProperties = array();
   
      foreach (
$productUserFields as $property) {
        if (
in_array($property['id'], $blockedProp)) {
          continue;
        }

        
/*
          'select' - набор значений, можно интерпретировать как  выпадающий список либо набор радиокнопок
          'assortment' - мультиселект
          'string' - пара ключь значение
          'assortmentCheckBox' - набор чекбоксов
         */
        
switch ($property['type']) {

          case 
'string': {
              
$marginStoper $marginPrice;
              if (!empty(
$property['value'])) {
                
$value = !empty($property['value']) ? $property['value'] : $property['data'];
                
$stringsProperties[$property['name']] = $value;
                if(
$printStrProp=='true'){
                  
$html .= '<p><span class="property-title">'.$property['name'].'</span>: <span class="label-black">'.
                    
htmlspecialchars_decode($value).
                  
'</span></p>';                
                }
              }
              break;
            }

          default:
            if (!empty(
$property['data'])) {
            
             
$str $property['data'];
             
$parts explode('|'$str);             
             if(!empty(
$parts)){    
             
$str '';             
             foreach(
$parts as $item){
               
$str .= ', '.preg_replace('/#.*#/'""$item);
             }
             
$str =  preg_replace('~,s$~'""$str);
             
$str =  preg_replace('~^,s~'""$str);
             } 
             
$property['data'] = $str;
 
              
$html .= '<p><span class="property-title">'.$property['name'].'</span>: <span class="label-black">'
             
.$property['data'].
               
'</span></span></p>';
            }
            break;
        }
      }

     
// $_SESSION['propertyNodummy'] = $secctionCartNoDummy;
    
}
   
    
$data = array(
     
'maxCount' => $maxCount,
     
'noneAmount' => $noneAmount,
     
'noneButton' => $noneButton,
     
'printCompareButton' => $printCompareButton,
     
'ajax' => $ajax,
     
'buyButton' => $buyButton,
     
'classForButton' => $classForButton,
     
'titleBtn' => $titleBtn,
     
'id' => $id,
     
'blockVariants' => $blockVariants,
     
'addHtml' => $addHtml
    
);
    
    
$html .= MG::layoutManager('layout_property'$data);
    
$html .= '</form>';

    
$result = array('html' => $html'marginPrice' => $marginPrice'propertyNodummy' => $secctionCartNoDummy'stringsProperties' => $stringsProperties);
    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }

  
/**
   * Формирует блок варинтов товара.
   * 
   * @param $id - id товара
   * @return  string
   */
  
public function getBlockVariants($id) {
     return 
"";
  }

  
/**
   * Формирует массив блоков варинтов товаров на странице каталога.
   * Метод создан для сокращения количества запросов к БД.
   * @param $array  - массив id товаров
   * @param $returnArray  - если true то вернет просто массив без html блоков
   * @return  string
   */
  
public function getBlocksVariantsToCatalog($array$returnArray false) {
    if (!empty(
$array)) {
      
$in implode(','$array);
    }
    
    
// Получаем все варианты для переданого массива продуктов.
    
if ($in) {
      
$res DB::query('
       SELECT  pv.*, c.rate,(pv.price_course + pv.price_course * (IFNULL(c.rate,0))) as `price_course` 
       FROM `'
.PREFIX.'product_variant` pv    
         LEFT JOIN `'
.PREFIX.'product` as p ON 
           p.id = pv.product_id
         LEFT JOIN `'
.PREFIX.'category` as c ON 
           c.id = p.cat_id  
       WHERE pv.product_id  in ('
.$in.')
       ORDER BY sort
     '
$id);

      if (!empty(
$res)) {
        while (
$variant DB::fetchAssoc($res)) {      
          if (!
$returnArray) {
            
$variant['price'] = MG::priceCourse($variant['price_course']);
          }
          
$results[$variant['product_id']][] = $variant;
        }
      }
    }

    if (
$returnArray) {
      return 
$results;
    }

    if (!empty(
$results)) {
      
// Для каждого продукта создаем HTML верстку вариантов.
      
foreach ($results as &$blockVariants) {       
        
$html '';
        
$blockVariants $html;
      }
    }
    
    return 
$results;
  }

  
/**
   * Формирует добавочную строку к названию характеристики,
   * в зависимости от наличия наценки и стоимости.   * 
   * @param $valueArr - массив с наценкой
   * @return  $array - массив с разделенными данными, название пункта и стоимость.
   */
  
public function addMarginToProp($margin) {
    
$symbol '+';
    if (!empty(
$margin)) {
      if (
$margin 0) {
        
$symbol '-';
        
$margin $margin * -1;
      }
    }
    return (!empty(
$margin)) ? ' '.$symbol.' '.$margin.' '.MG::getSetting('currency') : '';
  }

  
/**
   * Отделяет название характеристики от цены название_пункта#стоимость#.
   * Пример входящей строки:
   *  Красный#300#
   * @param $value - строка которую надо распарсить
   * @return  $array - массив с разделенными данными, название пункта и стоимость.
   */
  
public function parseMarginToProp($value) {
    
$array = array();
    
$pattern "/^(.*)#([d.,-]*)#$/";
    
preg_match($pattern$value$matches);
    if (isset(
$matches[1]) && isset($matches[2])) {
      
$array = array('name' => $matches[1], 'margin' => $matches[2]);
    }
    return 
$array;
  }

  
/**
   * Обновление состояния корзины.
   */
  
public function calcPrice() {
    
$product $this->getProduct($_POST['inCartProductId']);
    
    
$currencyRate MG::getSetting('currencyRate');      
    
$currencyShopIso MG::getSetting('currencyShopIso');     
    if (isset(
$_POST['variant'])) {
      
$variants $this->getVariants($_POST['inCartProductId']);
            
      
$variant $variants[$_POST['variant']];
      
$product['price'] = $variant['price'];           
      
$product['code'] = $variant['code'];
      
$product['count'] = $variant['count'];
      
$product['old_price'] = $variant['old_price'];
      
$product['weight'] = $variant['weight'];
      
$product['price_course'] = $variant['price_course'];   
    }

    
$cart = new Models_Cart;
    
$property $cart->createProperty($_POST);
    
$product['currency_iso'] = $product['currency_iso']?$product['currency_iso']:$currencyShopIso;
    
$product['price'] = $product['price_course'];
    
$product['price'] = SmalCart::plusPropertyMargin($product['price'], $property['propertyReal']);
    
    
    
$response = array(
      
'status' => 'success',
      
'data' => array(
        
'title' => $product['title'],
        
'price' => MG::numberFormat($product['price']).' '.MG::getSetting('currency'),
        
'old_price' => $product['old_price'].' '.MG::getSetting('currency'),
        
'code' => $product['code'],
        
'count' => $product['count'],
        
'price_wc' => $product['price'],
        
'weight' => $product['weight']
      )
    );

    echo 
json_encode($response);
    exit;
  }

  
/**
   * Возвращает набор вариантов товара.
   * 
   * @param $id - id продукта для поиска его вариантов
   * @return  $array - массив с параметрами варианта.
   */
  
public function getVariants($id$title_variants false) {
    
$results = array();
    if (!
$title_variants) {
      
$res DB::query('
      SELECT  pv.*, c.rate,(pv.price_course + pv.price_course *(IFNULL(c.rate,0))) as `price_course` 
      FROM `'
.PREFIX.'product_variant` pv   
        LEFT JOIN `'
.PREFIX.'product` as p ON 
          p.id = pv.product_id
        LEFT JOIN `'
.PREFIX.'category` as c ON 
          c.id = p.cat_id       
      WHERE pv.product_id = '
.DB::quote($id).'
      ORDER BY sort
    '
);     
      
    } else {    
      
$res DB::query('
        SELECT  pv.*
        FROM `'
.PREFIX.'product_variant` pv    
        WHERE pv.product_id = '
.DB::quote($id).'  and pv.title_variant = '.DB::quote($title_variants).'
        ORDER BY sort
      '
);
    }

    if (!empty(
$res)) {  
      while (
$variant DB::fetchAssoc($res)) {
        
$results[$variant['id']] = $variant;
      }
    }
    return 
$results;
  }

  
/**
   * Возвращает массив id характеристик товара, которые ненужно выводить в карточке.
   * @return  $array - массив с id.
   */
  
public function noPrintProperty() {
    
$results = array();
   
    
$res DB::query('
      SELECT  `id`
      FROM `'
.PREFIX.'property`     
      WHERE `activity` = 0'
);
    
    while (
$row DB::fetchAssoc($res)) {
      
$results[] = $row['id'];
    }
 
    return 
$results;
  }
  
  
/**
   * Возвращает HTML блок связанных товаров
   * @param type $args
   * @return type
   */
  
public function createRelatedForm($args,$title='С этим товаром покупают') {
    
    if(
$args){     
      
$data['title'] = $title;
      
      
$stringRelated ' null';
      
$sortRelated = array();
      foreach (
explode(',',$args) as $item) {
        
$stringRelated .= ','.DB::quote($item);
        
$sortRelated[$item] = $item;
      }
      
$stringRelated substr($stringRelated1);
      
      
$data['products'] = $this->getProductByUserFilter(' p.code IN ('.$stringRelated.') and p.activity = 1');
   
      if(!empty(
$data['products'])){
        
$data['currency'] = MG::getSetting('currency');
        foreach (
$data['products'] as $item) {            
          
$img explode('|',$item['image_url']);
          
$item['img'] = $img[0];
          
$item['url'] = SITE .'/'.(isset($item["category_url"]) ? $item["category_url"] : 'catalog').'/'.$item["product_url"];
          
$item['price'] = MG::priceCourse($item['price_course']);
          
$sortRelated[$item['code']] = $item;
        }
        
$data['products'] = array();
        
//сортируем связанные товары в том порядке, в котором они идут в строке артикулов
        
foreach ($sortRelated as $item) {
          if(!empty(
$item['id'])){
            
$data['products'][$item['id']] = $item;
          }
        }
       
        
$result MG::layoutManager('layout_related'$data);      
      }
      
    };
    
    
$args func_get_args();
    return 
MG::createHook(__CLASS__."_".__FUNCTION__$result$args);
  }
  
  
  
/**
   * Конвертирование стоимости товаров по заданному курсу.
   * @return  $iso - валюта в которую будет производиться конвертация.
   * @return  $productsId - массив с id продуктов.
   */
  
public function convertToIso($iso,$productsId=array()) {
    
    
$productsId implode(','$productsId);
    if(empty(
$productsId)){$productsId 0;};
    
    
// вычислим соотношение валют имеющихся в базе товаров к выбранной для замены
    // вычисление производится на основе имеющихся данных по отношению в  валюте магазина
    
$currencyShort MG::getSetting('currencyShort');     
    
$currencyRate MG::getSetting('currencyRate');
    
$currencyShopIso MG::getSetting('currencyShopIso'); 
    
    
// если есть непривязанные к валютам товары, то  назначаем им текущую валюту магазина
    
DB::query('
      UPDATE `'
.PREFIX.'product` SET 
            `currency_iso` = '
.DB::quote($currencyShopIso).'
      WHERE `currency_iso` =  "" AND `id` IN ('
.DB::quote($productsIdtrue).')');
    
DB::query('
      UPDATE `'
.PREFIX.'product_variant` SET 
            `currency_iso` = '
.DB::quote($currencyShopIso).'
      WHERE `currency_iso` =  "" AND `id` IN ('
.DB::quote($productsIdtrue).')');

    
// запоминаем   базовое соотношение курсов к валюте магазина
    
$rateBaseArray $currencyRate;  
    
$rateBase $currencyRate[$iso];  
    
// создаем новое соотношение валют по отношению в выбранной для конвертации
    
foreach ($currencyRate as $key => $value) {     
        if(!empty(
$rateBase)){    
          
$currencyRate[$key] = $value $rateBase;                 
        }        
    }
    
$currencyRate[$iso] = 1;
  
    
// пересчитываем цену, старую цену и цену по курсу для выбраных товаров
    
foreach ($currencyRate as $key => $rate) { 
      
DB::query('
      UPDATE `'
.PREFIX.'product`
      SET `price`= ROUND(`price`*'
.DB::quote($rate,TRUE).',2),
          `old_price`= ROUND(`old_price`*'
.DB::quote($rate,TRUE).',2),
          `price_course`= ROUND(`price`*'
.DB::quote($rateBaseArray[$iso],TRUE).',2)
      WHERE currency_iso = '
.DB::quote($key).' AND `id` IN ('.DB::quote($productsIdtrue).')');
      
      
// также и в вариантах
      
DB::query('
      UPDATE `'
.PREFIX.'product_variant`
       SET `price`= ROUND(`price`*'
.DB::quote($rate,TRUE).',2),
          `old_price`= ROUND(`old_price`*'
.DB::quote($rate,TRUE).',2),
          `price_course`= ROUND(`price`*'
.DB::quote($rateBaseArray[$iso],TRUE).',2)
      WHERE currency_iso = '
.DB::quote($key).' AND `product_id` IN ('.DB::quote($productsIdtrue).')');
    }
    
    
// всем выбранным продуктам изменяем ISO
     
DB::query('
      UPDATE `'
.PREFIX.'product`
      SET `currency_iso` = '
.DB::quote($iso).'
      WHERE `id` IN ('
.DB::quote($productsIdtrue).')');
     
     
DB::query('
      UPDATE `'
.PREFIX.'product_variant`
      SET `currency_iso` = '
.DB::quote($iso).'
      WHERE `product_id` IN ('
.DB::quote($productsIdtrue).')');

  }

   
/**
   * Создание дубля цены в заданном  курсе.

   */
  
public function updatePriceCourse($iso,$listId = array()) {
    
     if(empty(
$listId)){$listId 0;}
     else{
     
$listId implode(','$listId);     
     }
    
    
// вычислим соотношение валют имеющихся в базе товаров к выбранной для замены
    // вычисление производится на основе имеющихся данных по отношению в  валюте магазина
    
$currencyShort MG::getSetting('currencyShort');     
    
$currencyRate MG::getSetting('currencyRate');
    
$currencyShopIso MG::getSetting('currencyShopIso');     
 
    
$where '';
    if(!empty(
$listId)){
      
$where =' AND `id` IN ('.DB::quote($listIdtrue).')';
    }
    
    
$whereVariant '';
    if(!empty(
$listId)){
      
$whereVariant =' AND `product_id` IN ('.DB::quote($listIdtrue).')';
    }
    
    
DB::query('
     UPDATE `'
.PREFIX.'product` SET 
           `currency_iso` = '
.DB::quote($currencyShopIso).'
     WHERE `currency_iso` = "" '
.$where);
  
    
    
$rate $currencyRate[$iso];  
    foreach (
$currencyRate as $key => $value) {     
        if(!empty(
$rate)){
          
$currencyRate[$key] = $value $rate;                 
        }        
    }
    
$currencyRate[$iso] = 1;

    foreach (
$currencyRate as $key => $rate) {
    
      
DB::query('
      UPDATE `'
.PREFIX.'product` 
        SET `price_course`= ROUND(`price`*'
.DB::quote($rate,TRUE).',2)          
      WHERE currency_iso = '
.DB::quote($key).' '.$where);
     
      
DB::query('
      UPDATE `'
.PREFIX.'product_variant` 
        SET `price_course`= ROUND(`price`*'
.DB::quote($rate,TRUE).',2)         
      WHERE currency_iso = '
.DB::quote($key).' '.$whereVariant);
    }
    
  }
}
Онлайн: 1
Реклама