application/modules/import_export/classes/BaseImport.php
<?php
namespace import_export\classes;
use CI_DB_active_record;
use CI_DB_result;
use CI_Model;
use Core;
use core\models\Route;
use Exception;
use import_export\classes\ProductsImport as ProductsHandler;
use MY_Controller;
use SPropertyValue;
use SPropertyValueQuery;
(defined('BASEPATH')) OR exit('No direct script access allowed');
/**
* @property Core $core
* @property CI_DB_active_record $db
*/
class BaseImport extends CI_Model
{
/**
* Class BaseImport
* @var BaseImport
*/
protected static $_instance;
/**
* Id currency
* @var Int
*/
public $currency = 2;
/**
* Charset
* @var string
*/
public $encoding = 'utf-8';
/**
* language
* @var string
*/
public $languages = 'ru';
/**
* language
* @var string
*/
public $mainLanguages;
/**
* Path to file
* @var string
*/
public $CSVsource = '';
/**
* CSV delimiter
* @var string
*/
public $delimiter = ';';
/**
* CSV enclosure
* @var string
*/
public $enclosure = '"';
/**
* Import type
* @var string
*/
public $importType = '';
/**
* Attributes
* @var array
*/
public $attributes = '';
/**
* The maximum number of fields
* @var int
*/
public $maxRowLength = 0;
/**
* Content
* @var array
*/
public $content = [];
/**
* Settings
* @var array
*/
public $settings = [];
/**
* Possible attributes
* @var array
*/
public $possibleAttributes = [];
/**
* Count products in CSV file
* @var int
*/
public $countProduct;
/**
* @var array
*/
public $allLanguages = [];
/**
* @var int
*/
public $maxRowLegth;
public function __construct() {
parent::__construct();
$this->languages = MY_Controller::getCurrentLocale();
$this->languages = $this->input->post('language') ?: $this->languages;
$this->getLangs();
}
private function getLangs() {
$langs = $this->db->get('languages')->result();
foreach ($langs as $val) {
$this->allLanguages[] = $val->identif;
if ($val->default == 1) {
$this->mainLanguages = $val->identif;
}
}
}
/**
* BaseImport Singleton
* @return BaseImport
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public static function create() {
(null !== self::$_instance) OR self::$_instance = new self();
return self::$_instance;
}
/**
* Start CSV Import
* @param integer $offers The final position
* @param integer $limit Step
* @param integer $countProd count products
* @param $EmptyFields
* @return false|null
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function makeImport($offers, $limit, $countProd, $EmptyFields) {
$this->makeAttributesList();
if ($offers == 0) {
$this->validateFile($offers, $limit);
} else {
$this->parseFile($offers, $limit);
$this->loadCategories($EmptyFields);
ProductsHandler::create()->make($EmptyFields);
$this->runProperties();
}
if (ImportBootstrap::noErrors()) {
ImportBootstrap::create()->addMessage(Factor::SuccessImportCompleted . '<b>' . $countProd . '</b>', Factor::MessageTypeSuccess);
} else {
return FALSE;
}
}
/**
* Get attributes list.
* @return BaseImport
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function makeAttributesList() {
if (!count($this->possibleAttributes)) {
$this->possibleAttributes = [
'skip' => lang('Skip column', 'import_export'),
'name' => lang('Product Name', 'import_export'),
'archive' => lang('Archive', 'import_export'),
'url' => lang('URL', 'import_export'),
'prc' => lang('Price', 'import_export'),
'oldprc' => lang('Old Price', 'import_export'),
'stk' => lang('Amount', 'import_export'),
'num' => lang('Article', 'import_export'),
'var' => lang('Variant name', 'import_export'),
'act' => lang('Active', 'import_export'),
'hit' => lang('Hit', 'import_export'),
'hot' => lang('Hot', 'import_export'),
'action' => lang('Action', 'import_export'),
'brd' => lang('Brand', 'import_export'),
'cat' => lang('Category', 'import_export'),
'addcats' => lang('Additional categories', 'import_export'),
'relp' => lang('Related products', 'import_export'),
'vimg' => lang('Main image variant', 'import_export'),
'cur' => lang('Currencies', 'import_export'),
'imgs' => lang('Additional images', 'import_export'),
'shdesc' => lang('Short description', 'import_export'),
'desc' => lang('Full description', 'import_export'),
'mett' => lang('Meta Title', 'import_export'),
'metd' => lang('Meta Description', 'import_export'),
'metk' => lang('Meta Keywords', 'import_export'),
];
$properties = $this->db->query(
'
SELECT shop_product_properties.id, shop_product_properties.csv_name, shop_product_properties_i18n.name
FROM `shop_product_properties`
LEFT OUTER JOIN `shop_product_properties_i18n` ON shop_product_properties.id = shop_product_properties_i18n.id
WHERE `csv_name` != "" AND shop_product_properties_i18n.locale = ?
',
$this->languages
)->result();
foreach ($properties as $property) {
$this->possibleAttributes[$property->csv_name] = $property->name;
}
}
return $this;
}
/**
* Validate Information and parse CSV. As a goal we have $content variable with file information.
* @param integer $offers The final position
* @param integer $limit Step
* @return false|null
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function validateFile($offers, $limit) {
if (substr(sprintf('%o', fileperms(ImportBootstrap::getUploadDir())), -4) != '0777') {
ImportBootstrap::addMessage(Factor::ErrorFolderPermission);
return FALSE;
}
if (!$file = @fopen($this->CSVsource, 'r')) {
ImportBootstrap::addMessage(Factor::ErrorFileReadError);
return FALSE;
}
$row = fgetcsv($file, $this->maxRowLegth, $this->delimiter, $this->enclosure);
if (!in_array('prc', $row) && !$this->attributeExist('prc')) {
ImportBootstrap::addMessage(Factor::ErrorPriceAttribute);
return FALSE;
}
if (!in_array('num', $row) && !$this->attributeExist('prc') && $this->importType == Factor::ImportProducts) {
ImportBootstrap::addMessage(Factor::ErrorNumberAttribute);
return FALSE;
}
if ((count($this->possibleAttributes) - count(array_diff($this->possibleAttributes, $row))) == count($this->attributes)) {
$this->attributes = $row;
} elseif (count($row) === count($this->attributes)) {
rewind($file);
} else {
ImportBootstrap::addMessage(Factor::ErrorPossibleAttrValues);
return FALSE;
}
$this->parseFile($offers, $limit, $file);
}
/**
* @param string $attribute
* @return bool
*/
public function attributeExist($attribute) {
$attributes = \CI::$APP->input->post('attributes');
if (!$attributes) {
return TRUE;
}
$attributes = explode(',', $attributes);
return in_array($attribute, $attributes) ? TRUE : FALSE;
}
/**
* File parsing
* @param integer $offers The final position
* @param integer $limit Step
* @param $file
* @return boolean
*/
public function parseFile($offers, $limit, $file = false) {
if (!$file) {
$file = @fopen($this->CSVsource, 'r');
}
if ($offers > 0) {
$positionStart = $offers - $limit;
$cnt = 0;
$iOffer = 0;
while (($row = fgetcsv($file, $this->maxRowLegth, $this->delimiter, $this->enclosure)) !== false) {
if ($cnt != 0) {
if ($iOffer < $positionStart) {
$iOffer++;
} else {
$this->content[] = array_combine($this->attributes, array_map('trim', $row));
}
}
if ($cnt >= $offers) {
break;
}
$cnt++;
}
} else {
$cnt = 0;
while (($row = fgetcsv($file, $this->maxRowLegth, $this->delimiter, $this->enclosure)) !== false) {
if ($cnt != 0) {
$this->countProduct++;
}
$cnt = 1;
}
$_SESSION['countProductsInFile'] = $this->countProduct;
}
fclose($file);
return TRUE;
}
/**
* Process Categories
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function loadCategories() {
if (ImportBootstrap::hasErrors()) {
return FALSE;
}
$this->load->helper('translit');
foreach ($this->content as $key => $node) {
if ($node['cat'] == '') {
continue;
}
if (trim($node['addcats'])) {
$cats = explode('|', $node['addcats']);
foreach ($cats as $cat) {
$this->content(['cat' => $cat], $key);
}
}
$this->content($node, $key);
}
}
/**
* @param string $node
* @param string $key
*/
private function content($node, $key) {
$parts = $this->parseCategoryName($node['cat']);
$pathIds = $pathNames = [];
$parentId = $line = 0;
foreach ($parts as $part) {
/* Find existing category */
$binds = [
$part,
$this->languages,
$parentId,
];
// $binds = array($part, $this->mainLanguages, $parentId);
$result = $this->db->query(
'
SELECT SCategory.id AS CategoryId
FROM `shop_category_i18n` AS SCategoryI18n
RIGHT OUTER JOIN `shop_category` AS SCategory ON SCategory.id = SCategoryI18n.id
WHERE SCategoryI18n.name = ? AND SCategoryI18n.locale = ? AND SCategory.parent_id = ?',
$binds
);
if ($result) {
$result = $result->row();
} else {
Logger::create()->set('Error $result in CategoryImport.php - IMPORT');
}
if (!($result instanceof \stdClass)) {
/* Create new category */
$lastPosition = $this->db->query('SELECT max(position) AS maxPos FROM `shop_category`')->row()->maxPos;
$binds = [
'parent_id' => $parentId,
'full_path_ids' => serialize($pathIds),
'active' => 1,
'position' => $lastPosition + 1,
];
$this->db->insert('shop_category', $binds);
$newCategoryId = $this->db->insert_id();
if ($newCategoryId) {
$route = [
'parent_url' => implode('/', array_map('translit_url', $pathNames)),
'url' => translit_url($part),
'entity_id' => $newCategoryId,
'type' => Route::TYPE_SHOP_CATEGORY,
];
$this->db->insert('route', $route);
$newRouteId = $this->db->insert_id();
$this->db->update('shop_category', ['route_id' => $newRouteId], ['id' => $newCategoryId]);
}
if (!$newCategoryId) {
Logger::create()->set('Error INSERT category or SELECT id new category in CategoryImport.php - IMPORT');
}
/* Add translation data for new category */
foreach ($this->allLanguages as $val) {
$this->db->insert('shop_category_i18n', ['id' => $newCategoryId, 'locale' => $val, 'name' => trim($part)]);
}
$this->content[$key]['CategoryId'] = $pathIds[] = $parentId = $newCategoryId;
$this->content[$key]['CategoryIds'] = $pathIds;
} else {
$this->content[$key]['CategoryId'] = $pathIds[] = $parentId = $result->CategoryId;
$this->content[$key]['CategoryIds'] = $pathIds;
}
$pathNames[] = $part;
}
}
/**
* Parse Category Name by slashes
* @param string $name
* @return array
* @access private
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
private function parseCategoryName($name) {
$result = array_map('trim', array_map('stripcslashes', preg_split('/\\REPLACE((?:[^\\\\\REPLACE]|\\\\.)*)/', $name, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)));
return explode('/', $result[0]);
}
/**
* FROM PropertiesImport
*/
/**
* Process Properties Handling
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function runProperties() {
if (ImportBootstrap::hasErrors()) {
return FALSE;
}
$properties = $this->db->query('SELECT `id`, `csv_name` FROM `shop_product_properties`')->result();
foreach ($properties as $property) {
$propertyAlias[$property->csv_name] = $property->id;
}
foreach ($this->content as $node) {
foreach ($node as $nodeKey => $nodeElement) {
if (array_key_exists($nodeKey, $propertyAlias)) {
$result = $this->db->query('SELECT * FROM `shop_product_properties_data` WHERE `product_id` = ? AND `property_id` = ?', [$node['ProductId'], $propertyAlias[$nodeKey]])->row();
if ($result instanceof \stdClass) {
$this->db->delete(
'shop_product_properties_data',
[
'product_id' => $node['ProductId'],
'property_id' => $propertyAlias[$nodeKey],
]
);
}
$values = array_map('trim', explode('|', $nodeElement));
foreach ($values as $v) {
$v = htmlspecialchars($v);
if ($v !== '') {
$property_value = SPropertyValueQuery::create()
->useSPropertyValueI18nQuery()
->filterByLocale($this->languages)
->filterByValue($v)
->endUse()
->findOneByPropertyId($propertyAlias[$nodeKey]);
if (!$property_value) {
$property_value = new SPropertyValue();
$property_value->setPropertyId($propertyAlias[$nodeKey]);
$property_value->setLocale($this->languages);
$property_value->setValue($v);
$property_value->save();
}
$this->checkPropertiesData($propertyAlias[$nodeKey], $node['ProductId'], $property_value->getId());
}
}
foreach ($node['CategoryIds'] as $categoryId) {
$result = $this->db->query('SELECT * FROM `shop_product_properties_categories` WHERE `category_id` = ? AND `property_id` = ?', [$categoryId, $propertyAlias[$nodeKey]])->row();
if (!($result instanceof \stdClass) && !empty($nodeElement)) {
$this->db->insert('shop_product_properties_categories', ['property_id' => $propertyAlias[$nodeKey], 'category_id' => $categoryId]);
}
}
$propery = $this->db->query(
'
SELECT `id`, `name`
FROM `shop_product_properties_i18n`
WHERE id = ? AND locale = ?',
[
$propertyAlias[$nodeKey],
$this->languages,
]
)->row();
$data = (!empty($propery->data)) ? unserialize($propery->data) : [];
$changed = false;
foreach ($values as $v) {
if (!in_array($v, $data, true)) {
$changed = true;
$data[] = $v;
}
}
if ($changed) {
$this->db->update('shop_product_properties_i18n', ['data' => serialize($data)], ['id' => $propertyAlias[$nodeKey], 'locale' => $this->languages]);
}
}
}
}
}
/**
* @param int $property_id
* @param int $product_id
* @param int $value_id
* @return bool
*/
private function checkPropertiesData($property_id, $product_id, $value_id) {
$import_data = [
'property_id' => $property_id,
'product_id' => $product_id,
'value_id' => $value_id,
];
/** @var CI_DB_result $test */
$test = $this->db->get_where('shop_product_properties_data', $import_data);
if ($test->num_rows() > 0) {
return false;
}
$this->db->insert('shop_product_properties_data', $import_data);
}
/**
* Set Import Type. Must be setted before import start.
* @param $type
* @return BaseImport
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function setImportType($type) {
$this->importType = $type;
return $this;
}
/**
* FROM CategoryImport
*/
/**
* Set Import Settings. Must be setted before import start.
* @param $settings
* @return BaseImport
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function setSettings($settings) {
$this->settings = $settings;
$this->attributes = array_diff(explode(',', $this->settings['attributes']), [null]);
return $this;
}
/**
* Set Import file name. Must be setted before import start.
* @param string $fileName
* @return BaseImport
* @access public
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function setFileName($fileName) {
try {
if (FALSE === file_exists($fileName)) {
throw new Exception(Factor::ErrorEmptySlot);
}
$this->CSVsource = $fileName;
return $this;
} catch (Exception $exc) {
$result[Factor::MessageTypeSuccess] = FALSE;
$result[Factor::MessageTypeError] = FALSE;
$result['message'] = $exc->getMessage();
echo json_encode($result);
exit();
}
}
/**
* Add new value to custom field and save it.
* @param mixed $name
* @param mixed $value
* @access public
* @return void
* @author Kaero
* @copyright ImageCMS (c) 2012, Kaero <dev@imagecms.net>
*/
public function addCustomFieldValue($name, $value) {
if (array_key_exists($name, $this->customFieldsCache)) {
$fieldDataArray = $this->customFieldsCache[$name]->getDataArray();
if ($fieldDataArray === null) {
$fieldDataArray = [];
}
if (!in_array($value, $fieldDataArray)) {
array_push($fieldDataArray, $value);
$newData = implode("\n", $fieldDataArray);
$this->customFieldsCache[$name]->setData($newData);
$this->customFieldsCache[$name]->save();
$this->customFieldsCache[$name]->setVirtualColumn('dataArray', $fieldDataArray);
$this->customFieldsCache[$name]->setData($newData);
}
}
}
}