| Server IP : 85.158.181.41 / Your IP : 216.73.217.12 Web Server : Apache System : Linux cloud9-vm129 6.1.178+1-ph #ph SMP PREEMPT_DYNAMIC Wed Jul 29 09:00:54 UTC 2026 x86_64 User : moncbefd ( 1024) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/moncbefd/www.moneta.at/system/classes/gambio_xml/ |
Upload File : |
<?php
/* --------------------------------------------------------------
GxmlMaster.inc.php 2016-07-25
Gambio GmbH
http://www.gambio.de
Copyright (c) 2016 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------
*/
require_once(DIR_FS_CATALOG . 'inc/xtc_get_geo_zone_code.inc.php');
/**
* Class GxmlMaster
*
* Contains the implementations of the general methods used in the Gambio XML
* API. The API is split into multiple plugins each of which handle a specific
* section of the shop data. The request router class will load and call the
* required method and the requested plugin will make the requested actions and
* produce a response in order to be returned back to the client.
*
* Refactored by A.Tselegidis
*
* @category System
* @package GambioAPI
* @version 1.0
*/
abstract class GxmlMaster
{
/**
* @var array
*/
protected $mapperArray = array();
/**
* @var array
*/
protected $tableMapperArray = array();
/**
* @var array
*/
protected $languageDependentMapperArray = array();
/**
* @var GxmlHelper
*/
protected $gxmlHelper;
/**
* @var SimpleXMLElement
*/
protected $responseXml;
/**
* @var string
*/
protected $pluralName;
/**
* @var string
*/
protected $singularName;
/**
* @var array
*/
protected $languageArray;
/**
* @var array
*/
protected $taxArray;
/**
* @var SimpleXMLElement
*/
protected $responseXmlBuffer;
/**
* Class Constructor
*/
public function __construct()
{
$this->gxmlHelper = MainFactory::create_object('GxmlHelper');
$this->responseXml = simplexml_load_string($this->gxmlHelper->getBlankXml());
$this->responseXmlBuffer = simplexml_load_string($this->gxmlHelper->getBlankXml());
$this->_loadLanguages();
$this->_loadTaxes();
}
/**
* Abstract Add Node Method
*
* This method will be implemented by some child classes in order to add XML nodes
* to the response XML object.
*
* @param array $data
* @param string $tableColumn
* @param string $nodeName
* @param SimpleXMLElement $xml
*/
abstract protected function _addNode(array $data, $tableColumn, $nodeName, SimpleXMLElement $xml);
/**
* Abstract Method Delete Object from Database
*
* @param SimpleXMLElement $requestXml
*/
abstract protected function _deleteObject(SimpleXMLElement $requestXml);
/**
* Generates a response XML object out of a response array.
*
* @param array $responseData Must contain the response data (associative array).
*
* @return SimpleXMLElement
*/
public function generateResponseXml(array $responseData)
{
$xml = simplexml_load_string($this->gxmlHelper->getBlankXml());
$isSuccessful = true;
$xml->addChild('request');
$xml->addChild($this->pluralName);
foreach($responseData as $item)
{
$childNode = $xml->{$this->pluralName}->addChild($this->singularName);
if(isset($item['external_' . $this->singularName . '_id']))
{
$childNode->addChild('external_' . $this->singularName . '_id', $item['external_' . $this->singularName . '_id']);
}
$childNode->addChild($this->singularName . '_id', $item[$this->singularName . '_id']);
$childNode->addChild('success', $item['success']);
$childNode->addChild('errormessage', $item['errormessage']);
$childNode->addChild('action_performed', $item['action_performed']);
$isSuccessful &= (boolean)$item['success'];
}
if (!$isSuccessful)
{
$xml->request->addChild('errormessage', 'request error');
}
$xml->request->addChild('success', $isSuccessful);
return $xml;
}
/**
* Change encoding to latin1.
*
* @param mixed $p_data Data could be either array, string or object. Otherwise there
* won't be any conversion and the $p_data value will be reutrned
* as it is.
*
* @return string Returns the latin1 encoded value of the $p_data parameter.
*/
public function convertToLatin1($p_data)
{
if(is_array($p_data))
{
$converted = array();
foreach($p_data as $key=>$value)
{
$key = $this->utf8Decode($key);
$converted[$key] = $this->convertToLatin1($value);
}
}
elseif(is_object($p_data))
{
$vars = array_keys(get_object_vars($p_data));
$converted = $p_data;
foreach($vars AS $var)
{
$converted->var = $this->convertToLatin1($p_data->$var);
}
}
elseif(is_string($p_data))
{
$converted = $this->utf8Decode($p_data);
}
else
{
$converted = $p_data;
}
return $converted;
}
/**
* Check if string is utf8 encoded.
*
* @param $p_string String value to be cheked.
*
* @return bool Returns the check result.
*/
public function isUtf8String($p_string)
{
if(preg_match('/(?:[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/xs', $p_string))
{
return true;
}
return false;
}
/**
* Decode UTF8 string.
*
* @param string $p_string The string to be decoded.
*
* @return string Returns the decoded string.
*/
public function utf8Decode($p_string)
{
if($this->isUtf8String($p_string))
{
$targetCharset = 'ISO-8859-15';
if(isset($_SESSION['language_charset']))
{
$targetCharset = trim(strtoupper($_SESSION['language_charset']));
}
if($targetCharset != 'UTF-8')
{
if(function_exists('iconv'))
{
$p_string = iconv("UTF-8", $targetCharset . "//TRANSLIT", $p_string);
}
else
{
$p_string = utf8_decode($p_string);
}
}
}
return $p_string;
}
/**
* Add a child XML node to a parent element.
*
* @param SimpleXMLElement $parentXml Parent XML object.
* @param SimpleXMLElement $childXml Child XML node will be added to parent.
* @param bool $includeXmlDeclaration (Optional) Whether to include the Xml declaration on the result.
*
* @return bool Returns the operation result.
*/
public function addXmlChild(SimpleXMLElement $parentXml, SimpleXMLElement $childXml, $includeXmlDeclaration = true)
{
$xmlString = (string) $childXml->asXML();
if($includeXmlDeclaration == false)
{
$xmlLineArray = explode("\n", $xmlString);
array_shift($xmlLineArray);
$xmlString = implode("\n", $xmlLineArray);
}
$domParent = dom_import_simplexml($parentXml);
$domChild = $domParent->ownerDocument->createDocumentFragment();
$domChild->appendXML($xmlString);
$result = (boolean)$domParent->appendChild($domChild);
return $result;
}
/**
* Delete an XML child node by tag name.
*
* @param SimpleXMLElement $xml The XML to be edited.
* @param string $p_tagName The tag name to be removed.
*/
public function deleteXmlChildrenByTagName(SimpleXMLElement $xml, $p_tagName)
{
$domParent = dom_import_simplexml($xml);
for($i = 0; $i < count($domParent->getElementsByTagName($p_tagName)); $i++)
{
$actual = $domParent->getElementsByTagName($p_tagName)->item($i);
if(!empty($actual))
{
$domParent->removeChild($actual);
$i--;
}
}
}
/**
* Wrap a node value with a prefix and a post fix.
*
* By default the <!CDATA[...]]> wrapper is used.
*
* @param sting $p_value This value will be wrapped by the prefix and the postfix.
* @param string $p_prefix (Optional) Will be added before the value.
* @param string $p_suffix (Optional) Will be added after the value.
*
* @return string Returns the wrapped value.
*/
public function wrapValue($p_value, $p_prefix = '<![CDATA[', $p_suffix = ']]>')
{
$wrappedValue = $p_value;
if($p_value !== '')
{
$wrappedValue = $p_prefix . $p_value . $p_suffix;
}
return $wrappedValue;
}
/**
* Add data in an XML object.
*
* @param array $data Includes the data to be included in the XML object.
* @param SimpleXMLElement $xml The object to be edited.
*/
public function add(array $data, $xml)
{
foreach ($this->mapperArray as $nodeName=>$tableColumn)
{
$this->_addNode($data, $tableColumn, $nodeName, $xml);
}
}
/**
* Check if node exists inside an XML object.
*
* @param SimpleXMLElement $xml The XML object to be searched.
* @param string $p_nodeName Node name to be found.
* @param array $p_attributesArray (Optional) If provided, the method will include attributes in the search.
* @param string $p_attributeConjunction (Optional) Attribute conjunction string (must be either "and" - "or").
*
* @return bool Returns whether the node was found or not.
*/
public function nodeExists(SimpleXMLElement $xml, $p_nodeName, $p_attributesArray = array(), $p_attributeConjunction = 'and')
{
$nodeChildren = $xml->children();
foreach ($nodeChildren as $nodeName=>$nodeValuesArray)
{
if ($nodeName == $p_nodeName)
{
if (empty($p_attributesArray))
{
return true;
}
else
{
$nodeExists = null;
foreach ($p_attributesArray as $attrName=>$attrValue)
{
$nodeValuesAttributes = $nodeValuesArray->attributes();
switch ($p_attributeConjunction)
{
case 'or':
if ($nodeExists === null)
{
$nodeExists = false;
}
$nodeExists |= isset($nodeValuesAttributes[$attrName]) && (string)$nodeValuesAttributes[$attrName][0] == $attrValue;
break;
case 'and':
if ($nodeExists === null)
{
$nodeExists = true;
}
$nodeExists &= isset($nodeValuesAttributes[$attrName]) && (string)$nodeValuesAttributes[$attrName][0] == $attrValue;
break;
default:
break;
}
}
return (boolean)$nodeExists;
}
}
}
return false;
}
/**
* Check if node value exists.
*
* @param SimpleXMLElement $xml The XML object to be searched.
* @param string $p_nodeName The node name that will be searched.
* @param string $p_nodeValueName The node value name that needs to be searched.
* @param string $p_nodeValue The node value that needs to be found.
* @param array $attributes (Optional) If provided, node attributes will be included
* in the search.
*
* @return bool Returns the search result.
*/
public function nodeValueExists(SimpleXMLElement $xml, $p_nodeName, $p_nodeValueName, $p_nodeValue, array $attributes = array())
{
$nodeExists = false;
foreach($xml->{$p_nodeName} as $nodeName => $nodeValuesArray)
{
if($nodeName == $p_nodeName)
{
if(empty($attributes))
{
foreach($nodeValuesArray->children() as $nodeValueName => $nodeValueArray)
{
if($nodeValueName == $p_nodeValueName && $p_nodeValue == (string)$nodeValueArray[0])
{
$nodeExists = $nodeValuesArray;
break;
}
}
}
else
{
foreach($attributes as $attrName => $attrValue)
{
foreach($nodeValuesArray->attributes() as $nodeAttrName=>$valueArray)
{
if($attrName == $nodeAttrName && (string)$valueArray[0] == $attrValue)
{
foreach($nodeValuesArray->children() as $nodeValueName => $nodeValueArray)
{
if($nodeValueName == $p_nodeValueName && $p_nodeValue == (string)$nodeValueArray[0])
{
$nodeExists = $nodeValuesArray;
break;
}
}
}
}
}
}
}
}
return $nodeExists;
}
/**
* Get an XML object that contains data about an API relative exception.
*
* @param Exception $ex The exception object that will be interpreted into
* the XML document.
*
* @return SimpleXMLElement Returns the XML document object that contains the
* exception information.
*/
public function handleApiException(Exception $ex)
{
// Return an error response.
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><GambioXML/>');
$xml->addChild('request');
$xml->request->addChild('success', '0');
$xml->request->addChild('errormessage', $ex->getMessage());
$xml->request->addChild('stack', $ex->getTraceAsString());
return $xml;
}
/**
* Get plural name of current class section.
*
* @return string
*/
protected function _getPluralName()
{
return $this->pluralName;
}
/**
* Set plural name of current class section.
*
* @param string $p_name
*/
protected function _setPluralName($p_name)
{
$this->pluralName = $p_name;
}
/**
* Get singular name of current class section.
*
* @return string
*/
protected function _getSingularName()
{
return $this->singularName;
}
/**
* Set singular name of current class section.
*
* @param string $p_name
*/
protected function _setSingularName($p_name)
{
$this->singularName = $p_name;
}
/**
* Save record to database.
*
* @param $p_dataObject
* @param $p_dataArray
* @param bool $p_primaryKeyName
* @param bool $p_primaryKeyValue
* @param bool $p_update
*
* @return bool|int|resource
*/
protected function _save(&$p_dataObject, $p_dataArray, $p_primaryKeyName = false, $p_primaryKeyValue = false, $p_update = false, array $p_primaryKeyArray = array())
{
$newRecordId = false;
$dataArray = $this->convertToLatin1($p_dataArray);
if (is_array(current($dataArray)) && $p_dataObject->v_db_table != TABLE_PRODUCTS_XSELL && $p_dataObject->v_db_table != 'products_properties_combis_values' && $p_dataObject->v_db_table != 'image_data' && $p_dataObject->v_db_table != TABLE_PRODUCTS_IMAGES && $p_dataObject->v_db_table != 'gm_prd_img_alt')
{
if(strpos($p_dataObject->v_db_table, TABLE_PERSONAL_OFFERS_BY) !== false)
{
foreach ($dataArray as $p_personal_offer_data_array)
{
if($p_update === true)
{
$p_dataObject->set_keys(array($p_primaryKeyName => $p_primaryKeyValue, 'quantity' => $p_personal_offer_data_array['quantity']));
}
else
{
$p_dataObject->set_keys(array($p_primaryKeyName => false));
}
$p_dataObject->set_data_value($p_primaryKeyName, $p_primaryKeyValue);
foreach ($p_personal_offer_data_array as $key=>$value)
{
$p_dataObject->set_data_value($key, $value);
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update');
if($p_update === true && $newRecordId === false)
{
$p_dataObject->set_keys(array($p_primaryKeyName => false));
$newRecordId = $this->_performDbAction($p_dataObject, 'update');
}
}
}
else
{
foreach ($dataArray as $t_language_id => $p_language_data_array)
{
if ($p_update)
{
$p_dataObject->set_keys(array($p_primaryKeyName => $p_primaryKeyValue, 'language_id' => $t_language_id));
}
else
{
$p_dataObject->set_keys(array($p_primaryKeyName => false));
$p_dataObject->set_data_value('language_id', $t_language_id);
}
foreach ($p_language_data_array as $key => $value)
{
$p_dataObject->set_data_value($key, $value);
}
if($p_primaryKeyName !== false && $p_primaryKeyValue !== false)
{
if($p_primaryKeyName != 'language_id' || $p_primaryKeyName == 'language_id' && in_array($p_dataObject->v_db_table, $this->languageDependentMapperArray))
{
$p_dataObject->set_data_value($p_primaryKeyName, $p_primaryKeyValue);
}
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update');
if($p_update === true && $newRecordId === false)
{
$p_dataObject->set_keys(array($p_primaryKeyName => false));
$p_dataObject->set_data_value('language_id', $t_language_id);
$newRecordId = $this->_performDbAction($p_dataObject, 'update');
}
}
}
}
elseif ($p_dataObject->v_db_table == TABLE_PRODUCTS_XSELL)
{
// insert and update
if(isset($p_dataArray['xsell_updates']) && is_array($p_dataArray['xsell_updates']))
{
foreach($p_dataArray['xsell_updates'] as $t_xsell_update)
{
$p_dataObject->set_data_value('products_id', $p_primaryKeyValue);
$p_dataObject->set_data_value('products_xsell_grp_name_id', 0);
$p_dataObject->set_data_value('xsell_id', (int)$t_xsell_update['product_id']);
isset($t_xsell_update['sort_order']) ? $t_sort_order = (int)$t_xsell_update['sort_order'] : $t_sort_order = 0;
$p_dataObject->set_data_value('sort_order', $t_sort_order);
$this->_performDbAction($p_dataObject, 'update', true);
}
}
// delete
if(isset($p_dataArray['xsell_deletion']) && is_array($p_dataArray['xsell_deletion']))
{
foreach($p_dataArray['xsell_deletion'] as $t_xsell_deletion)
{
$p_dataObject->set_keys(array($p_primaryKeyName => $p_primaryKeyValue, 'xsell_id' => $t_xsell_deletion['product_id']));
$this->_performDbAction($p_dataObject, 'delete');
}
}
return true;
}
else if ($p_dataObject->v_db_table == TABLE_PRODUCTS_TO_CATEGORIES)
{
$t_categories = explode(',', $dataArray['categories_id']);
foreach ($t_categories as $t_category_id)
{
$p_dataObject->set_data_value($p_primaryKeyName, $p_primaryKeyValue);
$p_dataObject->set_data_value('categories_id', $t_category_id);
$this->_performDbAction($p_dataObject, 'update', true);
}
$t_delete_categories = explode(',', $dataArray['delete_categories_id']);
foreach ($t_delete_categories as $t_category_id)
{
if($t_category_id === '')
{
continue;
}
$p_dataObject->set_keys(array($p_primaryKeyName => $p_primaryKeyValue, 'categories_id' => $t_category_id));
$this->_performDbAction($p_dataObject, 'delete');
}
}
else if ($p_dataObject->v_db_table == 'products_properties_combis_values')
{
foreach ($dataArray as $t_property_value)
{
foreach ($t_property_value as $key => $value)
{
$p_dataObject->set_data_value($key, $value);
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update', true);
}
}
else if ($p_dataObject->v_db_table == 'image_data')
{
foreach ($dataArray as $productImageData)
{
$p_dataObject->v_db_table = TABLE_PRODUCTS_IMAGES;
$newRecordId = $this->_save($p_dataObject, $productImageData['products_images'], $p_primaryKeyName, $p_primaryKeyValue, $p_update);
$newImageId = $newRecordId;
if(isset($productImageData['gm_prd_img_alt']))
{
$p_dataObject->v_table_content = array();
$p_dataObject->v_db_table = 'gm_prd_img_alt';
$newRecordId = $this->_save($p_dataObject, $productImageData['gm_prd_img_alt'], '', '', $p_update, array('image_id' => $newRecordId, $p_primaryKeyName => $p_primaryKeyValue));
}
$p_dataObject->v_table_content = array();
$responseArray = array(
'image_id' => $newImageId,
'success' => 1,
'errormessage' => '',
'action_performed' => (isset($productImageData['products_images']['image_id']) ? 'update' : 'insert')
);
if(isset($productImageData['products_images']['external_image_id'])
&& !empty($productImageData['products_images']['external_image_id']))
{
$responseArray['external_image_id'] = $productImageData['products_images']['external_image_id'];
}
$imageData = $this->_generateAdditionalImagesResponseXml($responseArray);
$image = $this->responseXmlBuffer->addChild('image');
foreach($imageData as $property => $propertyValue)
{
$image->addChild($property, $propertyValue);
}
}
}
else if ($p_dataObject->v_db_table == TABLE_PRODUCTS_IMAGES)
{
$p_dataObject->set_keys(array('products_id' => $p_primaryKeyName, 'image_nr' => $dataArray['image_nr']));
$p_dataObject->set_data_value('products_id', $p_primaryKeyValue);
foreach ($dataArray as $key => $value)
{
if ($key == 'external_image_id')
{
continue;
}
$p_dataObject->set_data_value($key, $value);
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update', true);
}
else if ($p_dataObject->v_db_table == 'gm_prd_img_alt')
{
foreach ($dataArray as $t_language_id => $t_image_alt_data)
{
$primaryKeyArray = $p_primaryKeyArray;
$primaryKeyArray['language_id'] = $t_language_id;
foreach ($t_image_alt_data as $key => $value)
{
$p_dataObject->set_keys($primaryKeyArray);
$p_dataObject->set_data_value($key, $value);
foreach($primaryKeyArray as $keyName => $keyValue)
{
$p_dataObject->set_data_value($keyName, $keyValue);
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update', true);
}
}
}
else
{
if ($p_update && $p_dataObject->v_db_table != TABLE_ORDERS_STATUS_HISTORY)
{
$p_dataObject->set_keys(array($p_primaryKeyName => $p_primaryKeyValue));
}
else
{
$p_dataObject->set_keys(array($p_primaryKeyName => false));
}
foreach($dataArray as $key => $value)
{
$p_dataObject->set_data_value($key, $value);
}
if($p_primaryKeyName !== false && $p_primaryKeyValue !== false)
{
$p_dataObject->set_data_value($p_primaryKeyName, $p_primaryKeyValue);
}
$newRecordId = $this->_performDbAction($p_dataObject, 'update');
}
return $newRecordId;
}
/**
* Save object to database.
*
* When the client sents an upload requests that stores data in the database this
* method will be called from the "_upload" method and perform the insert-update
* operation.
*
* @param SimpleXMLElement $xml Contains the object to be stored in the database.
*
* @return numeric Returns the record ID.
*/
protected function _saveObject(SimpleXMLElement $xml)
{
$xmlData = $this->_parseXmlData($xml);
// Load data objects by using the given xml node values.
$tableNames = array_keys($xmlData);
$dataObjects = array();
foreach ($tableNames as $name)
{
$dataObjects[$name] = MainFactory::create_object('GMDataObject', array($name));
}
$idColumn = $xml->getName() . '_id';
$recordId = (string)$xml->{$idColumn};
$isUpdate = false;
if(!empty($recordId))
{
if(empty($this->v_default_action) || $this->v_default_action == 'update')
{
$isUpdate = true;
}
}
else
{
$recordId = false;
}
// Save record to database.
$dbIdColumn = $this->mapperArray[$idColumn];
$dbTable = $this->tableMapperArray[$idColumn];
$tableObject = $dataObjects[$dbTable];
$recordData = $xmlData[$dbTable];
$resultRecordId = $this->_save($tableObject, $recordData, $dbIdColumn, $recordId, $isUpdate);
if ($isUpdate == false)
{
$xml->addChild($idColumn, $resultRecordId);
$xmlData = $this->_parseXmlData($xml);
}
if ($resultRecordId == -1 || $resultRecordId === true)
{
$resultRecordId = $recordId;
}
$tableNames = array_flip($tableNames);
unset($tableNames[$dbTable]);
$tableNames = array_flip($tableNames);
if($isUpdate && $resultRecordId === false) // cannot proceed if the $resultRecordId is not found and we're currently in update operation
{
throw new Exception('Record ID does not exist in the database (column: ' . $dbTable . '.' . $dbIdColumn . ', record ID: ' . $recordId . ')');
}
// save sub tables
foreach ($tableNames as $name)
{
$tableObject = $dataObjects[$name];
$recordData = $xmlData[$name];
$t_id = $this->_save($tableObject, $recordData, $dbIdColumn, $resultRecordId, $isUpdate);
if ($isUpdate == true && $t_id == false)
{
$this->_save($tableObject, $recordData, $dbIdColumn, $resultRecordId, false);
}
}
return $resultRecordId;
}
/**
* Generate the WHERE clause of a query.
*
* Generate the WHERE clause of an SQL query depending the parameters
* passed by the client.
*
* @param array $data Must contain the "where_parts" value.
* @param bool $p_appendWhereClause (Optional) Whether there is already a WHERE clause
* and this is a supplementary one.
*
* @return string Returns the generated WHERE clause.
*
*/
protected function _generateWhereClause($data, $p_appendWhereClause = false)
{
$whereClause = '';
$conditionsGroupArray = array();
if(is_array($data) && isset($data['where_parts']))
{
$whereClause = ' WHERE ((';
if($p_appendWhereClause)
{
$whereClause = ' AND ((';
}
foreach($data['where_parts'] as $dataArray)
{
$conditionsArray = array();
foreach($dataArray as $column => $value)
{
$conditionsArray[] = $column . " = '" . xtc_db_input($value) . "'";
}
$conditionsGroupArray[] = implode(' AND ', $conditionsArray);
}
$whereClause .= implode(') OR (', $conditionsGroupArray);
$whereClause .= ')) ';
}
return $whereClause;
}
/**
* Generates the LIMIT section of the query.
*
* @param array $p_arguments Contains the limit and offset values.
*
* @return string Returns the LIMIT query part.
* @throws InvalidArgumentException When limit or offset values are invalid.
*/
protected function _generateLimitClause($p_arguments)
{
if(!is_array($p_arguments))
{
throw new InvalidArgumentException('Invalid query arguments provided: ' . print_r($p_arguments, true));
}
if(!isset($p_arguments['limit']))
{
return ''; // No limit parameter was provided.
}
$limitClause = '';
// Validate limit value.
if(!is_numeric($p_arguments['limit']))
{
throw new InvalidArgumentException('Invalid limit value given: ' . $p_arguments['limit']);
}
$limit = (int) $p_arguments['limit'];
// Validate offset value.
if(isset($p_arguments['offset']) && !is_numeric($p_arguments['offset']))
{
throw new InvalidArgumentException('Invalid offset value given: ' . $p_arguments['offset']);
}
$offset = (int) (isset($p_arguments['offset'])) ? $p_arguments['offset'] : 0;
// Create the query part string only if limit is above zero.
if($limit > 0)
{
$limitClause = ' LIMIT ' . $offset . ', ' . $limit;
}
return $limitClause;
}
/**
* Get an array with the XML data.
*
* @param SimpleXMLElement $xml XML to be parsed.
* @param string $p_parentTable (Optional) The DB table that is referenced by this XML.
*
* @return array Returns an array with the XML data.
*/
protected function _parseXmlData(SimpleXMLElement $xml, $p_parentTable = '')
{
$result = array();
foreach($xml->children() as $nodeName=>$nodeValuesArray)
{
$nodeName = $p_parentTable . $nodeName;
if(isset($this->tableMapperArray[$nodeName]) == false || isset($this->mapperArray[$nodeName]) == false)
{
if(in_array($nodeName, array('special', 'categories', 'cross_selling_products', 'status_history', 'additional_images')) == false)
{
continue;
}
}
if(isset($this->tableMapperArray[$nodeName]))
{
$table = $this->tableMapperArray[$nodeName];
}
if(isset($this->mapperArray[$nodeName]))
{
$column = $this->mapperArray[$nodeName];
}
switch ($nodeName)
{
case 'special':
case 'status_history':
$result = array_merge($result, $this->_parseXmlData($xml->{$nodeName}, $nodeName . '/'));
break;
case 'customer_group_permission':
$result[$table][$column . $nodeValuesArray['customer_group_id']] = (string)$nodeValuesArray[0];
break;
case 'quantity_unit_id':
$result[$table]['products_id'] = true;
$result[$table][$this->mapperArray[$nodeName]] = (string)$nodeValuesArray[0];
break;
case 'cross_selling_products':
$updateXsellingProducts = array();
$deleteXsellingProducts = array();
foreach ($nodeValuesArray->children() as $xsellProductNode)
{
$xsellUpdate = array();
$xsellDelete = array();
foreach ($xsellProductNode as $leafName => $leafValue)
{
if (isset($xsellProductNode['action']) && $xsellProductNode['action'] == 'delete')
{
$xsellDelete[$leafName] = (string)$leafValue;
continue;
}
else
{
$xsellUpdate[$leafName] = (string)$leafValue;
}
}
if(count($xsellUpdate))
{
$updateXsellingProducts[] = $xsellUpdate;
}
if(count($xsellDelete))
{
$deleteXsellingProducts[] = $xsellDelete;
}
}
$result[$this->tableMapperArray['cross_selling_products/cross_selling_product/product_id']]['xsell_updates'] = $updateXsellingProducts;
$result[$this->tableMapperArray['cross_selling_products/cross_selling_product/product_id']]['xsell_deletion'] = $deleteXsellingProducts;
break;
case 'categories':
$categories = array();
$deleteCategories = array();
foreach ($nodeValuesArray->children() as $categoryNode)
{
foreach ($categoryNode->children() as $leafName => $leafValue)
{
if ($leafName == 'category_id')
{
if (isset($categoryNode['action']) && $categoryNode['action'] == 'delete')
{
$deleteCategories[] = $leafValue;
}
else
{
$categories[] = $leafValue;
}
}
}
}
if (!empty($categories))
{
$result[$this->tableMapperArray['categories/category/category_id']]['categories_id'] = implode(',', $categories);
$result[$this->tableMapperArray['categories/category/category_id']]['delete_categories_id'] = implode(',', $deleteCategories);
}
break;
case 'personal_offer':
foreach($nodeValuesArray->children() as $personalOfferNodeName => $personalOfferNodeValuesArray)
{
$count_index = 0;
switch($personalOfferNodeName)
{
case 'price':
if(isset($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']]))
{
$count_index = count($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']]) - 1;
if(isset($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']][$count_index]['price']))
{
$count_index++;
}
}
$result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']][$count_index]['personal_offer'] = (string)$personalOfferNodeValuesArray[0];
break;
case 'quantity':
if(isset($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']]))
{
$count_index = count($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']]) - 1;
if(isset($result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']][$count_index]['quantity']))
{
$count_index++;
}
}
$result[TABLE_PERSONAL_OFFERS_BY . $nodeValuesArray['customer_group_id']][$count_index]['quantity'] = (string)$personalOfferNodeValuesArray[0];
break;
}
}
break;
case 'personal_offers':
$result = array_merge($result, $this->_parseXmlData($xml->{$nodeName}, ''));
break;
case 'property_values':
if (!isset($result['products_properties_combis_values']) || !is_array($result['products_properties_combis_values']))
{
$result['products_properties_combis_values'] = array();
}
for ($i = 0; $i < count($nodeValuesArray); $i++)
{
$result['products_properties_combis_values'][] = array('properties_values_id' => (int) $nodeValuesArray->property_value[$i]->property_value_id,
'products_properties_combis_id' => (int) $xml->product_combi_id);
}
break;
case 'additional_images':
$result['image_data'] = array();
foreach($nodeValuesArray->children() as $imageNode)
{
$result['image_data'][] = $this->_parseXmlData($imageNode, 'additional_images/image/');
}
break;
case 'additional_images/image/image_url':
break;
default:
if (isset($this->mapperArray[$nodeName]))
{
if ((isset($nodeValuesArray['language_id']) || isset($nodeValuesArray['language_iso']))
&& in_array($table, $this->languageDependentMapperArray))
{
if (!isset($nodeValuesArray['language_id']))
{
$languageId = $this->_resolveLanguageIso($nodeValuesArray['language_iso']);
}
else
{
$languageId = $nodeValuesArray['language_id'];
}
$result[$table][(string)$languageId][$column] = (string)$nodeValuesArray[0];
}
else
{
$result[$table][$this->mapperArray[$nodeName]] = (string)$nodeValuesArray[0];
}
}
break;
}
}
return $result;
}
/**
* Implements the upload procedure.
*
* IMPORTANT! This method does not always return a value(!!!)
*
* @param SimpleXMLElement $xml XML object to be used by the operation.
* @param array $responseData Array with the response data (used by reference).
*
* @return mixed Returns the id of the record that was affected buy the operation.
*/
protected function _upload(SimpleXMLElement $xml, array &$responseData)
{
$recordType = $this->singularName;
$externalId = (string)$xml->{'external_' . $recordType . '_id'};
$recordId = (string)$xml->{$recordType . '_id'};
$isDelete = ($xml['action'] == 'delete'); // Whether current operation is delete.
if(!empty($recordId) && (!is_numeric($recordId) || (int)$recordId != (double)$recordId))
{
throw new InvalidArgumentException('Request XML is invalid: Invalid ' . $recordType . '_id value: ' . $recordId);
}
if(empty($externalId) && empty($recordId) && $isDelete === false) // Missing External ID Error
{
$responseData[] = array(
'external_' . $recordType . '_id' => '',
$recordType . '_id' => $recordId,
'success' => '0',
'errormessage' => 'missing external_' . $recordType . '_id',
'action_performed' => 'error'
);
}
else if($isDelete) // Delete Record
{
$responseData[] = array(
'external_' . $recordType . '_id' => $externalId,
$recordType . '_id' => $recordId,
'errormessage' => '',
'action_performed' => 'delete'
);
$result = $this->_deleteObject($xml);
$responseData[count($responseData) - 1]['success'] = (int)$result;
}
else // Insert/Update Record
{
$responseData[] = array(
'external_' . $recordType . '_id' => $externalId,
'errormessage' => '',
'action_performed' => (empty($recordId) ? 'create' : 'update')
);
// Execute the save operation and store the record id to response data.
$recordId = $this->_saveObject($xml);
$responseData[count($responseData) - 1][$recordType . '_id'] = $recordId;
// Set operation result to response data.
$result = (boolean)$recordId;
$responseData[count($responseData) - 1]['success'] = (int)$result;
}
return $recordId;
}
/**
* Remove all the children of the given xml element.-
*
* @param SimpleXMLElement $xml XML object to be edited.
* @param bool $p_delete Whether to delete the children or save them.
*
* @returns bool Returns the operation result.
*/
protected function _uploadChildren(SimpleXMLElement $xml, $p_delete)
{
if ($p_delete)
{
$result = $this->delete_children($xml);
}
else
{
$result = $this->save_children($xml);
}
return $result;
}
/**
* Perform an action upon the database.
*
* @param mixed $p_sqlObject Could be a query or a database handler object.
* @param mixed(bool|string) $p_action (Optional) The action to be performed, could be either "create", "update", "delete".
* @param bool $p_replace (Optional) Whether to replace an existing record on the database.
*
* @return bool|int|resource Returns the database operation result.
*/
protected function _performDbAction(&$p_sqlObject, $p_action = false, $p_replace = false)
{
$result = true;
if (is_string($p_sqlObject))
{
$result = xtc_db_query($p_sqlObject);
}
else
{
switch ($p_action)
{
case 'create':
case 'update':
$result = $p_sqlObject->save_body_data($p_replace);
$result = $result === 0 ? -1 : $result;
break;
case 'delete':
$result = $p_sqlObject->delete();
break;
default:
$result = false;
break;
}
}
return $result;
}
/**
* Generates the XML object for additional images in the response
*
* @param $p_responseArray
*
* @return SimpleXMLElement
*/
protected function _generateAdditionalImagesResponseXml($p_responseArray)
{
$responseXmlContent = $this->gxmlHelper->getBlankXml();
$responseXml = simplexml_load_string($responseXmlContent);
if(isset($p_responseArray['external_image_id']))
{
$responseXml->addChild('external_image_id', $p_responseArray['external_image_id']);
}
$responseXml->addChild('image_id', $p_responseArray['image_id']);
$responseXml->addChild('success', $p_responseArray['success']);
$responseXml->addChild('errormessage', $p_responseArray['errormessage']);
$responseXml->addChild('action_performed', $p_responseArray['action_performed']);
return $responseXml;
}
/**
* Add shipping times node to current response XML object.
*/
protected function _addShippingTimes()
{
$shippingTimes = $this->responseXml->addChild('shipping_times');
$query = "SELECT
shipping_status_id,
language_id,
shipping_status_name,
number_of_days,
shipping_quantity
FROM " . TABLE_SHIPPING_STATUS . "
ORDER BY
shipping_status_id,
language_id";
$result = xtc_db_query($query);
$shippingStatusId = 0;
while($resultArray = xtc_db_fetch_array($result))
{
if($resultArray['shipping_status_id'] != $shippingStatusId)
{
$shippingTime = $shippingTimes->addChild('shipping_time');
$shippingTime->addChild('shipping_time_id', $resultArray['shipping_status_id']);
$shippingTime->addChild('number_of_days', $resultArray['number_of_days']);
$shippingTime->addChild('quantity', $resultArray['shipping_quantity']);
}
$name = $shippingTime->addChild('name', $this->wrapValue($resultArray['shipping_status_name']));
$name->addAttribute('language_id', $resultArray['language_id']);
$name->addAttribute('language_iso', $this->languageArray[$resultArray['language_id']]['iso']);
$shippingStatusId = $resultArray['shipping_status_id'];
}
}
/**
* Add tax classes node to current response XML object.
*/
protected function _addTaxClasses()
{
$this->_loadTaxes();
$taxClasses = $this->responseXml->addChild('tax_classes');
foreach($this->taxArray as $t_tax_class)
{
$taxClass = $taxClasses->addChild('tax_class');
$taxClass->addChild('tax_class_id', $t_tax_class['tax_class_id']);
$taxClass->addChild('title', $this->wrapValue($t_tax_class['title']));
$description = $taxClass->addChild('description', $this->wrapValue($t_tax_class['description']));
$description->addAttribute('type', 2);
$taxClass->addChild('tax_rate', $t_tax_class['tax_rate']);
$taxClass->addChild('date_added', $t_tax_class['date_added']);
$taxClass->addChild('last_modified', $t_tax_class['last_modified']);
}
return $taxClasses;
}
/**
* Add quantity units node to current response XML object.
*/
protected function _addQuantityUnits()
{
$quantityUnits = $this->responseXml->addChild('quantity_units');
$query = "SELECT
quantity_unit_id,
language_id,
unit_name
FROM quantity_unit_description
ORDER BY
quantity_unit_id,
language_id";
$result = xtc_db_query($query);
$quantityUnitId = 0;
while($resultArray = xtc_db_fetch_array($result))
{
if($resultArray['quantity_unit_id'] != $quantityUnitId)
{
$quantityUnit = $quantityUnits->addChild('quantity_unit');
$quantityUnit->addChild('quantity_unit_id', $resultArray['quantity_unit_id']);
}
$name = $quantityUnit->addChild('name', $this->wrapValue($resultArray['unit_name']));
$name->addAttribute('language_id', $resultArray['language_id']);
$name->addAttribute('language_iso', $this->languageArray[$resultArray['language_id']]['iso']);
$quantityUnitId = $resultArray['quantity_unit_id'];
}
}
/**
* Add base price units node to current response XML object.
*/
protected function _addBasePriceUnits()
{
$basePriceUnits = $this->responseXml->addChild('base_price_units');
$query = "SELECT
products_vpe_id,
language_id,
products_vpe_name
FROM " . TABLE_PRODUCTS_VPE . "
ORDER BY
products_vpe_id,
language_id";
$result = xtc_db_query($query);
$productsVpeId = 0;
while($resultArray = xtc_db_fetch_array($result))
{
if($resultArray['products_vpe_id'] != $productsVpeId)
{
$basePriceUnit = $basePriceUnits->addChild('base_price_unit');
$basePriceUnit->addChild('base_price_unit_id', $resultArray['products_vpe_id']);
}
$name = $basePriceUnit->addChild('name', $this->wrapValue($resultArray['products_vpe_name']));
$name->addAttribute('language_id', $resultArray['language_id']);
$name->addAttribute('language_iso', $this->languageArray[$resultArray['language_id']]['iso']);
$productsVpeId = $resultArray['products_vpe_id'];
}
}
/**
* Add customer groups node to current response XML object.
*/
protected function _addCustomerGroups()
{
$customerGroups = $this->responseXml->addChild('customer_groups');
$query = "SELECT
customers_status_id,
language_id,
customers_status_name,
customers_status_show_price_tax
FROM " . TABLE_CUSTOMERS_STATUS . "
ORDER BY
customers_status_id,
language_id";
$result = xtc_db_query($query);
$customersStatusId = '';
while($resultArray = xtc_db_fetch_array($result))
{
if($resultArray['customers_status_id'] != $customersStatusId)
{
$customerGroup = $customerGroups->addChild('customer_group');
$customerGroup->addChild('customer_status_id', $resultArray['customers_status_id']);
$customerGroup->addChild('include_taxes', $resultArray['customers_status_show_price_tax']);
}
$name = $customerGroup->addChild('name', $this->wrapValue($resultArray['customers_status_name']));
$name->addAttribute('language_id', $resultArray['language_id']);
$name->addAttribute('language_iso', $this->languageArray[$resultArray['language_id']]['iso']);
$customersStatusId = $resultArray['customers_status_id'];
}
}
/**
* Add languages node to current response XML object.
*/
protected function _addLanguages()
{
$languages = $this->responseXml->addChild('languages');
foreach ($this->languageArray as $languageId => $languageData)
{
$language = $languages->addChild('language');
$language->addChild('language_id', $languageId);
$language->addChild('name', $this->wrapValue($languageData['language_name']));
$language->addChild('iso', $languageData['iso']);
$language->addChild('charset', $languageData['charset']);
}
}
/**
* Add order status node to current response XML object.
*/
protected function _addOrderStatus()
{
$orderStatuses = $this->responseXml->addChild('order_statuses');
$query = '
SELECT
orders_status_id,
language_id,
orders_status_name
FROM ' . TABLE_ORDERS_STATUS. '
ORDER BY
orders_status_id, language_id';
$result = xtc_db_query($query);
$orderStatusId = '';
while($resultArray = xtc_db_fetch_array($result))
{
if($resultArray['orders_status_id'] != $orderStatusId)
{
$orderStatus = $orderStatuses->addChild('order_status');
$orderStatus->addChild('orders_status_id', $resultArray['orders_status_id']);
}
$name = $orderStatus->addChild('name', $this->wrapValue($resultArray['orders_status_name']));
$name->addAttribute('language_id', $resultArray['language_id']);
$name->addAttribute('language_iso', $this->languageArray[$resultArray['language_id']]['iso']);
$orderStatusId = $resultArray['orders_status_id'];
}
}
/**
* Load all language records from the database.
*
* This method will store all the language records from the database into an
* array for future reference.
*/
protected function _loadLanguages()
{
if (empty($this->languageArray))
{
$this->languageArray = array();
$query = "SELECT
languages_id,
name,
code,
language_charset
FROM " . TABLE_LANGUAGES. "
ORDER BY
languages_id";
$result = xtc_db_query($query);
while($resultArray = xtc_db_fetch_array($result))
{
$this->languageArray[$resultArray['languages_id']] = array();
$this->languageArray[$resultArray['languages_id']]['language_name'] = $resultArray['name'];
$this->languageArray[$resultArray['languages_id']]['iso'] = $resultArray['code'];
$this->languageArray[$resultArray['languages_id']]['charset'] = $resultArray['language_charset'];
}
}
}
/**
* Load all tax related records from database.
*
* This method will load all tax related records from the database and store them
* into a private array for future reference.
*/
protected function _loadTaxes()
{
if (empty($this->taxArray))
{
$this->taxArray = array();
$t_sql = "SELECT
tax_class.tax_class_id,
tax_class.tax_class_title,
tax_rates.tax_rate,
tax_class.tax_class_description,
tax_class.last_modified,
tax_class.date_added
FROM " . TABLE_TAX_CLASS . " tax_class ," . TABLE_TAX_RATES . " tax_rates
WHERE
tax_class.tax_class_id = tax_rates.tax_class_id AND
tax_rates.tax_zone_id = " . (int)xtc_get_geo_zone_code(STORE_COUNTRY) . "
ORDER BY
tax_class.tax_class_id";
$t_result = xtc_db_query($t_sql);
while($t_result_array = xtc_db_fetch_array($t_result))
{
$this->taxArray[$t_result_array['tax_class_id']] = array();
$this->taxArray[$t_result_array['tax_class_id']]['tax_class_id'] = $t_result_array['tax_class_id'];
$this->taxArray[$t_result_array['tax_class_id']]['title'] = $t_result_array['tax_class_title'];
$this->taxArray[$t_result_array['tax_class_id']]['description'] = $t_result_array['tax_class_description'];
$this->taxArray[$t_result_array['tax_class_id']]['tax_rate'] = $t_result_array['tax_rate'];
$this->taxArray[$t_result_array['tax_class_id']]['date_added'] = $t_result_array['date_added'];
$this->taxArray[$t_result_array['tax_class_id']]['last_modified'] = $t_result_array['last_modified'];
}
}
}
/**
* Find the language id that matches the given language ISO.
*
* @param string $p_languageIso ISO string that is going to be used for the search.
*
* @return numeric Returns the language id value.
*/
protected function _resolveLanguageIso($p_languageIso)
{
foreach ($this->languageArray as $languageId => $languageData)
{
if ($languageData['iso'] == $p_languageIso)
{
return $languageId;
}
}
return false;
}
/**
* Add a general purpose node to the response XML object.
*
* This is a general purpose method that will call the sub-methods who will
* eventually include the XML nodes to the response XML object.
*
* @param array $nodeTypes Contains the node types to be added ("languages", "customer_groups",
* "shipping_times", "tax_classes", "base_price_units", "quantity_units",
* "order_status").
*/
protected function _includeNode(array $nodeTypes)
{
foreach($nodeTypes as $type)
{
switch($type)
{
case 'languages':
$this->_addLanguages();
break;
case 'customer_groups':
$this->_addCustomerGroups();
break;
case 'shipping_times':
$this->_addShippingTimes();
break;
case 'tax_classes':
$this->_addTaxClasses();
break;
case 'base_price_units':
$this->_addBasePriceUnits();
break;
case 'quantity_units':
$this->_addQuantityUnits();
break;
case 'order_status':
$this->_addOrderStatus();
break;
}
}
}
/**
* Generate an SQL query string from the given parameters.
*
* This method will generate an array that contains the query sections that
* correspond to the required $types array.
*
* @param SimpleXMLElement $parametersXml Parameters XML object provided by the API client.
* @param array $types Contains the query values that will be included into the result.
*
* @return array Returns an array with the query string values.
*/
protected function _generateSqlStrings(SimpleXMLElement $parametersXml, array $types)
{
$queryStrings = array();
foreach($types AS $type)
{
switch($type)
{
case 'limit':
if(isset($parametersXml->limit))
{
if(!is_numeric((string)$parametersXml->limit)) // convert to string in order to check if this is really a numeric value
{
throw new InvalidArgumentException('Invalid limit value provided: ' . $parametersXml->limit);
}
if((int)$parametersXml->limit > 0)
{
$queryStrings['limit'] = (int) $parametersXml->limit;
}
if(isset($parametersXml->offset))
{
if(!is_numeric((string)$parametersXml->offset)) // convert to string in order to check if this is really a numeric value
{
throw new InvalidArgumentException('Invalid offset value provided: ' . $parametersXml->offset);
}
$queryStrings['offset'] = (int) $parametersXml->offset;
}
}
break;
case 'where':
if(isset($parametersXml->{$this->_getPluralName()}) && isset($parametersXml->{$this->_getPluralName()}->{$this->_getSingularName()}))
{
$singularNotes = $parametersXml->{$this->_getPluralName()}->{$this->_getSingularName()};
for($i=0; $i<count($singularNotes); $i++)
{
$mapperKeyArray = $this->_generatePathArray($singularNotes[$i]);
for($j=0; $j<count($mapperKeyArray); $j++)
{
if(isset($this->mapperArray[$mapperKeyArray[$j]]) && $this->mapperArray[$mapperKeyArray[$j]] != '')
{
$node = $singularNotes[$i]->xpath($mapperKeyArray[$j]);
$queryStrings['where_parts'][$i][$this->tableMapperArray[$mapperKeyArray[$j]]
. '.' . $this->mapperArray[$mapperKeyArray[$j]]] = (string)$node[0];
}
}
}
}
break;
}
}
return $queryStrings;
}
/**
* Generate a path array
*
* @param SimpleXMLElement $xml XML object to be used for the calculation of the path.
* @param string $p_path (Optional)
*
* @return array Returns the generated array.
*/
protected function _generatePathArray(SimpleXMLElement $xml, $p_path = '')
{
$pathArray = array();
foreach($xml->children() AS $childName=>$childNode)
{
$subChildCount = count($childNode->children());
if($subChildCount > 0)
{
$pathArray = array_merge($pathArray, $this->_generatePathArray($childNode, $p_path . $childName . '/'));
}
else
{
$pathArray[] = $p_path . $childName;
}
}
return $pathArray;
}
}