* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision: 7708 $
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
abstract class AdminTabCore
{
/** @var integer Tab id */
public $id = -1;
/** @var string Associated table name */
public $table;
/** @var string Object identifier inside the associated table */
protected $identifier = false;
/** @var string Tab name */
public $name;
/** @var string Security token */
public $token;
/** @var boolean Automatically join language table if true */
public $lang = false;
/** @var boolean Tab Automatically displays edit/delete icons if true */
public $edit = false;
/** @var boolean Tab Automatically displays view icon if true */
public $view = false;
/** @var boolean Tab Automatically displays delete icon if true */
public $delete = false;
/** @var boolean Table records are not deleted but marked as deleted */
public $deleted = false;
/** @var boolean Tab Automatically displays duplicate icon if true */
public $duplicate = false;
/** @var boolean Content line is clickable if true */
public $noLink = false;
/** @var boolean select other required fields */
public $requiredDatabase = false;
/** @var boolean Tab Automatically displays '$color' as background color on listing if true */
public $colorOnBackground = false;
/** @var string Add fields into data query to display list */
protected $_select;
/** @var string Join tables into data query to display list */
protected $_join;
/** @var string Add conditions into data query to display list */
protected $_where;
/** @var string Group rows into data query to display list */
protected $_group;
/** @var string Having rows into data query to display list */
protected $_having;
/** @var array Name and directory where class image are located */
public $fieldImageSettings = array();
/** @var string Image type */
public $imageType = 'jpg';
/** @var array Fields to display in list */
public $fieldsDisplay = array();
/** @var array Cache for query results */
protected $_list = array();
/** @var integer Number of results in list */
protected $_listTotal = 0;
/** @var array WHERE clause determined by filter fields */
protected $_filter;
/** @var array Temporary SQL table WHERE clause determinated by filter fields */
protected $_tmpTableFilter = '';
/** @var array Number of results in list per page (used in select field) */
protected $_pagination = array(20, 50, 100, 300);
/** @var string ORDER BY clause determined by field/arrows in list header */
protected $_orderBy;
/** @var string Default ORDER BY clause when $_orderBy is not defined */
protected $_defaultOrderBy = false;
/** @var string Order way (ASC, DESC) determined by arrows in list header */
protected $_orderWay;
/** @var integer Max image size for upload */
protected $maxImageSize = 2000000;
/** @var array Errors displayed after post processing */
public $_errors = array();
/** @var array Confirmations displayed after post processing */
protected $_conf;
/** @var object Object corresponding to the tab */
protected $_object = false;
/** @var array tabAccess */
public $tabAccess;
/** @var string specificConfirmDelete */
public $specificConfirmDelete = NULL;
protected $identifiersDnd = array('id_product' => 'id_product', 'id_category' => 'id_category_to_move','id_cms_category' => 'id_cms_category_to_move', 'id_cms' => 'id_cms');
/** @var bool Redirect or not ater a creation */
protected $_redirect = true;
protected $_languages = NULL;
protected $_defaultFormLanguage = NULL;
protected $_includeObj = array();
protected $_includeVars = false;
protected $_includeContainer = true;
public $ajax = false;
public static $tabParenting = array(
'AdminProducts' => 'AdminCatalog',
'AdminCategories' => 'AdminCatalog',
'AdminCMS' => 'AdminCMSContent',
'AdminCMSCategories' => 'AdminCMSContent',
'AdminOrdersStates' => 'AdminStatuses',
'AdminAttributeGenerator' => 'AdminProducts',
'AdminAttributes' => 'AdminAttributesGroups',
'AdminFeaturesValues' => 'AdminFeatures',
'AdminReturnStates' => 'AdminStatuses',
'AdminStatsTab' => 'AdminStats'
);
public function __construct()
{
global $cookie;
$this->id = Tab::getCurrentTabId();
$this->_conf = array(
1 => $this->l('Deletion successful'), 2 => $this->l('Selection successfully deleted'),
3 => $this->l('Creation successful'), 4 => $this->l('Update successful'),
5 => $this->l('Status update successful'), 6 => $this->l('Settings update successful'),
7 => $this->l('Image successfully deleted'), 8 => $this->l('Module downloaded successfully'),
9 => $this->l('Thumbnails successfully regenerated'), 10 => $this->l('Message sent to the customer'),
11 => $this->l('Comment added'), 12 => $this->l('Module installed successfully'),
13 => $this->l('Module uninstalled successfully'), 14 => $this->l('Language successfully copied'),
15 => $this->l('Translations successfully added'), 16 => $this->l('Module transplanted successfully to hook'),
17 => $this->l('Module removed successfully from hook'), 18 => $this->l('Upload successful'),
19 => $this->l('Duplication completed successfully'), 20 => $this->l('Translation added successfully but the language has not been created'),
21 => $this->l('Module reset successfully'), 22 => $this->l('Module deleted successfully'),
23 => $this->l('Localization pack imported successfully'), 24 => $this->l('Refund Successful'),
25 => $this->l('Images successfully moved'));
if (!$this->identifier) $this->identifier = 'id_'.$this->table;
if (!$this->_defaultOrderBy) $this->_defaultOrderBy = $this->identifier;
$className = get_class($this);
if ($className == 'AdminCategories' OR $className == 'AdminProducts')
$className = 'AdminCatalog';
$this->token = Tools::getAdminToken($className.(int)$this->id.(int)$cookie->id_employee);
}
/**
* use translations files to replace english expression.
*
* @param mixed $string term or expression in english
* @param string $class
* @param boolan $addslashes if set to true, the return value will pass through addslashes(). Otherwise, stripslashes().
* @param boolean $htmlentities if set to true(default), the return value will pass through htmlentities($string, ENT_QUOTES, 'utf-8')
* @return string the translation if available, or the english default text.
*/
protected function l($string, $class = 'AdminTab', $addslashes = FALSE, $htmlentities = TRUE)
{
// if the class is extended by a module, use modules/[module_name]/xx.php lang file
$currentClass = get_class($this);
if (Module::getModuleNameFromClass($currentClass))
{
$string = str_replace('\'', '\\\'', $string);
return Module::findTranslation(Module::$classInModule[$currentClass], $string, $currentClass);
}
global $_LANGADM;
if ($class == __CLASS__)
$class = 'AdminTab';
$key = md5(str_replace('\'', '\\\'', $string));
$str = (key_exists(get_class($this).$key, $_LANGADM)) ? $_LANGADM[get_class($this).$key] : ((key_exists($class.$key, $_LANGADM)) ? $_LANGADM[$class.$key] : $string);
$str = $htmlentities ? htmlentities($str, ENT_QUOTES, 'utf-8') : $str;
return str_replace('"', '"', ($addslashes ? addslashes($str) : stripslashes($str)));
}
/**
* ajaxDisplay is the default ajax return sytem
*
* @return void
*/
public function displayAjax()
{
}
/**
* Manage page display (form, list...)
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function display()
{
global $currentIndex, $cookie;
// Include other tab in current tab
if ($this->includeSubTab('display', array('submitAdd2', 'add', 'update', 'view'))){}
// Include current tab
elseif ((Tools::getValue('submitAdd'.$this->table) AND sizeof($this->_errors)) OR isset($_GET['add'.$this->table]))
{
if ($this->tabAccess['add'] === '1')
{
$this->displayForm();
if ($this->tabAccess['view'])
echo '
'.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).' ';
}
else
echo $this->l('You do not have permission to add here');
}
elseif (isset($_GET['update'.$this->table]))
{
if ($this->tabAccess['edit'] === '1' OR ($this->table == 'employee' AND $cookie->id_employee == Tools::getValue('id_employee')))
{
$this->displayForm();
if ($this->tabAccess['view'])
echo '
'.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).' ';
}
else
echo $this->l('You do not have permission to edit here');
}
elseif (isset($_GET['view'.$this->table]))
$this->{'view'.$this->table}();
else
{
$this->getList((int)($cookie->id_lang));
$this->displayList();
$this->displayOptionsList();
$this->displayRequiredFields();
$this->includeSubTab('display');
}
}
public function displayRequiredFields()
{
global $currentIndex;
if (!$this->tabAccess['add'] OR !$this->tabAccess['delete'] === '1' OR !$this->requiredDatabase)
return;
$rules = call_user_func_array(array($this->className, 'getValidationRules'), array($this->className));
$required_class_fields = array($this->identifier);
foreach ($rules['required'] AS $required)
$required_class_fields[] = $required;
echo '
';
}
public function includeSubTab($methodname, $actions = array())
{
if (!isset($this->_includeTab) OR !is_array($this->_includeTab))
return false;
$key = 0;
$inc = false;
foreach ($this->_includeTab as $subtab => $extraVars)
{
/* New tab loading */
$classname = 'Admin'.$subtab;
if ($module = Db::getInstance()->getValue('SELECT `module` FROM `'._DB_PREFIX_.'tab` WHERE `class_name` = \''.pSQL($classname).'\'') AND file_exists(_PS_MODULE_DIR_.'/'.$module.'/'.$classname.'.php'))
include_once(_PS_MODULE_DIR_.'/'.$module.'/'.$classname.'.php');
elseif (file_exists(PS_ADMIN_DIR.'/tabs/'.$classname.'.php'))
include_once('tabs/'.$classname.'.php');
if (!isset($this->_includeObj[$key]))
$this->_includeObj[$key] = new $classname;
$adminTab = $this->_includeObj[$key];
$adminTab->token = $this->token;
/* Extra variables addition */
if (!empty($extraVars) AND is_array($extraVars))
foreach ($extraVars AS $varKey => $varValue)
$adminTab->$varKey = $varValue;
/* Actions management */
foreach ($actions as $action)
{
switch ($action)
{
case 'submitAdd1':
if (Tools::getValue('submitAdd'.$adminTab->table))
$ok_inc = true;
break;
case 'submitAdd2':
if (Tools::getValue('submitAdd'.$adminTab->table) AND sizeof($adminTab->_errors))
$ok_inc = true;
break;
case 'submitDel':
if (Tools::getValue('submitDel'.$adminTab->table))
$ok_inc = true;
break;
case 'submitFilter':
if (Tools::isSubmit('submitFilter'.$adminTab->table))
$ok_inc = true;
case 'submitReset':
if (Tools::isSubmit('submitReset'.$adminTab->table))
$ok_inc = true;
default:
if (isset($_GET[$action.$adminTab->table]))
$ok_inc = true;
}
}
$inc = false;
if ((isset($ok_inc) AND $ok_inc) OR !sizeof($actions))
{
if (!$adminTab->viewAccess())
{
echo Tools::displayError('Access denied');
return false;
}
if (!sizeof($actions))
if (($methodname == 'displayErrors' AND sizeof($adminTab->_errors)) OR $methodname != 'displayErrors')
echo (isset($this->_includeTabTitle[$key]) ? '
'.$this->_includeTabTitle[$key].'
' : '');
if ($adminTab->_includeVars)
foreach ($adminTab->_includeVars AS $var => $value)
$adminTab->$var = $this->$value;
$adminTab->$methodname();
$inc = true;
}
$key++;
}
return $inc;
}
/**
* Manage page display (form, list...)
*
* @param string $className Allow to validate a different class than the current one
*/
public function validateRules($className = false)
{
if (!$className)
$className = $this->className;
/* Class specific validation rules */
$rules = call_user_func(array($className, 'getValidationRules'), $className);
if ((sizeof($rules['requiredLang']) OR sizeof($rules['sizeLang']) OR sizeof($rules['validateLang'])))
{
/* Language() instance determined by default language */
$defaultLanguage = new Language((int)(Configuration::get('PS_LANG_DEFAULT')));
/* All availables languages */
$languages = Language::getLanguages(false);
}
/* Checking for required fields */
foreach ($rules['required'] AS $field)
if (($value = Tools::getValue($field)) == false AND (string)$value != '0')
if (!Tools::getValue($this->identifier) OR ($field != 'passwd' AND $field != 'no-picture'))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is required');
/* Checking for multilingual required fields */
foreach ($rules['requiredLang'] AS $fieldLang)
if (($empty = Tools::getValue($fieldLang.'_'.$defaultLanguage->id)) === false OR $empty !== '0' AND empty($empty))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' '.$this->l('is required at least in').' '.$defaultLanguage->name;
/* Checking for maximum fields sizes */
foreach ($rules['size'] AS $field => $maxLength)
if (Tools::getValue($field) !== false AND Tools::strlen(Tools::getValue($field)) > $maxLength)
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is too long').' ('.$maxLength.' '.$this->l('chars max').')';
/* Checking for maximum multilingual fields size */
foreach ($rules['sizeLang'] AS $fieldLang => $maxLength)
foreach ($languages AS $language)
if (Tools::getValue($fieldLang.'_'.$language['id_lang']) !== false AND Tools::strlen(Tools::getValue($fieldLang.'_'.$language['id_lang'])) > $maxLength)
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' ('.$language['name'].') '.$this->l('is too long').' ('.$maxLength.' '.$this->l('chars max, html chars including').')';
/* Overload this method for custom checking */
$this->_childValidation();
/* Checking for fields validity */
foreach ($rules['validate'] AS $field => $function)
if (($value = Tools::getValue($field)) !== false AND ($field != 'passwd'))
if (!Validate::$function($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $field, $className).' '.$this->l('is invalid');
/* Checking for passwd_old validity */
if (($value = Tools::getValue('passwd')) != false)
{
if ($className == 'Employee' AND !Validate::isPasswdAdmin($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), 'passwd', $className).' '.$this->l('is invalid');
elseif ($className == 'Customer' AND !Validate::isPasswd($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), 'passwd', $className).' '.$this->l('is invalid');
}
/* Checking for multilingual fields validity */
foreach ($rules['validateLang'] AS $fieldLang => $function)
foreach ($languages AS $language)
if (($value = Tools::getValue($fieldLang.'_'.$language['id_lang'])) !== false AND !empty($value))
if (!Validate::$function($value))
$this->_errors[] = $this->l('the field').' '.call_user_func(array($className, 'displayFieldName'), $fieldLang, $className).' ('.$language['name'].') '.$this->l('is invalid');
}
/**
* Overload this method for custom checking
*/
protected function _childValidation() { }
/**
* Overload this method for custom checking
*
* @param integer $id Object id used for deleting images
* TODO This function will soon be deprecated. Use ObjectModel->deleteImage instead.
*/
public function deleteImage($id)
{
$dir = null;
/* Deleting object images and thumbnails (cache) */
if (key_exists('dir', $this->fieldImageSettings))
{
$dir = $this->fieldImageSettings['dir'].'/';
if (file_exists(_PS_IMG_DIR_.$dir.$id.'.'.$this->imageType) AND !unlink(_PS_IMG_DIR_.$dir.$id.'.'.$this->imageType))
return false;
}
if (file_exists(_PS_TMP_IMG_DIR_.$this->table.'_'.$id.'.'.$this->imageType) AND !unlink(_PS_TMP_IMG_DIR_.$this->table.'_'.$id.'.'.$this->imageType))
return false;
if (file_exists(_PS_TMP_IMG_DIR_.$this->table.'_mini_'.$id.'.'.$this->imageType) AND !unlink(_PS_TMP_IMG_DIR_.$this->table.'_mini_'.$id.'.'.$this->imageType))
return false;
$types = ImageType::getImagesTypes();
foreach ($types AS $imageType)
if (file_exists(_PS_IMG_DIR_.$dir.$id.'-'.stripslashes($imageType['name']).'.'.$this->imageType) AND !unlink(_PS_IMG_DIR_.$dir.$id.'-'.stripslashes($imageType['name']).'.'.$this->imageType))
return false;
return true;
}
/**
* ajaxPreProcess is a method called in ajax-tab.php before displayConf().
*
* @return void
*/
public function ajaxPreProcess()
{
}
/**
* ajaxProcess is the default handle method for request with ajax-tab.php
*
* @return void
*/
public function ajaxProcess()
{
}
/**
* Manage page processing
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function postProcess()
{
global $currentIndex, $cookie;
if (!isset($this->table))
return false;
// set token
$token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
// Sub included tab postProcessing
$this->includeSubTab('postProcess', array('status', 'submitAdd1', 'submitDel', 'delete', 'submitFilter', 'submitReset'));
/* Delete object image */
if (isset($_GET['deleteImage']))
{
if (Validate::isLoadedObject($object = $this->loadObject()))
if (($object->deleteImage()))
Tools::redirectAdmin($currentIndex.'&add'.$this->table.'&'.$this->identifier.'='.Tools::getValue($this->identifier).'&conf=7&token='.$token);
$this->_errors[] = Tools::displayError('An error occurred during image deletion (cannot load object).');
}
/* Delete object */
elseif (isset($_GET['delete'.$this->table]))
{
if ($this->tabAccess['delete'] === '1')
{
if (Validate::isLoadedObject($object = $this->loadObject()) AND isset($this->fieldImageSettings))
{
// check if request at least one object with noZeroObject
if (isset($object->noZeroObject) AND sizeof(call_user_func(array($this->className, $object->noZeroObject))) <= 1)
$this->_errors[] = Tools::displayError('You need at least one object.').' '.$this->table.' '.Tools::displayError('You cannot delete all of the items.');
else
{
if ($this->deleted)
{
$object->deleteImage();
$object->deleted = 1;
if ($object->update())
Tools::redirectAdmin($currentIndex.'&conf=1&token='.$token);
}
elseif ($object->delete())
Tools::redirectAdmin($currentIndex.'&conf=1&token='.$token);
$this->_errors[] = Tools::displayError('An error occurred during deletion.');
}
}
else
$this->_errors[] = Tools::displayError('An error occurred while deleting object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
/* Change object statuts (active, inactive) */
elseif ((isset($_GET['status'.$this->table]) OR isset($_GET['status'])) AND Tools::getValue($this->identifier))
{
if ($this->tabAccess['edit'] === '1')
{
if (Validate::isLoadedObject($object = $this->loadObject()))
{
if ($object->toggleStatus())
Tools::redirectAdmin($currentIndex.'&conf=5'.((($id_category = (int)(Tools::getValue('id_category'))) AND Tools::getValue('id_product')) ? '&id_category='.$id_category : '').'&token='.$token);
else
$this->_errors[] = Tools::displayError('An error occurred while updating status.');
}
else
$this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
/* Move an object */
elseif (isset($_GET['position']))
{
if ($this->tabAccess['edit'] !== '1')
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
elseif (!Validate::isLoadedObject($object = $this->loadObject()))
$this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
elseif (!$object->updatePosition((int)(Tools::getValue('way')), (int)(Tools::getValue('position'))))
$this->_errors[] = Tools::displayError('Failed to update the position.');
else
Tools::redirectAdmin($currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.(($id_category = (int)(Tools::getValue($this->identifier))) ? ('&'.$this->identifier.'='.$id_category) : '').'&token='.$token);
Tools::redirectAdmin($currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.((($id_category = (int)(Tools::getValue('id_category'))) AND Tools::getValue('id_product')) ? '&id_category='.$id_category : '').'&token='.$token);
}
/* Delete multiple objects */
elseif (Tools::getValue('submitDel'.$this->table))
{
if ($this->tabAccess['delete'] === '1')
{
if (isset($_POST[$this->table.'Box']))
{
$object = new $this->className();
if (isset($object->noZeroObject) AND
// Check if all object will be deleted
(sizeof(call_user_func(array($this->className, $object->noZeroObject))) <= 1 OR sizeof($_POST[$this->table.'Box']) == sizeof(call_user_func(array($this->className, $object->noZeroObject)))))
$this->_errors[] = Tools::displayError('You need at least one object.').' '.$this->table.' '.Tools::displayError('You cannot delete all of the items.');
else
{
$result = true;
if ($this->deleted)
{
foreach(Tools::getValue($this->table.'Box') as $id)
{
$toDelete = new $this->className($id);
$toDelete->deleted = 1;
$result = $result AND $toDelete->update();
}
}
else
$result = $object->deleteSelection(Tools::getValue($this->table.'Box'));
if ($result)
Tools::redirectAdmin($currentIndex.'&conf=2&token='.$token);
$this->_errors[] = Tools::displayError('An error occurred while deleting selection.');
}
}
else
$this->_errors[] = Tools::displayError('You must select at least one element to delete.');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
/* Create or update an object */
elseif (Tools::getValue('submitAdd'.$this->table))
{
/* Checking fields validity */
$this->validateRules();
if (!sizeof($this->_errors))
{
$id = (int)(Tools::getValue($this->identifier));
/* Object update */
if (isset($id) AND !empty($id))
{
if ($this->tabAccess['edit'] === '1' OR ($this->table == 'employee' AND $cookie->id_employee == Tools::getValue('id_employee') AND Tools::isSubmit('updateemployee')))
{
$object = new $this->className($id);
if (Validate::isLoadedObject($object))
{
/* Specific to objects which must not be deleted */
if ($this->deleted AND $this->beforeDelete($object))
{
// Create new one with old objet values
$objectNew = new $this->className($object->id);
$objectNew->id = NULL;
$objectNew->date_add = '';
$objectNew->date_upd = '';
// Update old object to deleted
$object->deleted = 1;
$object->update();
// Update new object with post values
$this->copyFromPost($objectNew, $this->table);
$result = $objectNew->add();
if (Validate::isLoadedObject($objectNew))
$this->afterDelete($objectNew, $object->id);
}
else
{
$this->copyFromPost($object, $this->table);
$result = $object->update();
$this->afterUpdate($object);
}
if (!$result)
$this->_errors[] = Tools::displayError('An error occurred while updating object.').' '.$this->table.' ('.Db::getInstance()->getMsgError().')';
elseif ($this->postImage($object->id) AND !sizeof($this->_errors))
{
$parent_id = (int)(Tools::getValue('id_parent', 1));
// Specific back redirect
if ($back = Tools::getValue('back'))
Tools::redirectAdmin(urldecode($back).'&conf=4');
// Specific scene feature
if (Tools::getValue('stay_here') == 'on' || Tools::getValue('stay_here') == 'true' || Tools::getValue('stay_here') == '1')
Tools::redirectAdmin($currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&updatescene&token='.$token);
// Save and stay on same form
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
Tools::redirectAdmin($currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&update'.$this->table.'&token='.$token);
// Save and back to parent
if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
Tools::redirectAdmin($currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=4&token='.$token);
// Default behavior (save and back)
Tools::redirectAdmin($currentIndex.($parent_id ? '&'.$this->identifier.'='.$object->id : '').'&conf=4&token='.$token);
}
}
else
$this->_errors[] = Tools::displayError('An error occurred while updating object.').' '.$this->table.' '.Tools::displayError('(cannot load object)');
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
/* Object creation */
else
{
if ($this->tabAccess['add'] === '1')
{
$object = new $this->className();
$this->copyFromPost($object, $this->table);
if (!$object->add())
$this->_errors[] = Tools::displayError('An error occurred while creating object.').' '.$this->table.' ('.mysql_error().')';
elseif (($_POST[$this->identifier] = $object->id /* voluntary */) AND $this->postImage($object->id) AND !sizeof($this->_errors) AND $this->_redirect)
{
$parent_id = (int)(Tools::getValue('id_parent', 1));
$this->afterAdd($object);
// Save and stay on same form
if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
Tools::redirectAdmin($currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=3&update'.$this->table.'&token='.$token);
// Save and back to parent
if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
Tools::redirectAdmin($currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=3&token='.$token);
// Default behavior (save and back)
Tools::redirectAdmin($currentIndex.($parent_id ? '&'.$this->identifier.'='.$object->id : '').'&conf=3&token='.$token);
}
}
else
$this->_errors[] = Tools::displayError('You do not have permission to add here.');
}
}
$this->_errors = array_unique($this->_errors);
}
/* Cancel all filters for this tab */
elseif (isset($_POST['submitReset'.$this->table]))
{
$filters = $cookie->getFamily($this->table.'Filter_');
foreach ($filters AS $cookieKey => $filter)
if (strncmp($cookieKey, $this->table.'Filter_', 7 + Tools::strlen($this->table)) == 0)
{
$key = substr($cookieKey, 7 + Tools::strlen($this->table));
/* Table alias could be specified using a ! eg. alias!field */
$tmpTab = explode('!', $key);
$key = (count($tmpTab) > 1 ? $tmpTab[1] : $tmpTab[0]);
if (array_key_exists($key, $this->fieldsDisplay))
unset($cookie->$cookieKey);
}
if (isset($cookie->{'submitFilter'.$this->table}))
unset($cookie->{'submitFilter'.$this->table});
if (isset($cookie->{$this->table.'Orderby'}))
unset($cookie->{$this->table.'Orderby'});
if (isset($cookie->{$this->table.'Orderway'}))
unset($cookie->{$this->table.'Orderway'});
unset($_POST);
}
/* Submit options list */
elseif (Tools::getValue('submitOptions'.$this->table))
{
$this->updateOptions($token);
}
/* Manage list filtering */
elseif (Tools::isSubmit('submitFilter'.$this->table) OR $cookie->{'submitFilter'.$this->table} !== false)
{
$_POST = array_merge($cookie->getFamily($this->table.'Filter_'), (isset($_POST) ? $_POST : array()));
foreach ($_POST AS $key => $value)
{
/* Extracting filters from $_POST on key filter_ */
if ($value != NULL AND !strncmp($key, $this->table.'Filter_', 7 + Tools::strlen($this->table)))
{
$key = Tools::substr($key, 7 + Tools::strlen($this->table));
/* Table alias could be specified using a ! eg. alias!field */
$tmpTab = explode('!', $key);
$filter = count($tmpTab) > 1 ? $tmpTab[1] : $tmpTab[0];
if ($field = $this->filterToField($key, $filter))
{
$type = (array_key_exists('filter_type', $field) ? $field['filter_type'] : (array_key_exists('type', $field) ? $field['type'] : false));
if (($type == 'date' OR $type == 'datetime') AND is_string($value))
$value = unserialize($value);
$key = isset($tmpTab[1]) ? $tmpTab[0].'.`'.$tmpTab[1].'`' : '`'.$tmpTab[0].'`';
if (array_key_exists('tmpTableFilter', $field))
$sqlFilter = & $this->_tmpTableFilter;
elseif (array_key_exists('havingFilter', $field))
$sqlFilter = & $this->_filterHaving;
else
$sqlFilter = & $this->_filter;
/* Only for date filtering (from, to) */
if (is_array($value))
{
if (isset($value[0]) AND !empty($value[0]))
{
if (!Validate::isDate($value[0]))
$this->_errors[] = Tools::displayError('\'from:\' date format is invalid (YYYY-MM-DD)');
else
$sqlFilter .= ' AND '.pSQL($key).' >= \''.pSQL(Tools::dateFrom($value[0])).'\'';
}
if (isset($value[1]) AND !empty($value[1]))
{
if (!Validate::isDate($value[1]))
$this->_errors[] = Tools::displayError('\'to:\' date format is invalid (YYYY-MM-DD)');
else
$sqlFilter .= ' AND '.pSQL($key).' <= \''.pSQL(Tools::dateTo($value[1])).'\'';
}
}
else
{
$sqlFilter .= ' AND ';
if ($type == 'int' OR $type == 'bool')
$sqlFilter .= (($key == $this->identifier OR $key == '`'.$this->identifier.'`' OR $key == '`active`') ? 'a.' : '').pSQL($key).' = '.(int)($value).' ';
elseif ($type == 'decimal')
$sqlFilter .= (($key == $this->identifier OR $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' = '.(float)($value).' ';
elseif ($type == 'select')
$sqlFilter .= (($key == $this->identifier OR $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' = \''.pSQL($value).'\' ';
else
$sqlFilter .= (($key == $this->identifier OR $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' LIKE \'%'.pSQL($value).'%\' ';
}
}
}
}
}
elseif (Tools::isSubmit('submitFields') AND $this->requiredDatabase AND $this->tabAccess['add'] === '1' AND $this->tabAccess['delete'] === '1')
{
if (!is_array($fields = Tools::getValue('fieldsBox')))
$fields = array();
$object = new $this->className();
if (!$object->addFieldsRequiredDatabase($fields))
$this->_errors[] = Tools::displayError('Error in updating required fields');
else
Tools::redirectAdmin($currentIndex.'&conf=4&token='.$token);
}
}
protected function updateOptions($token)
{
global $currentIndex;
if ($this->tabAccess['edit'] === '1')
{
foreach ($this->_fieldsOptions as $key => $field)
{
if ($this->validateField(Tools::getValue($key), $field))
{
// check if a method updateOptionFieldName is available
$method_name = 'updateOption'.Tools::toCamelCase($key, true);
if (method_exists($this, $method_name))
$this->$method_name(Tools::getValue($key));
elseif ($field['type'] == 'textLang' OR $field['type'] == 'textareaLang')
{
$languages = Language::getLanguages(false);
$list = array();
foreach ($languages as $language)
{
$val = (isset($field['cast']) ? $field['cast'](Tools::getValue($key.'_'.$language['id_lang'])) : Tools::getValue($key.'_'.$language['id_lang']));
if (Validate::isCleanHtml($val))
$list[$language['id_lang']] = $val;
else
$this->_errors[] = Tools::displayError('Can not add configuration '.$key.' for lang '.Language::getIsoById((int)$language['id_lang']));
}
Configuration::updateValue($key, $list);
}
else
{
$val = (isset($field['cast']) ? $field['cast'](Tools::getValue($key)) : Tools::getValue($key));
if (Validate::isCleanHtml($val))
Configuration::updateValue($key, $val);
else
$this->_errors[] = Tools::displayError('Can not add configuration '.$key);
}
}
}
if (count($this->_errors) <= 0)
Tools::redirectAdmin($currentIndex.'&conf=6&token='.$token);
}
else
$this->_errors[] = Tools::displayError('You do not have permission to edit here.');
}
protected function validateField($value, $field)
{
if (isset($field['validation']))
{
$validate = new Validate();
if (method_exists($validate, $field['validation']))
{
if (!Validate::$field['validation']($value))
{
$this->_errors[] = Tools::displayError($field['title'].' : Incorrect value');
return false;
}
}
}
return true;
}
protected function uploadImage($id, $name, $dir, $ext = false)
{
if (isset($_FILES[$name]['tmp_name']) AND !empty($_FILES[$name]['tmp_name']))
{
// Delete old image
if (Validate::isLoadedObject($object = $this->loadObject()))
$object->deleteImage();
else
return false;
// Check image validity
if ($error = checkImage($_FILES[$name], $this->maxImageSize))
$this->_errors[] = $error;
elseif (!$tmpName = tempnam(_PS_TMP_IMG_DIR_, 'PS') OR !move_uploaded_file($_FILES[$name]['tmp_name'], $tmpName))
return false;
else
{
$_FILES[$name]['tmp_name'] = $tmpName;
// Copy new image
if (!imageResize($tmpName, _PS_IMG_DIR_.$dir.$id.'.'.$this->imageType, NULL, NULL, ($ext ? $ext : $this->imageType)))
$this->_errors[] = Tools::displayError('An error occurred while uploading image.');
if (sizeof($this->_errors))
return false;
if ($this->afterImageUpload())
{
unlink($tmpName);
return true;
}
return false;
}
}
return true;
}
protected function uploadIco($name, $dest)
{
if (isset($_FILES[$name]['tmp_name']) AND !empty($_FILES[$name]['tmp_name']))
{
/* Check ico validity */
if ($error = checkIco($_FILES[$name], $this->maxImageSize))
$this->_errors[] = $error;
/* Copy new ico */
elseif (!copy($_FILES[$name]['tmp_name'], $dest))
$this->_errors[] = Tools::displayError('an error occurred while uploading favicon: '.$_FILES[$name]['tmp_name'].' to '.$dest);
}
return !sizeof($this->_errors) ? true : false;
}
/**
* Overload this method for custom checking
*
* @param integer $id Object id used for deleting images
* @return boolean
*/
protected function postImage($id)
{
if (isset($this->fieldImageSettings['name']) AND isset($this->fieldImageSettings['dir']))
return $this->uploadImage($id, $this->fieldImageSettings['name'], $this->fieldImageSettings['dir'].'/');
elseif (!empty($this->fieldImageSettings))
foreach ($this->fieldImageSettings AS $image)
if (isset($image['name']) AND isset($image['dir']))
$this->uploadImage($id, $image['name'], $image['dir'].'/');
return !sizeof($this->_errors) ? true : false;
}
/**
* Copy datas from $_POST to object
*
* @param object &$object Object
* @param string $table Object table
*/
protected function copyFromPost(&$object, $table)
{
/* Classical fields */
foreach ($_POST AS $key => $value)
if (key_exists($key, $object) AND $key != 'id_'.$table)
{
/* Do not take care of password field if empty */
if ($key == 'passwd' AND Tools::getValue('id_'.$table) AND empty($value))
continue;
/* Automatically encrypt password in MD5 */
if ($key == 'passwd' AND !empty($value))
$value = Tools::encrypt($value);
$object->{$key} = $value;
}
/* Multilingual fields */
$rules = call_user_func(array(get_class($object), 'getValidationRules'), get_class($object));
if (sizeof($rules['validateLang']))
{
$languages = Language::getLanguages(false);
foreach ($languages AS $language)
foreach (array_keys($rules['validateLang']) AS $field)
if (isset($_POST[$field.'_'.(int)($language['id_lang'])]))
$object->{$field}[(int)($language['id_lang'])] = $_POST[$field.'_'.(int)($language['id_lang'])];
}
}
/**
* Display errors
*/
public function displayErrors()
{
if ($nbErrors = count($this->_errors) AND $this->_includeContainer)
{
echo '
';
if (count($this->_errors) == 1)
echo $this->_errors[0];
else
{
echo $nbErrors.' '.$this->l('errors').' ';
foreach ($this->_errors AS $error)
echo '
'.$error.'
';
echo '';
}
echo '
';
}
$this->includeSubTab('displayErrors');
}
/**
* Display a warning message
*
* @param string $warn Warning message to display
*/
public function displayWarning($warn)
{
$str_output = '';
if (!empty($warn))
{
$str_output .= '
';
if (!is_array($warn))
$str_output .= ''.$warn;
else
{ $str_output .= ''.
(count($warn) > 1 ? $this->l('There are') : $this->l('There is')).' '.count($warn).' '.(count($warn) > 1 ? $this->l('warnings') : $this->l('warning'))
.''.$this->l('Click here to see more').''.$this->l('Hide warning').'
';
foreach($warn as $val)
$str_output .= '
'.$val.'
';
$str_output .= '
';
}
$str_output .= '
';
}
echo $str_output;
}
/**
* Display confirmations
*/
public function displayConf()
{
if ($conf = Tools::getValue('conf'))
echo '
'.$this->_conf[(int)($conf)].'
';
}
/**
* Get the current objects' list form the database
*
* @param integer $id_lang Language used for display
* @param string $orderBy ORDER BY clause
* @param string $_orderWay Order way (ASC, DESC)
* @param integer $start Offset in LIMIT clause
* @param integer $limit Row count in LIMIT clause
*/
public function getList($id_lang, $orderBy = NULL, $orderWay = NULL, $start = 0, $limit = NULL)
{
global $cookie;
/* Manage default params values */
if (empty($limit))
$limit = ((!isset($cookie->{$this->table.'_pagination'})) ? $this->_pagination[1] : $limit = $cookie->{$this->table.'_pagination'});
if (!Validate::isTableOrIdentifier($this->table))
die (Tools::displayError('Table name is invalid:').' "'.$this->table.'"');
if (empty($orderBy))
$orderBy = $cookie->__get($this->table.'Orderby') ? $cookie->__get($this->table.'Orderby') : $this->_defaultOrderBy;
if (empty($orderWay))
$orderWay = $cookie->__get($this->table.'Orderway') ? $cookie->__get($this->table.'Orderway') : 'ASC';
$limit = (int)(Tools::getValue('pagination', $limit));
$cookie->{$this->table.'_pagination'} = $limit;
/* Check params validity */
if (!Validate::isOrderBy($orderBy) OR !Validate::isOrderWay($orderWay)
OR !is_numeric($start) OR !is_numeric($limit)
OR !Validate::isUnsignedId($id_lang))
die(Tools::displayError('get list params is not valid'));
/* Determine offset from current page */
if ((isset($_POST['submitFilter'.$this->table]) OR
isset($_POST['submitFilter'.$this->table.'_x']) OR
isset($_POST['submitFilter'.$this->table.'_y'])) AND
!empty($_POST['submitFilter'.$this->table]) AND
is_numeric($_POST['submitFilter'.$this->table]))
$start = (int)($_POST['submitFilter'.$this->table] - 1) * $limit;
/* Cache */
$this->_lang = (int)($id_lang);
$this->_orderBy = $orderBy;
$this->_orderWay = Tools::strtoupper($orderWay);
/* SQL table : orders, but class name is Order */
$sqlTable = $this->table == 'order' ? 'orders' : $this->table;
/* Query in order to get results with all fields */
$sql = 'SELECT SQL_CALC_FOUND_ROWS
'.($this->_tmpTableFilter ? ' * FROM (SELECT ' : '').'
'.($this->lang ? 'b.*, ' : '').'a.*'.(isset($this->_select) ? ', '.$this->_select.' ' : '').'
FROM `'._DB_PREFIX_.$sqlTable.'` a
'.($this->lang ? 'LEFT JOIN `'._DB_PREFIX_.$this->table.'_lang` b ON (b.`'.$this->identifier.'` = a.`'.$this->identifier.'` AND b.`id_lang` = '.(int)($id_lang).')' : '').'
'.(isset($this->_join) ? $this->_join.' ' : '').'
WHERE 1 '.(isset($this->_where) ? $this->_where.' ' : '').($this->deleted ? 'AND a.`deleted` = 0 ' : '').(isset($this->_filter) ? $this->_filter : '').'
'.(isset($this->_group) ? $this->_group.' ' : '').'
'.((isset($this->_filterHaving) || isset($this->_having)) ? 'HAVING ' : '').(isset($this->_filterHaving) ? ltrim($this->_filterHaving, ' AND ') : '').(isset($this->_having) ? $this->_having.' ' : '').'
ORDER BY '.(($orderBy == $this->identifier) ? 'a.' : '').'`'.pSQL($orderBy).'` '.pSQL($orderWay).
($this->_tmpTableFilter ? ') tmpTable WHERE 1'.$this->_tmpTableFilter : '').'
LIMIT '.(int)($start).','.(int)($limit);
$this->_list = Db::getInstance()->ExecuteS($sql);
$this->_listTotal = Db::getInstance()->getValue('SELECT FOUND_ROWS() AS `'._DB_PREFIX_.$this->table.'`');
}
/**
* Display image aside object form
*
* @param integer $id Object id
* @param string $image Local image filepath
* @param integer $size Image width
* @param integer $id_image Image id (for products with several images)
* @param string $token Employee token used in the image deletion link
* @param boolean $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function displayImage($id, $image, $size, $id_image = NULL, $token = NULL, $disableCache = false)
{
global $currentIndex;
if (!isset($token) OR empty($token))
$token = $this->token;
if ($id AND file_exists($image))
echo '
';
}
/**
* Display list header (filtering, pagination and column names)
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function displayListHeader($token = NULL)
{
global $currentIndex, $cookie;
$isCms = false;
if (preg_match('/cms/Ui', $this->identifier))
$isCms = true;
$id_cat = Tools::getValue('id_'.($isCms ? 'cms_' : '').'category');
if (!isset($token) OR empty($token))
$token = $this->token;
/* Determine total page number */
$totalPages = ceil($this->_listTotal / Tools::getValue('pagination', (isset($cookie->{$this->table.'_pagination'}) ? $cookie->{$this->table.'_pagination'} : $this->_pagination[0])));
if (!$totalPages) $totalPages = 1;
echo '';
echo '';
if (isset($this->_includeTab) AND sizeof($this->_includeTab))
echo '
';
}
/**
* Options lists
*/
public function displayOptionsList()
{
global $currentIndex, $cookie, $tab;
if (!isset($this->_fieldsOptions) OR !sizeof($this->_fieldsOptions))
return false;
$defaultLanguage = (int)Configuration::get('PS_LANG_DEFAULT');
$this->_languages = Language::getLanguages(false);
$tab = Tab::getTab((int)$cookie->id_lang, Tab::getIdFromClassName($tab));
echo '
';
echo (isset($this->optionTitle) ? '
'.$this->optionTitle.'
' : '');
echo '
';
}
/**
* Load class object using identifier in $_GET (if possible)
* otherwise return an empty object, or die
*
* @param boolean $opt Return an empty object if load fail
* @return object
*/
protected function loadObject($opt = false)
{
if ($id = (int)(Tools::getValue($this->identifier)) AND Validate::isUnsignedId($id))
{
if (!$this->_object)
$this->_object = new $this->className($id);
if (Validate::isLoadedObject($this->_object))
return $this->_object;
$this->_errors[] = Tools::displayError('Object cannot be loaded (not found)');
}
elseif ($opt)
{
$this->_object = new $this->className();
return $this->_object;
}
else
$this->_errors[] = Tools::displayError('Object cannot be loaded (identifier missing or invalid)');
$this->displayErrors();
}
/**
* Return field value if possible (both classical and multilingual fields)
*
* Case 1 : Return value if present in $_POST / $_GET
* Case 2 : Return object value
*
* @param object $obj Object
* @param string $key Field name
* @param integer $id_lang Language id (optional)
* @return string
*/
protected function getFieldValue($obj, $key, $id_lang = NULL)
{
if ($id_lang)
$defaultValue = ($obj->id AND isset($obj->{$key}[$id_lang])) ? $obj->{$key}[$id_lang] : '';
else
$defaultValue = isset($obj->{$key}) ? $obj->{$key} : '';
return Tools::getValue($key.($id_lang ? '_'.$id_lang : ''), $defaultValue);
}
/**
* Display form
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function displayForm($firstCall = true)
{
global $cookie;
$allowEmployeeFormLang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
if ($allowEmployeeFormLang && !$cookie->employee_form_lang)
$cookie->employee_form_lang = (int)(Configuration::get('PS_LANG_DEFAULT'));
$useLangFromCookie = false;
$this->_languages = Language::getLanguages(false);
if ($allowEmployeeFormLang)
foreach ($this->_languages AS $lang)
if ($cookie->employee_form_lang == $lang['id_lang'])
$useLangFromCookie = true;
if (!$useLangFromCookie)
$this->_defaultFormLanguage = (int)(Configuration::get('PS_LANG_DEFAULT'));
else
$this->_defaultFormLanguage = (int)($cookie->employee_form_lang);
// Only if it is the first call to displayForm, otherwise it has already been defined
if ($firstCall)
{
echo '
';
}
}
/**
* Display object details
*
* @global string $currentIndex Current URL in order to keep current Tab
*/
public function viewDetails() { global $currentIndex; }
/**
* Called before deletion
*
* @param object $object Object
* @return boolean
*/
protected function beforeDelete($object) { return true; }
/**
* Called before deletion
*
* @param object $object Object
* @return boolean
*/
protected function afterDelete($object, $oldId) { return true; }
protected function afterAdd($object) { return true; }
protected function afterUpdate($object) { return true; }
/**
* Check rights to view the current tab
*
* @return boolean
*/
protected function afterImageUpload() {
return true;
}
/**
* Check rights to view the current tab
*
* @return boolean
*/
public function viewAccess($disable = false)
{
global $cookie;
if ($disable)
return true;
$this->tabAccess = Profile::getProfileAccess($cookie->profile, $this->id);
if ($this->tabAccess['view'] === '1')
return true;
return false;
}
/**
* Check for security token
*/
public function checkToken()
{
$token = Tools::getValue('token');
return (!empty($token) AND $token === $this->token);
}
/**
* Display flags in forms for translations
*
* @param array $languages All languages available
* @param integer $defaultLanguage Default language id
* @param string $ids Multilingual div ids in form
* @param string $id Current div id]
* #param boolean $return define the return way : false for a display, true for a return
*/
public function displayFlags($languages, $defaultLanguage, $ids, $id, $return = false)
{
if (sizeof($languages) == 1)
return false;
$output = '
';
if ($return)
return $output;
echo $output;
}
protected function filterToField($key, $filter)
{
foreach ($this->fieldsDisplay AS $field)
if (array_key_exists('filter_key', $field) AND $field['filter_key'] == $key)
return $field;
if (array_key_exists($filter, $this->fieldsDisplay))
return $this->fieldsDisplay[$filter];
return false;
}
protected function warnDomainName()
{
if ($_SERVER['HTTP_HOST'] != Configuration::get('PS_SHOP_DOMAIN') AND $_SERVER['HTTP_HOST'] != Configuration::get('PS_SHOP_DOMAIN_SSL'))
$this->displayWarning($this->l('Your are currently connected with the following domain name:').' '.$_SERVER['HTTP_HOST'].' '.
$this->l('This one is different from the main shop domain name set in "Preferences > SEO & URLs":').' '.Configuration::get('PS_SHOP_DOMAIN').' '.
$this->l('Click here if you want to modify the main shop domain name').'');
}
}