555 lines
16 KiB
PHP
555 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* NOTICE OF LICENSE
|
|
* With the purchase or the installation of the software in your application
|
|
* you accept the license agreement.
|
|
*
|
|
* You can not resell and redistribute this file.
|
|
*
|
|
* @author Dalibor Stojcevski <dal_sto@yahoo.com>
|
|
* @copyright 2019 Dalibor Stojcevski
|
|
* @license Dalibor Stojcevski
|
|
*/
|
|
|
|
/** No max line limit since the lines can be more than 4096. Performance impact is not significant. */
|
|
|
|
function filter_category_array ($element) {
|
|
return (!is_array($element) && $element !== '');
|
|
}
|
|
|
|
define('MAX_LINE_SIZE', 0);
|
|
|
|
class Import
|
|
{
|
|
|
|
private $json_array = array();
|
|
private $product_links = array();
|
|
private $settings;
|
|
|
|
public function __construct($settings)
|
|
{
|
|
$this->settings = $settings;
|
|
}
|
|
|
|
public function getAllData($path, $test = false)
|
|
{
|
|
$fields = $this->settings['import_api_field'];
|
|
$nested_data = array();
|
|
|
|
$id_parts = explode('->', $path);
|
|
|
|
array_shift($id_parts);
|
|
|
|
foreach ($fields as $field => $value) {
|
|
if(!$value) continue;
|
|
$field_paths = $value ? html_entity_decode($value, ENT_QUOTES, 'UTF-8') : '';
|
|
$field_parts = explode('->', $field_paths);
|
|
|
|
$nested_data[$field] = $this->getFieldData($this->json_array, $field_parts, $id_parts);
|
|
}
|
|
|
|
if ($test == 'view-raw') {
|
|
return $nested_data;
|
|
}
|
|
|
|
$nested_data = $this->checkCombinations($nested_data);
|
|
|
|
if ($test == 'view-split') {
|
|
return $nested_data;
|
|
}
|
|
|
|
$original_product = $this->resolveAllNestedData($nested_data);
|
|
|
|
if ($test == 'view-grouping') {
|
|
return $original_product;
|
|
}
|
|
|
|
$modified = $this->changeOriginal($original_product);
|
|
|
|
return $modified;
|
|
}
|
|
|
|
public function resolveAllNestedData($nested_data)
|
|
{
|
|
if (!empty($nested_data['feature_value'])) {
|
|
|
|
if (empty($nested_data['feature'])) {
|
|
if (!empty($this->settings['import_api_modification']['feature'])) {
|
|
$nested_data['feature'] = $this->settings['import_api_modification']['feature'];
|
|
} else {
|
|
$nested_data['feature'] = 'Feature';
|
|
}
|
|
}
|
|
|
|
$feature_map = $this->resolveNested($nested_data['feature_value'], $nested_data['feature']);
|
|
$nested_data['features'] = array();
|
|
|
|
foreach ($feature_map as $key => $map) {
|
|
$nested_data['features'][$key] = array(
|
|
'feature' => $map['parent'],
|
|
'feature_value' => $map['value']
|
|
);
|
|
}
|
|
}
|
|
$nested_data['attributes'] = array();
|
|
for ($i = 1;$i <= 3; $i++) {
|
|
|
|
if (!empty($nested_data['attribute_value' . $i])) {
|
|
if (empty($nested_data['attribute' . $i])) {
|
|
if (!empty($this->settings['import_api_modification']['attribute' . $i])) {
|
|
$nested_data['attribute' . $i] = $this->settings['import_api_modification']['attribute' . $i];
|
|
} else {
|
|
$nested_data['attribute' . $i] = 'Select ' . $i;
|
|
}
|
|
}
|
|
|
|
$attribute_map = $this->resolveNested($nested_data['attribute_value' . $i], $nested_data['attribute' . $i]);
|
|
|
|
$attribute_details_par = array('price', 'ean', 'quantity', 'weight');
|
|
foreach ($attribute_map as $key => $map) {
|
|
foreach ($attribute_details_par as $parameter) {
|
|
if (isset($nested_data['attribute_' . $parameter])) {
|
|
if (is_array($nested_data['attribute_' . $parameter])) {
|
|
if (isset($nested_data['attribute_' . $parameter][$key])) {
|
|
$nested_data['attribute_details'][$parameter][$map['value']] = $nested_data['attribute_' . $parameter][$key];
|
|
}
|
|
} else {
|
|
$nested_data['attribute_details'][$parameter][$map['value']] = $nested_data['attribute_' . $parameter];
|
|
}
|
|
}
|
|
}
|
|
$nested_data['attributes'][$i][$key] = array(
|
|
'attribute' => $map['parent'],
|
|
'attribute_value' => $map['value']
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($nested_data['category'])) {
|
|
|
|
if (!isset($nested_data['category_parent'])) {
|
|
$nested_data['category_parent'] = 0; // it is not good idea to put default top category here
|
|
}
|
|
|
|
if ($this->settings['import_api_settings']['category_path'] && is_array($nested_data['category'])) {
|
|
|
|
$nested_data['category'] = implode('->', array_filter($nested_data['category'], "filter_category_array"));
|
|
}
|
|
|
|
$nested_data['category_path'] = $this->resolveNested($nested_data['category'], $nested_data['category_parent']);
|
|
}
|
|
|
|
$nested_data['options'] = array();
|
|
if (!empty($nested_data['option_value'])) {
|
|
|
|
if (!isset($nested_data['option'])) {
|
|
$nested_data['option'] = $this->settings['import_api_default_option'];
|
|
}
|
|
|
|
if (!isset($nested_data['option_price'])) {
|
|
$nested_data['option_price'] = 0;
|
|
}
|
|
|
|
if (!isset($nested_data['option_weight'])) {
|
|
$nested_data['option_weight'] = 0;
|
|
}
|
|
|
|
$option_map= $this->resolveNested($nested_data['option_value'], $nested_data['option']);
|
|
$option_price_map = $this->resolveNested($nested_data['option_price'], $nested_data['option_value']);
|
|
$option_weight_map = $this->resolveNested($nested_data['option_weight'], $nested_data['option_value']);
|
|
foreach ($option_map as $key => $map) {
|
|
if (is_array($nested_data['option_price'])) {
|
|
foreach ($option_price_map as $price_map) {
|
|
if ($map['value'] == $price_map['parent']) {
|
|
$nested_data['options'][$key] = array(
|
|
'option' => $map['parent'],
|
|
'option_value' => $map['value'],
|
|
'price' => $price_map['value']
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
$nested_data['options'][$key] = array(
|
|
'option' => $map['parent'],
|
|
'option_value' => $map['value'],
|
|
'price' => $nested_data['option_price']
|
|
);
|
|
}
|
|
|
|
if (is_array($nested_data['option_weight'])) {
|
|
foreach ($option_weight_map as $weight_map) {
|
|
if($map['value'] == $weight_map['parent']){
|
|
$nested_data['options'][$key]['weight'] = $weight_map['value'];
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
$nested_data['options'][$key]['weight'] = $nested_data['option_weight'];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return $nested_data;
|
|
}
|
|
public function getFieldData($tree, $field_parts, $id_parts)
|
|
{
|
|
while($field_parts) {
|
|
if ($this->isSeq($tree)) {
|
|
$seq_id = array_shift($id_parts);
|
|
$tree = $tree[$seq_id];
|
|
} else {
|
|
|
|
$part = array_shift($field_parts);
|
|
$uni_c = array_shift($id_parts);
|
|
|
|
if($part == $uni_c){
|
|
$tree = $tree[$part];
|
|
|
|
} else {
|
|
$field_parts = array_merge([$part], $field_parts); // vrati mu ga
|
|
return $this->followDifferentPath($field_parts, $tree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function followDifferentPath($own_parts, $tree){
|
|
$prev= ''; // for test
|
|
foreach($own_parts as $part){
|
|
//if ($part == 'image') {var_dump($tree);var_dump($own_parts);exit;}
|
|
|
|
if ($this->isSeq($tree)) {
|
|
$ret = array();
|
|
foreach($tree as $t){
|
|
$ret[] = $this->followDifferentPath($own_parts, $t);
|
|
}
|
|
return $ret;
|
|
} else {
|
|
array_shift($own_parts);
|
|
$tree = isset($tree[$part]) ? $tree[$part] : '';
|
|
}
|
|
$prev = $part; //for test
|
|
}
|
|
|
|
if(!is_array($tree)){
|
|
return trim($tree);
|
|
}
|
|
|
|
return $tree;
|
|
}
|
|
|
|
public function findUniqueProductsIdentifier($tree, $parts, $identifier, $path = ''){
|
|
|
|
$tmp_parts = $parts;
|
|
foreach ($parts as $part) {
|
|
if ($part == $identifier && !$this->isSeq($tree) && isset($tree[$part])) {
|
|
|
|
if (!empty($tree[$part]) && !is_array($tree[$part])) {
|
|
$path .= '->'. $tree[$part];
|
|
$this->product_links[] = $path;
|
|
}
|
|
|
|
//exit;
|
|
|
|
} elseif ($this->isSeq($tree)) {
|
|
|
|
foreach($tree as $key => $t){
|
|
$local_path = $path. '->' . $key;
|
|
$this->findUniqueProductsIdentifier($t, $tmp_parts, $identifier, $local_path);
|
|
}
|
|
return;
|
|
} else {
|
|
|
|
if (isset($tree[$part])) {
|
|
$tree = $tree[$part];
|
|
$path .= '->'. $part;
|
|
}
|
|
|
|
array_shift($tmp_parts);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function resolveNested($child_data, $parent_data, $default_parent = 'Value'){
|
|
|
|
$child_indexes = array();
|
|
|
|
if(!is_array($child_data)){
|
|
$child_data = array($child_data);
|
|
}
|
|
|
|
$this->setIndexPath($child_data, $child_indexes);
|
|
|
|
|
|
$parent_indexes = array();
|
|
|
|
if(is_array($parent_data)){
|
|
$this->setIndexPath($parent_data, $parent_indexes);
|
|
} else {
|
|
$map = array();
|
|
foreach($child_indexes as $child){
|
|
|
|
$map[] = array(
|
|
'value' => $child['value'],
|
|
'parent' => $parent_data
|
|
);
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
return $this->addParent($child_indexes, $parent_indexes);
|
|
|
|
}
|
|
|
|
public function addParent($children, $parents){
|
|
$map = array();
|
|
foreach($parents as $parent){
|
|
foreach($children as $key => $child){
|
|
if(substr($child['key_path'], 0, strlen($parent['key_path'])) === $parent['key_path']){
|
|
$map[] = array(
|
|
'value' => $child['value'],
|
|
'parent' => $parent['value']
|
|
);
|
|
|
|
unset($children[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
/**
|
|
* Takes nested array with unknown nesting levels and return one level array with indexes to values.
|
|
*
|
|
* @param array $array array with unknown nesting levels
|
|
* @param string $key_path string made from array keys
|
|
* @return array with values and string from value indexes
|
|
*/
|
|
|
|
public function setIndexPath($array, &$return_values = array(), $key_path = ''){
|
|
foreach($array as $key => $array_part){
|
|
|
|
if(is_array($array_part)){
|
|
$this->setIndexPath($array_part, $return_values, $key_path . $key . '.');
|
|
} else {
|
|
$return_values[] = array(
|
|
'key_path' => $key_path . $key . '.',
|
|
'value' => $array_part
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public function changeOriginal($product)
|
|
{
|
|
$modifications = $this->settings['import_api_modification'];
|
|
|
|
foreach ($modifications as $field => $modification) {
|
|
//if (!$modification) {
|
|
if ($modification === '') {
|
|
continue;
|
|
}
|
|
|
|
if (in_array($field, ['price']) && !$product[$field]) {
|
|
continue;
|
|
}
|
|
|
|
if (!isset($product[$field])) {
|
|
$product[$field] = '';
|
|
}
|
|
|
|
if (in_array($field, ['image', 'images', 'cover']) && !$product[$field]) {
|
|
continue;
|
|
}
|
|
|
|
$modification = html_entity_decode($modification, ENT_QUOTES, 'UTF-8');
|
|
|
|
$modified = $this->check_string($modification, $product);
|
|
$product[$field] = $modified;
|
|
|
|
if (in_array($field, ['price', 'quantity', 'option_price','option_quantity', 'special', 'additional_shipping_cost', 'width', 'height', 'depth', 'weight', 'attribute_price', 'attribute_quantity', 'attribute_weight', 'minimal_quantity'])) {
|
|
$modified = $this->calculateMath($modified);
|
|
$product[$field] = $modified;
|
|
}
|
|
}
|
|
|
|
return $product;
|
|
}
|
|
|
|
public function checkCombinations($product)
|
|
{
|
|
$combinations = $this->settings['import_api_combination'];
|
|
|
|
foreach ($combinations as $field => $combination) {
|
|
if (!$combination || !isset($product[$field])) {
|
|
continue;
|
|
} else {
|
|
$position = 'all';
|
|
$parts = explode('##', $combination);
|
|
if(isset($parts[1])){
|
|
$position = $parts[1];
|
|
}
|
|
}
|
|
|
|
$exploded = $this->explodeCombinations($product[$field], $parts[0], $position);
|
|
$product[$field] = $exploded;
|
|
|
|
}
|
|
return $product;
|
|
}
|
|
|
|
public function explodeCombinations($value, $separator, $position = 'all')
|
|
{
|
|
if (!is_array($value)) {
|
|
$parts = explode($separator, $value);
|
|
if ($position == 'all') {
|
|
return $parts;
|
|
}
|
|
|
|
if ($position == 'last') {
|
|
return end($parts);
|
|
}
|
|
|
|
if (isset($parts[$position-1])) {
|
|
return $parts[$position-1];
|
|
}
|
|
|
|
return $value;
|
|
} else {
|
|
$ret = array();
|
|
foreach ($value as $key => $v) {
|
|
$ret[] = $this->explodeCombinations($v, $separator, $position);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
}
|
|
|
|
public function getProductLinks()
|
|
{
|
|
|
|
return $this->product_links;
|
|
}
|
|
|
|
private function check_string($string, $prod)
|
|
{
|
|
if ($string) {
|
|
preg_match_all('/\[\[([a-z_]*\#?[^\]]*)\]\]/', $string , $match);
|
|
if ($match) {
|
|
$string = $this->replace_string($string, $match[1], $prod);
|
|
}
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
private function replace_string($string, $keys, $d_array)
|
|
{
|
|
foreach ($keys as $key) {
|
|
$exploded_key = explode('#', $key);
|
|
$separator = false;
|
|
|
|
if (isset($exploded_key[1])) {
|
|
$string = str_replace($key, $exploded_key[0], $string);
|
|
$key = $exploded_key[0];
|
|
$separator = $exploded_key[1];
|
|
}
|
|
|
|
if (isset($d_array[$key])) {
|
|
if (is_array($d_array[$key])) {
|
|
$string = $this->replace_all_array_strings($d_array[$key], $key, $string, $separator);
|
|
} else {
|
|
$string = str_replace('[['. $key .']]', $d_array[$key], $string);
|
|
}
|
|
}
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
private function replace_all_array_strings($array, $key, $string, $separator = false)
|
|
{
|
|
$s = array();
|
|
foreach ($array as $d_part) {
|
|
$s[] = str_replace('[['. $key .']]', $d_part, $string);
|
|
}
|
|
|
|
if ($separator !== false) {
|
|
$s = implode($separator, $s);
|
|
}
|
|
|
|
return $s;
|
|
}
|
|
|
|
private function calculateMath($expression)
|
|
{
|
|
$expression = str_replace(',', '.', $expression);
|
|
$expression = str_replace(' ', '', $expression);
|
|
$expression = preg_replace('/[^0-9\.\+\-\*\/\(\)]/', '', $expression);
|
|
|
|
$expression = $this->replaceMathExpession($expression, '*');
|
|
$expression = $this->replaceMathExpession($expression, '/');
|
|
|
|
$expression = $this->replaceMathExpession($expression, '+');
|
|
$expression = $this->replaceMathExpession($expression, '-');
|
|
return $expression;
|
|
}
|
|
|
|
private function replaceMathExpession($expression, $sign)
|
|
{
|
|
$patern = '\\' . $sign;
|
|
$expression = preg_replace_callback(
|
|
'/[0-9]*\.?[0-9]+' . $patern . '[0-9]*\.?[0-9]+(' . $patern . '[0-9]*\.?[0-9]+)*/',
|
|
function ($matches) use ($sign) {
|
|
if (!empty($matches[0])) {
|
|
return $this->calculate_string($matches[0], $sign);
|
|
}
|
|
}, $expression);
|
|
return $expression;
|
|
}
|
|
|
|
private function calculate_string($string, $sign)
|
|
{
|
|
$parts = explode($sign, $string);
|
|
$final = $parts[0];
|
|
|
|
for ($i = 1; $i < count($parts); $i++) {
|
|
if ($sign == '*') {
|
|
$final = $final * $parts[$i];
|
|
} elseif ($sign == '/') {
|
|
$final = $final / $parts[$i];
|
|
} elseif ($sign == '+') {
|
|
$final = $final + $parts[$i];
|
|
} elseif ($sign == '-') {
|
|
$final = $final - $parts[$i];
|
|
}
|
|
}
|
|
return $final;
|
|
}
|
|
|
|
public function jsonToArray($json_url)
|
|
{
|
|
$json_string = @file_get_contents($json_url);
|
|
$json_array = json_decode($json_string, true);
|
|
return $json_array;
|
|
}
|
|
|
|
public function setJsonArray($json_array)
|
|
{
|
|
$this->json_array = $json_array;
|
|
}
|
|
|
|
public function isSeq($array)
|
|
{
|
|
if (is_array($array) ) {
|
|
return is_int(array_key_first($array));
|
|
}
|
|
//return is_array($array) && isset($array[0]);
|
|
return false;
|
|
}
|
|
}
|