PageRenderTime 73ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/AdminTab.php

https://bitbucket.org/marcenuc/prestashop
PHP | 2435 lines | 1743 code | 268 blank | 424 comment | 519 complexity | 4a05da5969aba5b19e189c5b5171b5e2 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*
  3. * 2007-2012 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2012 PrestaShop SA
  23. * @version Release: $Revision: 7499 $
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. * International Registered Trademark & Property of PrestaShop SA
  26. */
  27. /**
  28. * @deprecated 1.5.0
  29. */
  30. abstract class AdminTabCore
  31. {
  32. /** @var integer Tab id */
  33. public $id = -1;
  34. /** @var string Associated table name */
  35. public $table;
  36. /** @var string Object identifier inside the associated table */
  37. protected $identifier = false;
  38. /** @var string Tab name */
  39. public $className;
  40. /** @var string Security token */
  41. public $token;
  42. /** @var boolean Automatically join language table if true */
  43. public $lang = false;
  44. /** @var boolean Tab Automatically displays edit/delete icons if true */
  45. public $edit = false;
  46. /** @var boolean Tab Automatically displays view icon if true */
  47. public $view = false;
  48. /** @var boolean Tab Automatically displays delete icon if true */
  49. public $delete = false;
  50. /** @var boolean Table records are not deleted but marked as deleted */
  51. public $deleted = false;
  52. /** @var boolean Tab Automatically displays duplicate icon if true */
  53. public $duplicate = false;
  54. /** @var boolean Content line is clickable if true */
  55. public $noLink = false;
  56. /** @var boolean select other required fields */
  57. public $requiredDatabase = false;
  58. /** @var boolean Tab Automatically displays '$color' as background color on listing if true */
  59. public $colorOnBackground = false;
  60. /** @var string Add fields into data query to display list */
  61. protected $_select;
  62. /** @var string Join tables into data query to display list */
  63. protected $_join;
  64. /** @var string Add conditions into data query to display list */
  65. protected $_where;
  66. /** @var string Group rows into data query to display list */
  67. protected $_group;
  68. /** @var string Having rows into data query to display list */
  69. protected $_having;
  70. /** @var array Name and directory where class image are located */
  71. public $fieldImageSettings = array();
  72. /** @var string Image type */
  73. public $imageType = 'jpg';
  74. /** @var array Fields to display in list */
  75. public $fieldsDisplay = array();
  76. public $optionTitle = null;
  77. /** @var string shop */
  78. public $shopLinkType;
  79. /** @var bool */
  80. public $shopShareDatas = false;
  81. /** @var array Cache for query results */
  82. protected $_list = array();
  83. /** @var integer Number of results in list */
  84. protected $_listTotal = 0;
  85. /** @var array WHERE clause determined by filter fields */
  86. protected $_filter;
  87. /** @var array Temporary SQL table WHERE clause determinated by filter fields */
  88. protected $_tmpTableFilter = '';
  89. /** @var array Number of results in list per page (used in select field) */
  90. protected $_pagination = array(20, 50, 100, 300);
  91. /** @var string ORDER BY clause determined by field/arrows in list header */
  92. protected $_orderBy;
  93. /** @var string Default ORDER BY clause when $_orderBy is not defined */
  94. protected $_defaultOrderBy = false;
  95. /** @var string Order way (ASC, DESC) determined by arrows in list header */
  96. protected $_orderWay;
  97. /** @var integer Max image size for upload
  98. * As of 1.5 it is recommended to not set a limit to max image size
  99. **/
  100. protected $maxImageSize;
  101. /** @var array Errors displayed after post processing */
  102. public $_errors = array();
  103. /** @var array Confirmations displayed after post processing */
  104. protected $_conf;
  105. /** @var object Object corresponding to the tab */
  106. protected $_object = false;
  107. /** @var array tabAccess */
  108. public $tabAccess;
  109. /** @var string specificConfirmDelete */
  110. public $specificConfirmDelete = NULL;
  111. public static $currentIndex;
  112. public $smarty;
  113. 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', 'id_attribute' => 'id_attribute', 'id_attribute_group' => 'id_attribute_group', 'id_feature' => 'id_feature', 'id_carrier' => 'id_carrier');
  114. /** @var bool Redirect or not ater a creation */
  115. protected $_redirect = true;
  116. /** @var bool If false, don't add form tags in options forms */
  117. protected $formOptions = true;
  118. public $_fieldsOptions = array();
  119. /**
  120. * @since 1.5.0
  121. * @var array
  122. */
  123. public $optionsList = array();
  124. /**
  125. * @since 1.5.0
  126. * @var Context
  127. */
  128. public $context;
  129. protected $_languages = NULL;
  130. protected $_defaultFormLanguage = NULL;
  131. protected $_includeObj = array();
  132. protected $_includeVars = false;
  133. protected $_includeContainer = true;
  134. public $ajax = false;
  135. /**
  136. * if true, ajax-tab will not wait 1 sec
  137. * @var boolean
  138. */
  139. public $ignore_sleep = false;
  140. public static $tabParenting = array(
  141. 'AdminCms' => 'AdminCmsContent',
  142. 'AdminCmsCategories' => 'AdminCmsContent',
  143. 'AdminOrdersStates' => 'AdminStatuses',
  144. 'AdminAttributeGenerator' => 'AdminProducts',
  145. 'AdminAttributes' => 'AdminAttributesGroups',
  146. 'AdminFeaturesValues' => 'AdminFeatures',
  147. 'AdminReturnStates' => 'AdminStatuses',
  148. 'AdminStatsTab' => 'AdminStats'
  149. );
  150. public function __construct()
  151. {
  152. $this->context = Context::getContext();
  153. $this->id = Tab::getIdFromClassName(get_class($this));
  154. $this->_conf = array(
  155. 1 => $this->l('Deletion successful'), 2 => $this->l('Selection successfully deleted'),
  156. 3 => $this->l('Creation successful'), 4 => $this->l('Update successful'),
  157. 5 => $this->l('Status update successful'), 6 => $this->l('Settings update successful'),
  158. 7 => $this->l('Image successfully deleted'), 8 => $this->l('Module downloaded successfully'),
  159. 9 => $this->l('Thumbnails successfully regenerated'), 10 => $this->l('Message sent to the customer'),
  160. 11 => $this->l('Comment added'), 12 => $this->l('Module installed successfully'),
  161. 13 => $this->l('Module uninstalled successfully'), 14 => $this->l('Language successfully copied'),
  162. 15 => $this->l('Translations successfully added'), 16 => $this->l('Module transplanted successfully to hook'),
  163. 17 => $this->l('Module removed successfully from hook'), 18 => $this->l('Upload successful'),
  164. 19 => $this->l('Duplication completed successfully'), 20 => $this->l('Translation added successfully but the language has not been created'),
  165. 21 => $this->l('Module reset successfully'), 22 => $this->l('Module deleted successfully'),
  166. 23 => $this->l('Localization pack imported successfully'), 24 => $this->l('Refund Successful'),
  167. 25 => $this->l('Images successfully moved'),
  168. );
  169. if (!$this->identifier) $this->identifier = 'id_'.$this->table;
  170. if (!$this->_defaultOrderBy) $this->_defaultOrderBy = $this->identifier;
  171. $className = get_class($this);
  172. // if ($className == 'AdminCategories' OR $className == 'AdminProducts')
  173. // $className = 'AdminCatalog';
  174. $this->token = Tools::getAdminToken($className.(int)$this->id.(int)$this->context->employee->id);
  175. if (!Shop::isFeatureActive())
  176. $this->shopLinkType = '';
  177. }
  178. /**
  179. * use translations files to replace english expression.
  180. *
  181. * @param mixed $string term or expression in english
  182. * @param string $class
  183. * @param boolan $addslashes if set to true, the return value will pass through addslashes(). Otherwise, stripslashes().
  184. * @param boolean $htmlentities if set to true(default), the return value will pass through htmlentities($string, ENT_QUOTES, 'utf-8')
  185. * @return string the translation if available, or the english default text.
  186. */
  187. protected function l($string, $class = 'AdminTab', $addslashes = FALSE, $htmlentities = TRUE)
  188. {
  189. // if the class is extended by a module, use modules/[module_name]/xx.php lang file
  190. $currentClass = get_class($this);
  191. if(Module::getModuleNameFromClass($currentClass))
  192. {
  193. $string = str_replace('\'', '\\\'', $string);
  194. return Translate::getModuleTranslation(Module::$classInModule[$currentClass], $string, $currentClass);
  195. }
  196. global $_LANGADM;
  197. if ($class == __CLASS__)
  198. $class = 'AdminTab';
  199. $key = md5(str_replace('\'', '\\\'', $string));
  200. $str = (key_exists(get_class($this).$key, $_LANGADM)) ? $_LANGADM[get_class($this).$key] : ((key_exists($class.$key, $_LANGADM)) ? $_LANGADM[$class.$key] : $string);
  201. $str = $htmlentities ? htmlentities($str, ENT_QUOTES, 'utf-8') : $str;
  202. return str_replace('"', '&quot;', ($addslashes ? addslashes($str) : stripslashes($str)));
  203. }
  204. /**
  205. * ajaxDisplay is the default ajax return sytem
  206. *
  207. * @return void
  208. */
  209. public function displayAjax()
  210. {
  211. }
  212. /**
  213. * Manage page display (form, list...)
  214. */
  215. public function display()
  216. {
  217. // Include other tab in current tab
  218. if ($this->includeSubTab('display', array('submitAdd2', 'add', 'update', 'view'))){}
  219. // Include current tab
  220. elseif ((Tools::getValue('submitAdd'.$this->table) && count($this->_errors)) || isset($_GET['add'.$this->table]))
  221. {
  222. if ($this->tabAccess['add'] === '1')
  223. {
  224. $this->displayForm();
  225. if ($this->tabAccess['view'])
  226. echo '<br /><br /><a href="'.((Tools::getValue('back')) ? Tools::getValue('back') : self::$currentIndex.'&token='.$this->token).'"><img src="../img/admin/arrow2.gif" /> '.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).'</a><br />';
  227. }
  228. else
  229. echo $this->l('You do not have permission to add here');
  230. }
  231. elseif (isset($_GET['update'.$this->table]))
  232. {
  233. if ($this->tabAccess['edit'] === '1' || ($this->table == 'employee' && $this->context->employee->id == Tools::getValue('id_employee')))
  234. {
  235. $this->displayForm();
  236. if ($this->tabAccess['view'])
  237. echo '<br /><br /><a href="'.((Tools::getValue('back')) ? Tools::getValue('back') : self::$currentIndex.'&token='.$this->token).'"><img src="../img/admin/arrow2.gif" /> '.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).'</a><br />';
  238. }
  239. else
  240. echo $this->l('You do not have permission to edit here');
  241. }
  242. elseif (isset($_GET['view'.$this->table]))
  243. $this->{'view'.$this->table}();
  244. else
  245. {
  246. $this->getList($this->context->language->id);
  247. $this->displayList();
  248. echo '<br />';
  249. $this->displayOptionsList();
  250. $this->displayRequiredFields();
  251. $this->includeSubTab('display');
  252. }
  253. }
  254. public function displayRequiredFields()
  255. {
  256. if (!$this->tabAccess['add'] || !$this->tabAccess['delete'] === '1' || !$this->requiredDatabase)
  257. return;
  258. $rules = call_user_func_array(array($this->className, 'getValidationRules'), array($this->className));
  259. $required_class_fields = array($this->identifier);
  260. foreach ($rules['required'] as $required)
  261. $required_class_fields[] = $required;
  262. echo '<br />
  263. <p><a href="#" onclick="if ($(\'.requiredFieldsParameters:visible\').length == 0) $(\'.requiredFieldsParameters\').slideDown(\'slow\'); else $(\'.requiredFieldsParameters\').slideUp(\'slow\'); return false;"><img src="../img/admin/duplicate.gif" alt="" /> '.$this->l('Set required fields for this section').'</a></p>
  264. <fieldset style="display:none" class="width1 requiredFieldsParameters">
  265. <legend>'.$this->l('Required Fields').'</legend>
  266. <form name="updateFields" action="'.self::$currentIndex.'&submitFields'.$this->table.'=1&token='.$this->token.'" method="post">
  267. <p><b>'.$this->l('Select the fields you would like to be required for this section.').'<br />
  268. <table cellspacing="0" cellpadding="0" class="table width1 clear">
  269. <tr>
  270. <th><input type="checkbox" onclick="checkDelBoxes(this.form, \'fieldsBox[]\', this.checked)" class="noborder" name="checkme"></th>
  271. <th>'.$this->l('Field Name').'</th>
  272. </tr>';
  273. $object = new $this->className();
  274. $res = $object->getFieldsRequiredDatabase();
  275. $required_fields = array();
  276. foreach ($res as $row)
  277. $required_fields[(int)$row['id_required_field']] = $row['field_name'];
  278. $table_fields = Db::getInstance()->executeS('SHOW COLUMNS FROM '.pSQL(_DB_PREFIX_.$this->table));
  279. $irow = 0;
  280. foreach ($table_fields as $field)
  281. {
  282. if (in_array($field['Field'], $required_class_fields))
  283. continue;
  284. echo '<tr class="'.($irow++ % 2 ? 'alt_row' : '').'">
  285. <td class="noborder"><input type="checkbox" name="fieldsBox[]" value="'.$field['Field'].'" '.(in_array($field['Field'], $required_fields) ? 'checked="checked"' : '').' /></td>
  286. <td>'.$field['Field'].'</td>
  287. </tr>';
  288. }
  289. echo '</table><br />
  290. <center><input style="margin-left:15px;" class="button" type="submit" value="'.$this->l(' Save ').'" name="submitFields" /></center>
  291. </fieldset>';
  292. }
  293. public function includeSubTab($methodname, $actions = array())
  294. {
  295. if (!isset($this->_includeTab) || !is_array($this->_includeTab))
  296. return false;
  297. $key = 0;
  298. $inc = false;
  299. foreach ($this->_includeTab as $subtab => $extraVars)
  300. {
  301. /* New tab loading */
  302. $classname = 'Admin'.$subtab;
  303. if (($module = Db::getInstance()->getValue('SELECT `module` FROM `'._DB_PREFIX_.'tab` WHERE `class_name` = \''.pSQL($classname).'\'')) && file_exists(_PS_MODULE_DIR_.'/'.$module.'/'.$classname.'.php'))
  304. include_once(_PS_MODULE_DIR_.'/'.$module.'/'.$classname.'.php');
  305. elseif (file_exists(_PS_ADMIN_DIR_.'/tabs/'.$classname.'.php'))
  306. include_once('tabs/'.$classname.'.php');
  307. if (!isset($this->_includeObj[$key]))
  308. $this->_includeObj[$key] = new $classname;
  309. $adminTab = $this->_includeObj[$key];
  310. $adminTab->token = $this->token;
  311. /* Extra variables addition */
  312. if (!empty($extraVars) && is_array($extraVars))
  313. foreach ($extraVars as $varKey => $varValue)
  314. $adminTab->$varKey = $varValue;
  315. /* Actions management */
  316. foreach ($actions as $action)
  317. {
  318. switch ($action)
  319. {
  320. case 'submitAdd1':
  321. if (Tools::getValue('submitAdd'.$adminTab->table))
  322. $ok_inc = true;
  323. break;
  324. case 'submitAdd2':
  325. if (Tools::getValue('submitAdd'.$adminTab->table) && count($adminTab->_errors))
  326. $ok_inc = true;
  327. break;
  328. case 'submitDel':
  329. if (Tools::getValue('submitDel'.$adminTab->table))
  330. $ok_inc = true;
  331. break;
  332. case 'submitFilter':
  333. if (Tools::isSubmit('submitFilter'.$adminTab->table))
  334. $ok_inc = true;
  335. case 'submitReset':
  336. if (Tools::isSubmit('submitReset'.$adminTab->table))
  337. $ok_inc = true;
  338. default:
  339. if (isset($_GET[$action.$adminTab->table]))
  340. $ok_inc = true;
  341. }
  342. }
  343. $inc = false;
  344. if ((isset($ok_inc) && $ok_inc) || !count($actions))
  345. {
  346. if (!$adminTab->viewAccess())
  347. {
  348. echo Tools::displayError('Access denied.');
  349. return false;
  350. }
  351. if (!count($actions))
  352. if (($methodname == 'displayErrors' && count($adminTab->_errors)) || $methodname != 'displayErrors')
  353. echo (isset($this->_includeTabTitle[$key]) ? '<h2>'.$this->_includeTabTitle[$key].'</h2>' : '');
  354. if ($adminTab->_includeVars)
  355. foreach ($adminTab->_includeVars as $var => $value)
  356. $adminTab->$var = $this->$value;
  357. $adminTab->$methodname();
  358. $inc = true;
  359. }
  360. $key++;
  361. }
  362. return $inc;
  363. }
  364. /**
  365. * Manage page display (form, list...)
  366. *
  367. * @param string $className Allow to validate a different class than the current one
  368. */
  369. public function validateRules($className = false)
  370. {
  371. if (!$className)
  372. $className = $this->className;
  373. /* Class specific validation rules */
  374. $rules = call_user_func(array($className, 'getValidationRules'), $className);
  375. if ((count($rules['requiredLang']) || count($rules['sizeLang']) || count($rules['validateLang'])))
  376. {
  377. /* Language() instance determined by default language */
  378. $defaultLanguage = new Language((int)(Configuration::get('PS_LANG_DEFAULT')));
  379. /* All availables languages */
  380. $languages = Language::getLanguages(false);
  381. }
  382. /* Checking for required fields */
  383. foreach ($rules['required'] as $field)
  384. if (($value = Tools::getValue($field)) == false && (string)$value != '0')
  385. if (!Tools::getValue($this->identifier) || ($field != 'passwd' && $field != 'no-picture'))
  386. $this->_errors[] = sprintf(Tools::displayError('The field %s is required.'), call_user_func(array($className, 'displayFieldName'), $field, $className));
  387. /* Checking for multilingual required fields */
  388. foreach ($rules['requiredLang'] as $fieldLang)
  389. if (($empty = Tools::getValue($fieldLang.'_'.$defaultLanguage->id)) === false || $empty !== '0' && empty($empty))
  390. $this->_errors[] = sprintf(Tools::displayError('The field %1$s is required at least in %2$s.'), call_user_func(array($className, 'displayFieldName'), $fieldLang, $className), $defaultLanguage->name);
  391. /* Checking for maximum fields sizes */
  392. foreach ($rules['size'] as $field => $maxLength)
  393. if (Tools::getValue($field) !== false && Tools::strlen(Tools::getValue($field)) > $maxLength)
  394. $this->_errors[] = sprintf(Tools::displayError('field %1$s is too long. (%2$d chars max)'), call_user_func(array($className, 'displayFieldName'), $field, $className), $maxLength);
  395. /* Checking for maximum multilingual fields size */
  396. foreach ($rules['sizeLang'] as $fieldLang => $maxLength)
  397. foreach ($languages as $language)
  398. if (Tools::getValue($fieldLang.'_'.$language['id_lang']) !== false && Tools::strlen(Tools::getValue($fieldLang.'_'.$language['id_lang'])) > $maxLength)
  399. $this->_errors[] = sprintf(Tools::displayError('field %1$s is too long. (%2$d chars max, html chars including)'), call_user_func(array($className, 'displayFieldName'), $fieldLang, $className), $maxLength);
  400. /* Overload this method for custom checking */
  401. $this->_childValidation();
  402. /* Checking for fields validity */
  403. foreach ($rules['validate'] AS $field => $function)
  404. if (($value = Tools::getValue($field)) !== false AND !empty($value) AND ($field != 'passwd'))
  405. if (!Validate::$function($value))
  406. $this->_errors[] = sprintf(Tools::displayError('The field %1$s (%2$s) is invalid.'), call_user_func(array($className, 'displayFieldName'), $field, $className));
  407. /* Checking for passwd_old validity */
  408. if (($value = Tools::getValue('passwd')) != false)
  409. {
  410. if ($className == 'Employee' && !Validate::isPasswdAdmin($value))
  411. $this->_errors[] = sprintf(Tools::displayError('The field %1$s (%2$s) is invalid.'), call_user_func(array($className, 'displayFieldName'), 'passwd', $className));
  412. elseif ($className == 'Customer' && !Validate::isPasswd($value))
  413. $this->_errors[] = sprintf(Tools::displayError('The field %1$s (%2$s) is invalid.'), call_user_func(array($className, 'displayFieldName'), 'passwd', $className));
  414. }
  415. /* Checking for multilingual fields validity */
  416. foreach ($rules['validateLang'] as $fieldLang => $function)
  417. foreach ($languages as $language)
  418. if (($value = Tools::getValue($fieldLang.'_'.$language['id_lang'])) !== false && !empty($value))
  419. if (!Validate::$function($value))
  420. $this->_errors[] = sprintf(Tools::displayError('The field %1$s (%2$s) is invalid.'), call_user_func(array($className, 'displayFieldName'), $fieldLang, $className), $language['name']);
  421. }
  422. /**
  423. * Overload this method for custom checking
  424. */
  425. protected function _childValidation() { }
  426. /**
  427. * Overload this method for custom checking
  428. *
  429. * @param integer $id Object id used for deleting images
  430. * @deprecated As of 1.5 use ObjectModel->deleteImage instead.
  431. */
  432. public function deleteImage($id)
  433. {
  434. Tools::displayAsDeprecated();
  435. $dir = null;
  436. /* Deleting object images and thumbnails (cache) */
  437. if (key_exists('dir', $this->fieldImageSettings))
  438. {
  439. $dir = $this->fieldImageSettings['dir'].'/';
  440. if (file_exists(_PS_IMG_DIR_.$dir.$id.'.'.$this->imageType) && !unlink(_PS_IMG_DIR_.$dir.$id.'.'.$this->imageType))
  441. return false;
  442. }
  443. if (file_exists(_PS_TMP_IMG_DIR_.$this->table.'_'.$id.'.'.$this->imageType) && !unlink(_PS_TMP_IMG_DIR_.$this->table.'_'.$id.'.'.$this->imageType))
  444. return false;
  445. if (file_exists(_PS_TMP_IMG_DIR_.$this->table.'_mini_'.$id.'.'.$this->imageType) && !unlink(_PS_TMP_IMG_DIR_.$this->table.'_mini_'.$id.'.'.$this->imageType))
  446. return false;
  447. $types = ImageType::getImagesTypes();
  448. foreach ($types as $imageType)
  449. if (file_exists(_PS_IMG_DIR_.$dir.$id.'-'.stripslashes($imageType['name']).'.'.$this->imageType) && !unlink(_PS_IMG_DIR_.$dir.$id.'-'.stripslashes($imageType['name']).'.'.$this->imageType))
  450. return false;
  451. return true;
  452. }
  453. /**
  454. * ajaxPreProcess is a method called in ajax-tab.php before displayConf().
  455. *
  456. * @return void
  457. */
  458. public function ajaxPreProcess()
  459. {
  460. }
  461. /**
  462. * ajaxProcess is the default handle method for request with ajax-tab.php
  463. *
  464. * @return void
  465. */
  466. public function ajaxProcess()
  467. {
  468. }
  469. /**
  470. * Manage page processing
  471. */
  472. public function postProcess()
  473. {
  474. if (!isset($this->table))
  475. return false;
  476. // set token
  477. $token = Tools::getValue('token') ? Tools::getValue('token') : $this->token;
  478. // Sub included tab postProcessing
  479. $this->includeSubTab('postProcess', array('status', 'submitAdd1', 'submitDel', 'delete', 'submitFilter', 'submitReset'));
  480. /* Delete object image */
  481. if (isset($_GET['deleteImage']))
  482. {
  483. if (Validate::isLoadedObject($object = $this->loadObject()))
  484. if (($object->deleteImage()))
  485. Tools::redirectAdmin(self::$currentIndex.'&add'.$this->table.'&'.$this->identifier.'='.Tools::getValue($this->identifier).'&conf=7&token='.$token);
  486. $this->_errors[] = Tools::displayError('An error occurred during image deletion (cannot load object).');
  487. }
  488. /* Delete object */
  489. elseif (isset($_GET['delete'.$this->table]))
  490. {
  491. if ($this->tabAccess['delete'] === '1')
  492. {
  493. if (Validate::isLoadedObject($object = $this->loadObject()) && isset($this->fieldImageSettings))
  494. {
  495. // check if request at least one object with noZeroObject
  496. if (isset($object->noZeroObject) && count(call_user_func(array($this->className, $object->noZeroObject))) <= 1)
  497. $this->_errors[] = Tools::displayError('You need at least one object.').' <b>'.$this->table.'</b><br />'.Tools::displayError('You cannot delete all of the items.');
  498. else
  499. {
  500. if ($this->deleted)
  501. {
  502. $object->deleteImage();
  503. $object->deleted = 1;
  504. if(method_exists($object, 'cleanPositions'))
  505. $object->cleanPositions();
  506. if ($object->update())
  507. Tools::redirectAdmin(self::$currentIndex.'&conf=1&token='.$token);
  508. }
  509. elseif ($object->delete())
  510. {
  511. if(method_exists($object, 'cleanPositions'))
  512. $object->cleanPositions();
  513. Tools::redirectAdmin(self::$currentIndex.'&conf=1&token='.$token);
  514. }
  515. $this->_errors[] = Tools::displayError('An error occurred during deletion.');
  516. }
  517. }
  518. else
  519. $this->_errors[] = Tools::displayError('An error occurred while deleting object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  520. }
  521. else
  522. $this->_errors[] = Tools::displayError('You do not have permission to delete here.');
  523. }
  524. /* Change object statuts (active, inactive) */
  525. elseif ((isset($_GET['status'.$this->table]) || isset($_GET['status'])) && Tools::getValue($this->identifier))
  526. {
  527. if ($this->tabAccess['edit'] === '1')
  528. {
  529. if (Validate::isLoadedObject($object = $this->loadObject()))
  530. {
  531. if ($object->toggleStatus())
  532. Tools::redirectAdmin(self::$currentIndex.'&conf=5'.((($id_category = (int)(Tools::getValue('id_category'))) && Tools::getValue('id_product')) ? '&id_category='.$id_category : '').'&token='.$token);
  533. else
  534. $this->_errors[] = Tools::displayError('An error occurred while updating status.');
  535. }
  536. else
  537. $this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  538. }
  539. else
  540. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  541. }
  542. /* Move an object */
  543. elseif (isset($_GET['position']))
  544. {
  545. if ($this->tabAccess['edit'] !== '1')
  546. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  547. elseif (!Validate::isLoadedObject($object = $this->loadObject()))
  548. $this->_errors[] = Tools::displayError('An error occurred while updating status for object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  549. elseif (!$object->updatePosition((int)(Tools::getValue('way')), (int)(Tools::getValue('position'))))
  550. $this->_errors[] = Tools::displayError('Failed to update the position.');
  551. else
  552. Tools::redirectAdmin(self::$currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.(($id_identifier = (int)(Tools::getValue($this->identifier))) ? ('&'.$this->identifier.'='.$id_identifier) : '').'&token='.$token);
  553. }
  554. /* Delete multiple objects */
  555. elseif (Tools::getValue('submitDel'.$this->table))
  556. {
  557. if ($this->tabAccess['delete'] === '1')
  558. {
  559. if (isset($_POST[$this->table.'Box']))
  560. {
  561. $object = new $this->className();
  562. if (isset($object->noZeroObject) &&
  563. // Check if all object will be deleted
  564. (count(call_user_func(array($this->className, $object->noZeroObject))) <= 1 || count($_POST[$this->table.'Box']) == count(call_user_func(array($this->className, $object->noZeroObject)))))
  565. $this->_errors[] = Tools::displayError('You need at least one object.').' <b>'.$this->table.'</b><br />'.Tools::displayError('You cannot delete all of the items.');
  566. else
  567. {
  568. $result = true;
  569. if ($this->deleted)
  570. {
  571. foreach(Tools::getValue($this->table.'Box') as $id)
  572. {
  573. $toDelete = new $this->className($id);
  574. $toDelete->deleted = 1;
  575. $result = $result && $toDelete->update();
  576. }
  577. }
  578. else
  579. $result = $object->deleteSelection(Tools::getValue($this->table.'Box'));
  580. if ($result)
  581. Tools::redirectAdmin(self::$currentIndex.'&conf=2&token='.$token);
  582. $this->_errors[] = Tools::displayError('An error occurred while deleting selection.');
  583. }
  584. // clean carriers positions
  585. Carrier::cleanPositions();
  586. }
  587. else
  588. $this->_errors[] = Tools::displayError('You must select at least one element to delete.');
  589. }
  590. else
  591. $this->_errors[] = Tools::displayError('You do not have permission to delete here.');
  592. }
  593. /* Create or update an object */
  594. elseif (Tools::getValue('submitAdd'.$this->table))
  595. {
  596. /* Checking fields validity */
  597. $this->validateRules();
  598. if (!count($this->_errors))
  599. {
  600. $id = (int)(Tools::getValue($this->identifier));
  601. /* Object update */
  602. if (isset($id) && !empty($id))
  603. {
  604. if ($this->tabAccess['edit'] === '1' || ($this->table == 'employee' && $this->context->employee->id == Tools::getValue('id_employee') && Tools::isSubmit('updateemployee')))
  605. {
  606. $object = new $this->className($id);
  607. if (Validate::isLoadedObject($object))
  608. {
  609. /* Specific to objects which must not be deleted */
  610. if ($this->deleted && $this->beforeDelete($object))
  611. {
  612. // Create new one with old objet values
  613. $objectNew = new $this->className($object->id);
  614. $objectNew->id = NULL;
  615. $objectNew->date_add = '';
  616. $objectNew->date_upd = '';
  617. // Update old object to deleted
  618. $object->deleted = 1;
  619. $object->update();
  620. // Update new object with post values
  621. $this->copyFromPost($objectNew, $this->table);
  622. $result = $objectNew->add();
  623. if (Validate::isLoadedObject($objectNew))
  624. $this->afterDelete($objectNew, $object->id);
  625. }
  626. else
  627. {
  628. $this->copyFromPost($object, $this->table);
  629. $result = $object->update();
  630. $this->afterUpdate($object);
  631. }
  632. if ($object->id)
  633. $this->updateAssoShop($object->id);
  634. if (!$result)
  635. $this->_errors[] = Tools::displayError('An error occurred while updating object.').' <b>'.$this->table.'</b> ('.Db::getInstance()->getMsgError().')';
  636. elseif ($this->postImage($object->id) && !count($this->_errors))
  637. {
  638. if ($this->table == 'group')
  639. $this->updateRestrictions($object->id);
  640. $parent_id = (int)(Tools::getValue('id_parent', 1));
  641. // Specific back redirect
  642. if ($back = Tools::getValue('back'))
  643. Tools::redirectAdmin(urldecode($back).'&conf=4');
  644. // Specific scene feature
  645. if (Tools::getValue('stay_here') == 'on' || Tools::getValue('stay_here') == 'true' || Tools::getValue('stay_here') == '1')
  646. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&updatescene&token='.$token);
  647. // Save and stay on same form
  648. if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
  649. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&update'.$this->table.'&token='.$token);
  650. // Save and back to parent
  651. if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
  652. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=4&token='.$token);
  653. // Default behavior (save and back)
  654. Tools::redirectAdmin(self::$currentIndex.($parent_id ? '&'.$this->identifier.'='.$object->id : '').'&conf=4&token='.$token);
  655. }
  656. }
  657. else
  658. $this->_errors[] = Tools::displayError('An error occurred while updating object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  659. }
  660. else
  661. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  662. }
  663. /* Object creation */
  664. else
  665. {
  666. if ($this->tabAccess['add'] === '1')
  667. {
  668. $object = new $this->className();
  669. $this->copyFromPost($object, $this->table);
  670. if (!$object->add())
  671. $this->_errors[] = Tools::displayError('An error occurred while creating object.').' <b>'.$this->table.' ('.Db::getInstance()->getMsgError().')</b>';
  672. elseif (($_POST[$this->identifier] = $object->id /* voluntary */) && $this->postImage($object->id) && !count($this->_errors) && $this->_redirect)
  673. {
  674. $parent_id = (int)(Tools::getValue('id_parent', 1));
  675. $this->afterAdd($object);
  676. $this->updateAssoShop($object->id);
  677. if ($this->table == 'group')
  678. {
  679. $this->updateRestrictions($object->id);
  680. // assign group access to every categories
  681. $categories = Category::getCategories($this->context->language->id, true);
  682. $rowList = array();$a=0;
  683. foreach ($categories as $category)
  684. foreach ($category as $categ_id => $categ)
  685. if ($categ_id != 1)
  686. $rowList[] = array('id_category' => $categ_id, 'id_group' => $object->id);
  687. Db::getInstance()->insert('category_group', $rowList);
  688. }
  689. // Save and stay on same form
  690. if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
  691. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=3&update'.$this->table.'&token='.$token);
  692. // Save and back to parent
  693. if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
  694. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=3&token='.$token);
  695. // Default behavior (save and back)
  696. Tools::redirectAdmin(self::$currentIndex.($parent_id ? '&'.$this->identifier.'='.$object->id : '').'&conf=3&token='.$token);
  697. }
  698. }
  699. else
  700. $this->_errors[] = Tools::displayError('You do not have permission to add here.');
  701. }
  702. }
  703. $this->_errors = array_unique($this->_errors);
  704. }
  705. /* Cancel all filters for this tab */
  706. elseif (isset($_POST['submitReset'.$this->table]))
  707. {
  708. $filters = $this->context->cookie->getFamily($this->table.'Filter_');
  709. foreach ($filters as $cookieKey => $filter)
  710. if (strncmp($cookieKey, $this->table.'Filter_', 7 + Tools::strlen($this->table)) == 0)
  711. {
  712. $key = substr($cookieKey, 7 + Tools::strlen($this->table));
  713. /* Table alias could be specified using a ! eg. alias!field */
  714. $tmpTab = explode('!', $key);
  715. $key = (count($tmpTab) > 1 ? $tmpTab[1] : $tmpTab[0]);
  716. if (array_key_exists($key, $this->fieldsDisplay))
  717. unset($this->context->cookie->$cookieKey);
  718. }
  719. if (isset($this->context->cookie->{'submitFilter'.$this->table}))
  720. unset($this->context->cookie->{'submitFilter'.$this->table});
  721. if (isset($this->context->cookie->{$this->table.'Orderby'}))
  722. unset($this->context->cookie->{$this->table.'Orderby'});
  723. if (isset($this->context->cookie->{$this->table.'Orderway'}))
  724. unset($this->context->cookie->{$this->table.'Orderway'});
  725. unset($_POST);
  726. }
  727. /* Submit options list */
  728. elseif (Tools::getValue('submitOptions'.$this->table))
  729. {
  730. $this->updateOptions($token);
  731. }
  732. /* Manage list filtering */
  733. elseif (Tools::isSubmit('submitFilter'.$this->table) || $this->context->cookie->{'submitFilter'.$this->table} !== false)
  734. {
  735. $_POST = array_merge($this->context->cookie->getFamily($this->table.'Filter_'), (isset($_POST) ? $_POST : array()));
  736. foreach ($_POST as $key => $value)
  737. {
  738. /* Extracting filters from $_POST on key filter_ */
  739. if ($value != NULL && !strncmp($key, $this->table.'Filter_', 7 + Tools::strlen($this->table)))
  740. {
  741. $key = Tools::substr($key, 7 + Tools::strlen($this->table));
  742. /* Table alias could be specified using a ! eg. alias!field */
  743. $tmpTab = explode('!', $key);
  744. $filter = count($tmpTab) > 1 ? $tmpTab[1] : $tmpTab[0];
  745. if ($field = $this->filterToField($key, $filter))
  746. {
  747. $type = (array_key_exists('filter_type', $field) ? $field['filter_type'] : (array_key_exists('type', $field) ? $field['type'] : false));
  748. if (($type == 'date' || $type == 'datetime') && is_string($value))
  749. $value = Tools::unSerialize($value);
  750. $key = isset($tmpTab[1]) ? $tmpTab[0].'.`'.bqSQL($tmpTab[1]).'`' : '`'.bqSQL($tmpTab[0]).'`';
  751. if (array_key_exists('tmpTableFilter', $field))
  752. $sqlFilter = & $this->_tmpTableFilter;
  753. elseif (array_key_exists('havingFilter', $field))
  754. $sqlFilter = & $this->_filterHaving;
  755. else
  756. $sqlFilter = & $this->_filter;
  757. /* Only for date filtering (from, to) */
  758. if (is_array($value))
  759. {
  760. if (isset($value[0]) && !empty($value[0]))
  761. {
  762. if (!Validate::isDate($value[0]))
  763. $this->_errors[] = Tools::displayError('\'From:\' date format is invalid (YYYY-MM-DD)');
  764. else
  765. $sqlFilter .= ' AND '.$key.' >= \''.pSQL(Tools::dateFrom($value[0])).'\'';
  766. }
  767. if (isset($value[1]) && !empty($value[1]))
  768. {
  769. if (!Validate::isDate($value[1]))
  770. $this->_errors[] = Tools::displayError('\'To:\' date format is invalid (YYYY-MM-DD)');
  771. else
  772. $sqlFilter .= ' AND '.$key.' <= \''.pSQL(Tools::dateTo($value[1])).'\'';
  773. }
  774. }
  775. else
  776. {
  777. $sqlFilter .= ' AND ';
  778. if ($type == 'int' || $type == 'bool')
  779. $sqlFilter .= (($key == $this->identifier || $key == '`'.$this->identifier.'`' || $key == '`active`') ? 'a.' : '').pSQL($key).' = '.(int)($value).' ';
  780. elseif ($type == 'decimal')
  781. $sqlFilter .= (($key == $this->identifier || $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' = '.(float)($value).' ';
  782. elseif ($type == 'select')
  783. $sqlFilter .= (($key == $this->identifier || $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' = \''.pSQL($value).'\' ';
  784. else
  785. $sqlFilter .= (($key == $this->identifier || $key == '`'.$this->identifier.'`') ? 'a.' : '').pSQL($key).' LIKE \'%'.pSQL($value).'%\' ';
  786. }
  787. }
  788. }
  789. }
  790. }
  791. elseif(Tools::isSubmit('submitFields') && $this->requiredDatabase && $this->tabAccess['add'] === '1' && $this->tabAccess['delete'] === '1')
  792. {
  793. if (!is_array($fields = Tools::getValue('fieldsBox')))
  794. $fields = array();
  795. $object = new $this->className();
  796. if (!$object->addFieldsRequiredDatabase($fields))
  797. $this->_errors[] = Tools::displayError('Error in updating required fields');
  798. else
  799. Tools::redirectAdmin(self::$currentIndex.'&conf=4&token='.$token);
  800. }
  801. }
  802. protected function updateAssoShop($id_object = false)
  803. {
  804. if (!Shop::isFeatureActive())
  805. return ;
  806. if (!$assos = AdminTab::getAssoShop($this->table, $id_object))
  807. return;
  808. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.$this->table.'_'.$assos[1].($id_object ? ' WHERE `'.$this->identifier.'`='.(int)$id_object : ''));
  809. foreach ($assos[0] as $asso)
  810. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.$this->table.'_'.$assos[1].' (`'.pSQL($this->identifier).'`, id_'.$assos[1].')
  811. VALUES('.(int)$asso['id_object'].', '.(int)$asso['id_'.$assos[1]].')');
  812. }
  813. protected static function getAssoShop($table, $id_object = false)
  814. {
  815. if (Shop::isTableAssociated($table))
  816. $type = 'shop';
  817. else
  818. return;
  819. $assos = array();
  820. foreach ($_POST as $k => $row)
  821. {
  822. if (!preg_match('/^checkBox'.Tools::toCamelCase($type, true).'Asso_'.$table.'_([0-9]+)?_([0-9]+)$/Ui', $k, $res))
  823. continue;
  824. $id_asso_object = (!empty($res[1]) ? $res[1] : $id_object);
  825. $assos[] = array('id_object' => (int)$id_asso_object, 'id_'.$type => (int)$res[2]);
  826. }
  827. return array($assos, $type);
  828. }
  829. /**
  830. * Update options and preferences
  831. *
  832. * @param string $token
  833. */
  834. protected function updateOptions($token)
  835. {
  836. if ($this->tabAccess['edit'] === '1')
  837. {
  838. $this->beforeUpdateOptions();
  839. $languages = Language::getLanguages(false);
  840. foreach ($this->optionsList as $category => $categoryData)
  841. {
  842. $fields = $categoryData['fields'];
  843. /* Check required fields */
  844. foreach ($fields as $field => $values)
  845. if (isset($values['required']) && $values['required'] && !empty($_POST['multishopOverrideOption'][$field]))
  846. if (isset($values['type']) && $values['type'] == 'textLang')
  847. {
  848. foreach ($languages as $language)
  849. if (($value = Tools::getValue($field.'_'.$language['id_lang'])) == false && (string)$value != '0')
  850. $this->_errors[] = sprintf(Tools::displayError('field %s is required.'), $values['title']);
  851. }
  852. elseif (($value = Tools::getValue($field)) == false && (string)$value != '0')
  853. $this->_errors[] = sprintf(Tools::displayError('field %s is required.'), $values['title']);
  854. /* Check fields validity */
  855. foreach ($fields as $field => $values)
  856. if (isset($values['type']) && $values['type'] == 'textLang')
  857. {
  858. foreach ($languages as $language)
  859. if (Tools::getValue($field.'_'.$language['id_lang']) && isset($values['validation']))
  860. if (!Validate::$values['validation'](Tools::getValue($field.'_'.$language['id_lang'])))
  861. $this->_errors[] = sprintf(Tools::displayError('field %s is invalid.'), $values['title']);
  862. }
  863. elseif (Tools::getValue($field) && isset($values['validation']))
  864. if (!Validate::$values['validation'](Tools::getValue($field)))
  865. $this->_errors[] = sprintf(Tools::displayError('field %s is invalid.'), $values['title']);
  866. /* Default value if null */
  867. foreach ($fields as $field => $values)
  868. if (!Tools::getValue($field) && isset($values['default']))
  869. $_POST[$field] = $values['default'];
  870. if (!count($this->_errors))
  871. {
  872. foreach ($fields as $key => $options)
  873. {
  874. if (isset($options['visibility']) && $options['visibility'] > Shop::getContext())
  875. continue;
  876. if (Shop::isFeatureActive() && empty($_POST['multishopOverrideOption'][$key]))
  877. {
  878. Configuration::deleteFromContext($key);
  879. continue;
  880. }
  881. // check if a method updateOptionFieldName is available
  882. $method_name = 'updateOption'.Tools::toCamelCase($key, true);
  883. if (method_exists($this, $method_name))
  884. $this->$method_name(Tools::getValue($key));
  885. else if (isset($options['type']) && in_array($options['type'], array('textLang', 'textareaLang')))
  886. {
  887. $list = array();
  888. foreach ($languages as $language)
  889. {
  890. $val = (isset($options['cast']) ? $options['cast'](Tools::getValue($key.'_'.$language['id_lang'])) : Tools::getValue($key.'_'.$language['id_lang']));
  891. if ($this->validateField($val, $options))
  892. {
  893. if (Validate::isCleanHtml($val))
  894. $list[$language['id_lang']] = $val;
  895. else
  896. $this->_errors[] = Tools::displayError('Can not add configuration '.$key.' for lang '.Language::getIsoById((int)$language['id_lang']));
  897. }
  898. }
  899. Configuration::updateValue($key, $list);
  900. }
  901. else
  902. {
  903. $val = (isset($options['cast']) ? $options['cast'](Tools::getValue($key)) : Tools::getValue($key));
  904. if ($this->validateField($val, $options))
  905. {
  906. if (Validate::isCleanHtml($val))
  907. Configuration::updateValue($key, $val);
  908. else
  909. $this->_errors[] = Tools::displayError('Can not add configuration '.$key);
  910. }
  911. }
  912. }
  913. }
  914. }
  915. if (count($this->_errors) <= 0)
  916. Tools::redirectAdmin(self::$currentIndex.'&conf=6&token='.$token);
  917. }
  918. else
  919. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  920. }
  921. /**
  922. * Can be overriden
  923. */
  924. public function beforeUpdateOptions()
  925. {
  926. }
  927. protected function validateField($value, $field)
  928. {
  929. if (isset($field['validation']))
  930. {
  931. if ((!isset($field['empty']) || !$field['empty'] || (isset($field['empty']) && $field['empty'] && $value)) && method_exists('Validate', $field['validation']))
  932. {
  933. if (!Validate::$field['validation']($value))
  934. {
  935. $this->_errors[] = Tools::displayError($field['title'].' : Incorrect value');
  936. return false;
  937. }
  938. }
  939. }
  940. return true;
  941. }
  942. protected function uploadImage($id, $name, $dir, $ext = false, $width = NULL, $height = NULL)
  943. {
  944. if (isset($_FILES[$name]['tmp_name']) && !empty($_FILES[$name]['tmp_name']))
  945. {
  946. // Delete old image
  947. if (Validate::isLoadedObject($object = $this->loadObject()))
  948. $object->deleteImage();
  949. else
  950. return false;
  951. // Check image validity
  952. $max_size = isset($this->maxImageSize) ? $this->maxImageSize : 0;
  953. if ($error = ImageManager::validateUpload($_FILES[$name], Tools::getMaxUploadSize($max_size)))
  954. $this->_errors[] = $error;
  955. elseif (!($tmpName = tempnam(_PS_TMP_IMG_DIR_, 'PS')) || !move_uploaded_file($_FILES[$name]['tmp_name'], $tmpName))
  956. return false;
  957. else
  958. {
  959. $_FILES[$name]['tmp_name'] = $tmpName;
  960. // Copy new image
  961. if (!ImageManager::resize($tmpName, _PS_IMG_DIR_.$dir.$id.'.'.$this->imageType, (int)$width, (int)$height, ($ext ? $ext : $this->imageType)))
  962. $this->_errors[] = Tools::displayError('An error occurred while uploading image.');
  963. if (count($this->_errors))
  964. return false;
  965. if ($this->afterImageUpload())
  966. {
  967. unlink($tmpName);
  968. return true;
  969. }
  970. return false;
  971. }
  972. }
  973. return true;
  974. }
  975. /**
  976. * Overload this method for custom checking
  977. *
  978. * @param integer $id Object id used for deleting images
  979. * @return boolean
  980. */
  981. protected function postImage($id)
  982. {
  983. if (isset($this->fieldImageSettings['name']) && isset($this->fieldImageSettings['dir']))
  984. return $this->uploadImage($id, $this->fieldImageSettings['name'], $this->fieldImageSettings['dir'].'/');
  985. elseif (!empty($this->fieldImageSettings))
  986. foreach ($this->fieldImageSettings as $image)
  987. if (isset($image['name']) && isset($image['dir']))
  988. $this->uploadImage($id, $image['name'], $image['dir'].'/');
  989. return !count($this->_errors) ? true : false;
  990. }
  991. /**
  992. * Copy datas from $_POST to object
  993. *
  994. * @param object &$object Object
  995. * @param string $table Object table
  996. */
  997. protected function copyFromPost(&$object, $table)
  998. {
  999. /* Classical fields */
  1000. foreach ($_POST as $key => $value)
  1001. if (key_exists($key, $object) && $key != 'id_'.$table)
  1002. {
  1003. /* Do not take care of password field if empty */
  1004. if ($key == 'passwd' && Tools::getValue('id_'.$table) && empty($value))
  1005. continue;
  1006. /* Automatically encrypt password in MD5 */
  1007. if ($key == 'passwd' && !empty($value))
  1008. $value = Tools::encrypt($value);
  1009. $object->{$key} = $value;
  1010. }
  1011. /* Multilingual fields */
  1012. $rules = call_user_func(array(get_class($object), 'getValidationRules'), get_class($object));
  1013. if (count($rules['validateLang']))
  1014. {
  1015. $languages = Language::getLanguages(false);
  1016. foreach ($languages as $language)
  1017. foreach (array_keys($rules['validateLang']) as $field)
  1018. if (isset($_POST[$field.'_'.(int)($language['id_lang'])]))
  1019. $object->{$field}[(int)($language['id_lang'])] = $_POST[$field.'_'.(int)($language['id_lang'])];
  1020. }
  1021. }
  1022. /**
  1023. * Display errors
  1024. */
  1025. public function displayErrors()
  1026. {
  1027. if ($nbErrors = count($this->_errors) && $this->_includeContainer)
  1028. {
  1029. echo '<script type="text/javascript">
  1030. $(document).ready(function() {
  1031. $(\'#hideError\').unbind(\'click\').click(function(){
  1032. $(\'.error\').hide(\'slow\', function (){
  1033. $(\'.error\').remove();
  1034. });
  1035. return false;
  1036. });
  1037. });
  1038. </script>
  1039. <div class="error"><span style="float:right"><a id="hideError" href=""><img alt="X" src="../img/admin/close.png" /></a></span><img src="../img/admin/error2.png" />';
  1040. if (count($this->_errors) == 1)
  1041. echo $this->_errors[0];
  1042. else
  1043. {
  1044. echo sprintf($this->l('%d errors'), $nbErrors).'<br /><ol>';
  1045. foreach ($this->_errors as $error)
  1046. echo '<li>'.$error.'</li>';
  1047. echo '</ol>';
  1048. }
  1049. echo '</div>';
  1050. }
  1051. $this->includeSubTab('displayErrors');
  1052. }
  1053. /**
  1054. * Display a warning message
  1055. *
  1056. * @param string $warn Warning message to display
  1057. */
  1058. public function displayWarning($warn)
  1059. {
  1060. $str_output = '';
  1061. if (!empty($warn))
  1062. {
  1063. $str_output .= '<script type="text/javascript">
  1064. $(document).ready(function() {
  1065. $(\'#linkSeeMore\').unbind(\'click\').click(function(){
  1066. $(\'#seeMore\').show(\'slow\');
  1067. $(this).hide();
  1068. $(\'#linkHide\').show();
  1069. return false;
  1070. });
  1071. $(\'#linkHide\').unbind(\'click\').click(function(){
  1072. $(\'#seeMore\').hide(\'slow\');
  1073. $(this).hide();
  1074. $(\'#linkSeeMore\').show();
  1075. return false;
  1076. });
  1077. $(\'#hideWarn\').unbind(\'click\').click(function(){
  1078. $(\'.warn\').hide(\'slow\', function (){
  1079. $(\'.warn\').remove();
  1080. });
  1081. return false;
  1082. });
  1083. });
  1084. </script>
  1085. <div class="warn">';
  1086. if (!is_array($warn))
  1087. $str_output .= '<img src="../img/admin/warn2.png" />'.$warn;
  1088. else
  1089. { $str_output .= '<span style="float:right"><a id="hideWarn" href=""><img alt="X" src="../img/admin/close.png" /></a></span><img src="../img/admin/warn2.png" />'.
  1090. (count($warn) > 1 ? $this->l('There are') : $this->l('There is')).' '.count($warn).' '.(count($warn) > 1 ? $this->l('warnings') : $this->l('warning'))
  1091. .'<span style="margin-left:20px;" id="labelSeeMore">
  1092. <a id="linkSeeMore" href="#" style="text-decoration:underline">'.$this->l('Click here to see more').'</a>
  1093. <a id="linkHide" href="#" style="text-decoration:underline;display:none">'.$this->l('Hide warning').'</a></span><ul style="display:none;" id="seeMore">';
  1094. foreach($warn as $val)
  1095. $str_output .= '<li>'.$val.'</li>';
  1096. $str_output .= '</ul>';
  1097. }
  1098. $str_output .= '</div>';
  1099. }
  1100. echo $str_output;
  1101. }
  1102. /**
  1103. * Display confirmations
  1104. */
  1105. public function displayConf()
  1106. {
  1107. if ($conf = Tools::getValue('conf'))
  1108. echo '
  1109. <div class="conf">
  1110. '.$this->_conf[(int)($conf)].'
  1111. </div>';
  1112. }
  1113. /**
  1114. * Get the current objects' list form the database
  1115. *
  1116. * @param integer $id_lang Language used for display
  1117. * @param string $orderBy ORDER BY clause
  1118. * @param string $_orderWay Order way (ASC, DESC)
  1119. * @param integer $start Offset in LIMIT clause
  1120. * @param integer $limit Row count in LIMIT clause
  1121. */
  1122. public function getList($id_lang, $orderBy = NULL, $orderWay = NULL, $start = 0, $limit = NULL, $id_lang_shop = false)
  1123. {
  1124. /* Manage default params values */
  1125. if (empty($limit))
  1126. $limit = ((!isset($this->context->cookie->{$this->table.'_pagination'})) ? $this->_pagination[1] : $limit = $this->context->cookie->{$this->table.'_pagination'});
  1127. if (!Validate::isTableOrIdentifier($this->table))
  1128. $this->_errors[] = Tools::displayError('Table name is invalid:').' "'.$this->table.'"';
  1129. if (empty($orderBy))
  1130. $orderBy = $this->context->cookie->__get($this->table.'Orderby') ? $this->context->cookie->__get($this->table.'Orderby') : $this->_defaultOrderBy;
  1131. if (empty($orderWay))
  1132. $orderWay = $this->context->cookie->__get($this->table.'Orderway') ? $this->context->cookie->__get($this->table.'Orderway') : 'ASC';
  1133. $limit = (int)(Tools::getValue('pagination', $limit));
  1134. $this->context->cookie->{$this->table.'_pagination'} = $limit;
  1135. /* Check params validity */
  1136. if (!Validate::isOrderBy($orderBy) || !Validate::isOrderWay($orderWay)
  1137. OR !is_numeric($start) || !is_numeric($limit)
  1138. OR !Validate::isUnsignedId($id_lang))
  1139. die(Tools::displayError('get list params is not valid'));
  1140. /* Determine offset from current page */
  1141. if ((isset($_POST['submitFilter'.$this->table]) OR
  1142. isset($_POST['submitFilter'.$this->table.'_x']) OR
  1143. isset($_POST['submitFilter'.$this->table.'_y'])) AND
  1144. !empty($_POST['submitFilter'.$this->table]) AND
  1145. is_numeric($_POST['submitFilter'.$this->table]))
  1146. $start = (int)($_POST['submitFilter'.$this->table] - 1) * $limit;
  1147. /* Cache */
  1148. $this->_lang = (int)($id_lang);
  1149. $this->_orderBy = $orderBy;
  1150. $this->_orderWay = Tools::strtoupper($orderWay);
  1151. /* SQL table : orders, but class name is Order */
  1152. $sqlTable = $this->table == 'order' ? 'orders' : $this->table;
  1153. // Add SQL shop restriction
  1154. $selectShop = $joinShop = $whereShop = '';
  1155. if ($this->shopLinkType)
  1156. {
  1157. $selectShop = ', shop.name as shop_name ';
  1158. $joinShop = ' LEFT JOIN '._DB_PREFIX_.$this->shopLinkType.' shop
  1159. ON a.id_'.$this->shopLinkType.' = shop.id_'.$this->shopLinkType;
  1160. $whereShop = Shop::addSqlRestriction($this->shopShareDatas, 'a', $this->shopLinkType);
  1161. }
  1162. $asso = Shop::getAssoTable($this->table);
  1163. if ($asso !== false && $assos['type'] == 'shop')
  1164. {
  1165. $filterKey = $asso['type'];
  1166. $idenfierShop = Shop::getContextListShopID();
  1167. }
  1168. $filterShop = '';
  1169. if (isset($filterKey))
  1170. {
  1171. if (!$this->_group)
  1172. $this->_group = 'GROUP BY a.'.pSQL($this->identifier);
  1173. else if (!preg_match('#(\s|,)\s*a\.`?'.pSQL($this->identifier).'`?(\s|,|$)#', $this->_group))
  1174. $this->_group .= ', a.'.pSQL($this->identifier);
  1175. if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL && !preg_match('#`?'.preg_quote(_DB_PREFIX_.$this->table.'_'.$filterKey).'`? *sa#', $this->_join))
  1176. $filterShop = 'JOIN `'._DB_PREFIX_.$this->table.'_'.$filterKey.'` sa ON (sa.'.$this->identifier.' = a.'.$this->identifier.' AND sa.id_'.$filterKey.' IN ('.implode(', ', $idenfierShop).'))';
  1177. }
  1178. ///////////////////////
  1179. /* Query in order to get results with all fields */
  1180. $sql = 'SELECT SQL_CALC_FOUND_ROWS
  1181. '.($this->_tmpTableFilter ? ' * FROM (SELECT ' : '').'
  1182. '.($this->lang ? 'b.*, ' : '').'a.*'.(isset($this->_select) ? ', '.$this->_select.' ' : '').$selectShop.'
  1183. FROM `'._DB_PREFIX_.$sqlTable.'` a
  1184. '.$filterShop.'
  1185. '.($this->lang ? 'LEFT JOIN `'._DB_PREFIX_.$this->table.'_lang` b ON (b.`'.$this->identifier.'` = a.`'.$this->identifier.'` AND b.`id_lang` = '.(int)$id_lang.($id_lang_shop ? ' AND b.`id_shop`='.(int)$id_lang_shop : '').')' : '').'
  1186. '.(isset($this->_join) ? $this->_join.' ' : '').'
  1187. '.$joinShop.'
  1188. WHERE 1 '.(isset($this->_where) ? $this->_where.' ' : '').($this->deleted ? 'AND a.`deleted` = 0 ' : '').(isset($this->_filter) ? $this->_filter : '').$whereShop.'
  1189. '.(isset($this->_group) ? $this->_group.' ' : '').'
  1190. '.((isset($this->_filterHaving) || isset($this->_having)) ? 'HAVING ' : '').(isset($this->_filterHaving) ? ltrim($this->_filterHaving, ' AND ') : '').(isset($this->_having) ? $this->_having.' ' : '').'
  1191. ORDER BY '.(($orderBy == $this->identifier) ? 'a.' : '').'`'.pSQL($orderBy).'` '.pSQL($orderWay).
  1192. ($this->_tmpTableFilter ? ') tmpTable WHERE 1'.$this->_tmpTableFilter : '').'
  1193. LIMIT '.(int)$start.','.(int)$limit;
  1194. $this->_list = Db::getInstance()->executeS($sql);
  1195. $this->_listTotal = Db::getInstance()->getValue('SELECT FOUND_ROWS() AS `'._DB_PREFIX_.$this->table.'`');
  1196. }
  1197. /**
  1198. * Display image aside object form
  1199. *
  1200. * @param integer $id Object id
  1201. * @param string $image Local image filepath
  1202. * @param integer $size Image width
  1203. * @param integer $id_image Image id (for products with several images)
  1204. * @param string $token Employee token used in the image deletion link
  1205. * @param boolean $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache
  1206. */
  1207. public function displayImage($id, $image, $size, $id_image = NULL, $token = NULL, $disableCache = false)
  1208. {
  1209. if (!isset($token) || empty($token))
  1210. $token = $this->token;
  1211. if ($id && file_exists($image))
  1212. echo '
  1213. <div id="image" >
  1214. '.ImageManager::thumbnail($image, $this->table.'_'.(int)($id).'.'.$this->imageType, $size, $this->imageType, $disableCache).'
  1215. <p align="center">'.$this->l('File size').' '.(filesize($image) / 1000).'kb</p>
  1216. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.(int)($id).'&token='.$token.($id_image ? '&id_image='.(int)($id_image) : '').'&deleteImage=1">
  1217. <img src="../img/admin/delete.gif" alt="'.$this->l('Delete').'" /> '.$this->l('Delete').'</a>
  1218. </div>';
  1219. }
  1220. /**
  1221. * Display list header (filtering, pagination and column names)
  1222. */
  1223. public function displayListHeader($token = NULL)
  1224. {
  1225. $isCms = false;
  1226. if (preg_match('/cms/Ui', $this->identifier))
  1227. $isCms = true;
  1228. $id_cat = Tools::getValue('id_'.($isCms ? 'cms_' : '').'category');
  1229. if (!isset($token) || empty($token))
  1230. $token = $this->token;
  1231. /* Determine total page number */
  1232. $totalPages = ceil($this->_listTotal / Tools::getValue('pagination', (isset($this->context->cookie->{$this->table.'_pagination'}) ? $this->context->cookie->{$this->table.'_pagination'} : $this->_pagination[0])));
  1233. if (!$totalPages) $totalPages = 1;
  1234. echo '<a name="'.$this->table.'">&nbsp;</a>';
  1235. echo '<form method="post" action="'.self::$currentIndex;
  1236. if(Tools::getIsset($this->identifier))
  1237. echo '&'.$this->identifier.'='.(int)(Tools::getValue($this->identifier));
  1238. echo '&token='.$token;
  1239. if (Tools::getIsset($this->table.'Orderby'))
  1240. echo '&'.$this->table.'Orderby='.urlencode($this->_orderBy).'&'.$this->table.'Orderway='.urlencode(strtolower($this->_orderWay));
  1241. echo '#'.$this->table.'" class="form">
  1242. <input type="hidden" id="submitFilter'.$this->table.'" name="submitFilter'.$this->table.'" value="0">
  1243. <table>
  1244. <tr>
  1245. <td style="vertical-align: bottom;">
  1246. <span style="float: left;">';
  1247. /* Determine current page number */
  1248. $page = (int)(Tools::getValue('submitFilter'.$this->table));
  1249. if (!$page) $page = 1;
  1250. if ($page > 1)
  1251. echo '
  1252. <input type="image" src="../img/admin/list-prev2.gif" onclick="getE(\'submitFilter'.$this->table.'\').value=1"/>
  1253. &nbsp; <input type="image" src="../img/admin/list-prev.gif" onclick="getE(\'submitFilter'.$this->table.'\').value='.($page - 1).'"/> ';
  1254. echo $this->l('Page').' <b>'.$page.'</b> / '.$totalPages;
  1255. if ($page < $totalPages)
  1256. echo '
  1257. <input type="image" src="../img/admin/list-next.gif" onclick="getE(\'submitFilter'.$this->table.'\').value='.($page + 1).'"/>
  1258. &nbsp;<input type="image" src="../img/admin/list-next2.gif" onclick="getE(\'submitFilter'.$this->table.'\').value='.$totalPages.'"/>';
  1259. echo ' | '.$this->l('Display').'
  1260. <select name="pagination">';
  1261. /* Choose number of results per page */
  1262. $selectedPagination = Tools::getValue('pagination', (isset($this->context->cookie->{$this->table.'_pagination'}) ? $this->context->cookie->{$this->table.'_pagination'} : NULL));
  1263. foreach ($this->_pagination as $value)
  1264. echo '<option value="'.(int)($value).'"'.($selectedPagination == $value ? ' selected="selected"' : (($selectedPagination == NULL && $value == $this->_pagination[1]) ? ' selected="selected2"' : '')).'>'.(int)($value).'</option>';
  1265. echo '
  1266. </select>
  1267. / '.(int)($this->_listTotal).' '.$this->l('result(s)').'
  1268. </span>
  1269. <span style="float: right;">
  1270. <input type="submit" name="submitReset'.$this->table.'" value="'.$this->l('Reset').'" class="button" />
  1271. <input type="submit" id="submitFilterButton_'.$this->table.'" name="submitFilter" value="'.$this->l('Filter').'" class="button" />
  1272. </span>
  1273. <span class="clear"></span>
  1274. </td>
  1275. </tr>
  1276. <tr>
  1277. <td>';
  1278. /* Display column names and arrows for ordering (ASC, DESC) */
  1279. if (array_key_exists($this->identifier,$this->identifiersDnd) && $this->_orderBy == 'position')
  1280. {
  1281. echo '
  1282. <script type="text/javascript" src="../js/jquery/jquery.tablednd_0_5.js"></script>
  1283. <script type="text/javascript">
  1284. var token = \''.($token!=NULL ? $token : $this->token).'\';
  1285. var come_from = \''.$this->table.'\';
  1286. var alternate = \''.($this->_orderWay == 'DESC' ? '1' : '0' ).'\';
  1287. </script>
  1288. <script type="text/javascript" src="../js/admin-dnd.js"></script>
  1289. ';
  1290. }
  1291. echo '<table'.(array_key_exists($this->identifier,$this->identifiersDnd) ? ' id="'.(((int)(Tools::getValue($this->identifiersDnd[$this->identifier], 1))) ? substr($this->identifier,3,strlen($this->identifier)) : '').'"' : '' ).' class="table'.((array_key_exists($this->identifier,$this->identifiersDnd) && ($this->_orderBy != 'position 'AND $this->_orderWay != 'DESC')) ? ' tableDnD' : '' ).'" cellpadding="0" cellspacing="0">
  1292. <thead>
  1293. <tr class="nodrag nodrop">
  1294. <th>';
  1295. if ($this->delete)
  1296. echo ' <input type="checkbox" name="checkme" class="noborder" onclick="checkDelBoxes(this.form, \''.$this->table.'Box[]\', this.checked)" />';
  1297. echo ' </th>';
  1298. foreach ($this->fieldsDisplay as $key => $params)
  1299. {
  1300. echo ' <th '.(isset($params['widthColumn']) ? 'style="width: '.$params['widthColumn'].'px"' : '').'>'.$params['title'];
  1301. if (!isset($params['orderby']) || $params['orderby'])
  1302. {
  1303. // Cleaning links
  1304. if (Tools::getValue($this->table.'Orderby') && Tools::getValue($this->table.'Orderway'))
  1305. self::$currentIndex = preg_replace('/&'.$this->table.'Orderby=([a-z _]*)&'.$this->table.'Orderway=([a-z]*)/i', '', self::$currentIndex);
  1306. echo ' <br />
  1307. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id_cat.'&'.$this->table.'Orderby='.urlencode($key).'&'.$this->table.'Orderway=desc&token='.$token.'"><img border="0" src="../img/admin/down'.((isset($this->_orderBy) && ($key == $this->_orderBy) && ($this->_orderWay == 'DESC')) ? '_d' : '').'.gif" /></a>
  1308. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id_cat.'&'.$this->table.'Orderby='.urlencode($key).'&'.$this->table.'Orderway=asc&token='.$token.'"><img border="0" src="../img/admin/up'.((isset($this->_orderBy) && ($key == $this->_orderBy) && ($this->_orderWay == 'ASC')) ? '_d' : '').'.gif" /></a>';
  1309. }
  1310. echo ' </th>';
  1311. }
  1312. if ($this->shopLinkType)
  1313. {
  1314. echo '<th style="width: 80px">'.$this->l(($this->shopLinkType == 'shop') ? 'Shop' : 'Group shop').'</th>';
  1315. }
  1316. /* Check if object can be modified, deleted or detailed */
  1317. if ($this->edit || $this->delete || ($this->view && $this->view !== 'noActionColumn'))
  1318. echo ' <th style="width: 52px">'.$this->l('Actions').'</th>';
  1319. echo ' </tr>
  1320. <tr class="nodrag nodrop" style="height: 35px;">
  1321. <td class="center">';
  1322. if ($this->delete)
  1323. echo ' --';
  1324. echo ' </td>';
  1325. /* Javascript hack in order to catch ENTER keypress event */
  1326. $keyPress = 'onkeypress="formSubmit(event, \'submitFilterButton_'.$this->table.'\');"';
  1327. /* Filters (input, select, date or bool) */
  1328. foreach ($this->fieldsDisplay as $key => $params)
  1329. {
  1330. $width = (isset($params['width']) ? ' style="width: '.(int)($params['width']).'px;"' : '');
  1331. echo '<td'.(isset($params['align']) ? ' class="'.$params['align'].'"' : '').'>';
  1332. if (!isset($params['type']))
  1333. $params['type'] = 'text';
  1334. $value = Tools::getValue($this->table.'Filter_'.(array_key_exists('filter_key', $params) ? $params['filter_key'] : $key));
  1335. if (isset($params['search']) && !$params['search'])
  1336. {
  1337. echo '--</td>';
  1338. continue;
  1339. }
  1340. switch ($params['type'])
  1341. {
  1342. case 'bool':
  1343. echo '
  1344. <select name="'.$this->table.'Filter_'.$key.'">
  1345. <option value="">--</option>
  1346. <option value="1"'.($value == 1 ? ' selected="selected"' : '').'>'.$this->l('Yes').'</option>
  1347. <option value="0"'.(($value == 0 && $value != '') ? ' selected="selected"' : '').'>'.$this->l('No').'</option>
  1348. </select>';
  1349. break;
  1350. case 'date':
  1351. case 'datetime':
  1352. if (is_string($value))
  1353. $value = Tools::unSerialize($value);
  1354. if (!Validate::isCleanHtml($value[0]) || !Validate::isCleanHtml($value[1]))
  1355. $value = '';
  1356. $name = $this->table.'Filter_'.(isset($params['filter_key']) ? $params['filter_key'] : $key);
  1357. $nameId = str_replace('!', '__', $name);
  1358. includeDatepicker(array($nameId.'_0', $nameId.'_1'));
  1359. echo $this->l('From').' <input type="text" id="'.$nameId.'_0" name="'.$name.'[0]" value="'.(isset($value[0]) ? $value[0] : '').'"'.$width.' '.$keyPress.' /><br />
  1360. '.$this->l('To').' <input type="text" id="'.$nameId.'_1" name="'.$name.'[1]" value="'.(isset($value[1]) ? $value[1] : '').'"'.$width.' '.$keyPress.' />';
  1361. break;
  1362. case 'select':
  1363. if (isset($params['filter_key']))
  1364. {
  1365. echo '<select onchange="$(\'#submitFilter'.$this->table.'\').focus();$(\'#submitFilter'.$this->table.'\').click();" name="'.$this->table.'Filter_'.$params['filter_key'].'" '.(isset($params['width']) ? 'style="width: '.$params['width'].'px"' : '').'>
  1366. <option value=""'.(($value == 0 && $value != '') ? ' selected="selected"' : '').'>--</option>';
  1367. if (isset($params['select']) && is_array($params['select']))
  1368. foreach ($params['select'] as $optionValue => $optionDisplay)
  1369. {
  1370. echo '<option value="'.$optionValue.'"'.((isset($_POST[$this->table.'Filter_'.$params['filter_key']]) && Tools::getValue($this->table.'Filter_'.$params['filter_key']) == $optionValue && Tools::getValue($this->table.'Filter_'.$params['filter_key']) != '') ? ' selected="selected"' : '').'>'.$optionDisplay.'</option>';
  1371. }
  1372. echo '</select>';
  1373. break;
  1374. }
  1375. case 'text':
  1376. default:
  1377. if (!Validate::isCleanHtml($value))
  1378. $value = '';
  1379. echo '<input type="text" name="'.$this->table.'Filter_'.(isset($params['filter_key']) ? $params['filter_key'] : $key).'" value="'.htmlentities($value, ENT_COMPAT, 'UTF-8').'"'.$width.' '.$keyPress.' />';
  1380. }
  1381. echo '</td>';
  1382. }
  1383. if ($this->shopLinkType)
  1384. {
  1385. echo '<td>--</td>';
  1386. }
  1387. if ($this->edit || $this->delete || ($this->view && $this->view !== 'noActionColumn'))
  1388. echo '<td class="center">--</td>';
  1389. echo '</tr>
  1390. </thead>';
  1391. }
  1392. public function displayTop()
  1393. {
  1394. }
  1395. /**
  1396. * Display list
  1397. */
  1398. public function displayList()
  1399. {
  1400. $this->displayTop();
  1401. if ($this->edit && (!isset($this->noAdd) || !$this->noAdd))
  1402. $this->displayAddButton();
  1403. /* Append when we get a syntax error in SQL query */
  1404. if ($this->_list === false)
  1405. {
  1406. $this->displayWarning($this->l('Bad SQL query'));
  1407. return false;
  1408. }
  1409. /* Display list header (filtering, pagination and column names) */
  1410. $this->displayListHeader();
  1411. if (!count($this->_list))
  1412. echo '<tr><td class="center" colspan="'.(count($this->fieldsDisplay) + 2).'">'.$this->l('No items found').'</td></tr>';
  1413. /* Show the content of the table */
  1414. $this->displayListContent();
  1415. /* Close list table and submit button */
  1416. $this->displayListFooter();
  1417. }
  1418. public function displayListContent($token = NULL)
  1419. {
  1420. /* Display results in a table
  1421. *
  1422. * align : determine value alignment
  1423. * prefix : displayed before value
  1424. * suffix : displayed after value
  1425. * image : object image
  1426. * icon : icon determined by values
  1427. * active : allow to toggle status
  1428. */
  1429. $id_category = 1; // default categ
  1430. $irow = 0;
  1431. if ($this->_list && isset($this->fieldsDisplay['position']))
  1432. {
  1433. $positions = array_map(create_function('$elem', 'return (int)$elem[\'position\'];'), $this->_list);
  1434. sort($positions);
  1435. }
  1436. if ($this->_list)
  1437. {
  1438. $isCms = false;
  1439. if (preg_match('/cms/Ui', $this->identifier))
  1440. $isCms = true;
  1441. $keyToGet = 'id_'.($isCms ? 'cms_' : '').'category'.(in_array($this->identifier, array('id_category', 'id_cms_category')) ? '_parent' : '');
  1442. foreach ($this->_list as $tr)
  1443. {
  1444. $id = $tr[$this->identifier];
  1445. echo '<tr'.(array_key_exists($this->identifier,$this->identifiersDnd) ? ' id="tr_'.(($id_category = (int)(Tools::getValue('id_'.($isCms ? 'cms_' : '').'category', '1'))) ? $id_category : '').'_'.$id.'_'.$tr['position'].'"' : '').($irow++ % 2 ? ' class="alt_row"' : '').' '.((isset($tr['color']) && $this->colorOnBackground) ? 'style="background-color: '.$tr['color'].'"' : '').'>
  1446. <td class="center">';
  1447. if ($this->delete && (!isset($this->_listSkipDelete) || !in_array($id, $this->_listSkipDelete)))
  1448. echo '<input type="checkbox" name="'.$this->table.'Box[]" value="'.$id.'" class="noborder" />';
  1449. echo '</td>';
  1450. foreach ($this->fieldsDisplay as $key => $params)
  1451. {
  1452. $tmp = explode('!', $key);
  1453. $key = isset($tmp[1]) ? $tmp[1] : $tmp[0];
  1454. echo '
  1455. <td '.(isset($params['position']) ? ' id="td_'.(isset($id_category) && $id_category ? $id_category : 0).'_'.$id.'"' : '').' class="'.((!isset($this->noLink) || !$this->noLink) ? 'pointer' : '').((isset($params['position']) && $this->_orderBy == 'position')? ' dragHandle' : ''). (isset($params['align']) ? ' '.$params['align'] : '').'" ';
  1456. if (!isset($params['position']) && (!isset($this->noLink) || !$this->noLink))
  1457. echo ' onclick="document.location = \''.self::$currentIndex.'&'.$this->identifier.'='.$id.($this->view? '&view' : '&update').$this->table.'&token='.($token!=NULL ? $token : $this->token).'\'">'.(isset($params['prefix']) ? $params['prefix'] : '');
  1458. else
  1459. echo '>';
  1460. if (isset($params['active']) && isset($tr[$key]))
  1461. $this->_displayEnableLink($token, $id, $tr[$key], $params['active'], Tools::getValue('id_category'), Tools::getValue('id_product'));
  1462. elseif (isset($params['activeVisu']) && isset($tr[$key]))
  1463. echo '<img src="../img/admin/'.($tr[$key] ? 'enabled.gif' : 'disabled.gif').'"
  1464. alt="'.($tr[$key] ? $this->l('Enabled') : $this->l('Disabled')).'" title="'.($tr[$key] ? $this->l('Enabled') : $this->l('Disabled')).'" />';
  1465. elseif (isset($params['position']))
  1466. {
  1467. if ($this->_orderBy == 'position' && $this->_orderWay != 'DESC')
  1468. {
  1469. echo '<a'.(!($tr[$key] != $positions[count($positions) - 1]) ? ' style="display: none;"' : '').' href="'.self::$currentIndex.
  1470. '&'.$keyToGet.'='.(int)($id_category).'&'.$this->identifiersDnd[$this->identifier].'='.$id.'
  1471. &way=1&position='.(int)($tr['position'] + 1).'&token='.($token!=NULL ? $token : $this->token).'">
  1472. <img src="../img/admin/'.($this->_orderWay == 'ASC' ? 'down' : 'up').'.gif"
  1473. alt="'.$this->l('Down').'" title="'.$this->l('Down').'" /></a>';
  1474. echo '<a'.(!($tr[$key] != $positions[0]) ? ' style="display: none;"' : '').' href="'.self::$currentIndex.
  1475. '&'.$keyToGet.'='.(int)($id_category).'&'.$this->identifiersDnd[$this->identifier].'='.$id.'
  1476. &way=0&position='.(int)($tr['position'] - 1).'&token='.($token!=NULL ? $token : $this->token).'">
  1477. <img src="../img/admin/'.($this->_orderWay == 'ASC' ? 'up' : 'down').'.gif"
  1478. alt="'.$this->l('Up').'" title="'.$this->l('Up').'" /></a>';
  1479. }
  1480. else
  1481. echo (int)($tr[$key] + 1);
  1482. }
  1483. elseif (isset($params['image']))
  1484. {
  1485. // item_id is the product id in a product image context, else it is the image id.
  1486. $item_id = isset($params['image_id']) ? $tr[$params['image_id']] : $id;
  1487. // If it's a product image
  1488. if (isset($tr['id_image']))
  1489. {
  1490. $image = new Image((int)$tr['id_image']);
  1491. $path_to_image = _PS_IMG_DIR_.$params['image'].'/'.$image->getExistingImgPath().'.'.$this->imageType;
  1492. }else
  1493. $path_to_image = _PS_IMG_DIR_.$params['image'].'/'.$item_id.(isset($tr['id_image']) ? '-'.(int)($tr['id_image']) : '').'.'.$this->imageType;
  1494. echo ImageManager::thumbnail($path_to_image, $this->table.'_mini_'.$item_id.'.'.$this->imageType, 45, $this->imageType);
  1495. }
  1496. elseif (isset($params['icon']) && (isset($params['icon'][$tr[$key]]) || isset($params['icon']['default'])))
  1497. echo '<img src="../img/admin/'.(isset($params['icon'][$tr[$key]]) ? $params['icon'][$tr[$key]] : $params['icon']['default'].'" alt="'.$tr[$key]).'" title="'.$tr[$key].'" />';
  1498. elseif (isset($params['price']))
  1499. echo Tools::displayPrice($tr[$key], (isset($params['currency']) ? Currency::getCurrencyInstance($tr['id_currency']) : $this->context->currency), false);
  1500. elseif (isset($params['float']))
  1501. echo rtrim(rtrim($tr[$key], '0'), '.');
  1502. elseif (isset($params['type']) && $params['type'] == 'date')
  1503. echo Tools::displayDate($tr[$key], $this->context->language->id);
  1504. elseif (isset($params['type']) && $params['type'] == 'datetime')
  1505. echo Tools::displayDate($tr[$key], $this->context->language->id, true);
  1506. elseif (isset($tr[$key]))
  1507. {
  1508. if ($key == 'price')
  1509. $echo = round($tr[$key], 2);
  1510. else if (isset($params['maxlength']) && Tools::strlen($tr[$key]) > $params['maxlength'])
  1511. $echo = '<span title="'.$tr[$key].'">'.Tools::substr($tr[$key], 0, $params['maxlength']).'...</span>';
  1512. else
  1513. $echo = $tr[$key];
  1514. echo isset($params['callback']) ? call_user_func_array(array((isset($params['callback_object'])) ? $params['callback_object'] : $this->className, $params['callback']), array($echo, $tr)) : $echo;
  1515. }
  1516. else
  1517. echo '--';
  1518. echo (isset($params['suffix']) ? $params['suffix'] : '').
  1519. '</td>';
  1520. }
  1521. if ($this->shopLinkType)
  1522. {
  1523. $name = (Tools::strlen($tr['shop_name']) > 15) ? Tools::substr($tr['shop_name'], 0, 15).'...' : $tr['shop_name'];
  1524. echo '<td class="center" '.(($name != $tr['shop_name']) ? 'title="'.$tr['shop_name'].'"' : '').'>'.$name.'</td>';
  1525. }
  1526. if ($this->edit || $this->delete || ($this->view && $this->view !== 'noActionColumn'))
  1527. {
  1528. echo '<td class="center" style="white-space: nowrap;">';
  1529. if ($this->view)
  1530. $this->_displayViewLink($token, $id);
  1531. if ($this->edit)
  1532. $this->_displayEditLink($token, $id);
  1533. if ($this->delete && (!isset($this->_listSkipDelete) || !in_array($id, $this->_listSkipDelete)))
  1534. $this->_displayDeleteLink($token, $id);
  1535. if ($this->duplicate)
  1536. $this->_displayDuplicate($token, $id);
  1537. echo '</td>';
  1538. }
  1539. echo '</tr>';
  1540. }
  1541. }
  1542. }
  1543. protected function displayAddButton()
  1544. {
  1545. echo '<br /><a href="'.self::$currentIndex.'&add'.$this->table.'&token='.$this->token.'"><img src="../img/admin/add.gif" border="0" /> '.$this->l('Add new').'</a><br /><br />';
  1546. }
  1547. protected function _displayEnableLink($token, $id, $value, $active, $id_category = NULL, $id_product = NULL)
  1548. {
  1549. echo '<a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id.'&'.$active.$this->table.
  1550. ((int)$id_category && (int)$id_product ? '&id_category='.$id_category : '').'&token='.($token!=NULL ? $token : $this->token).'">
  1551. <img src="../img/admin/'.($value ? 'enabled.gif' : 'disabled.gif').'"
  1552. alt="'.($value ? $this->l('Enabled') : $this->l('Disabled')).'" title="'.($value ? $this->l('Enabled') : $this->l('Disabled')).'" /></a>';
  1553. }
  1554. protected function _displayDuplicate($token = NULL, $id)
  1555. {
  1556. $_cacheLang['Duplicate'] = $this->l('Duplicate');
  1557. $_cacheLang['Copy images too?'] = $this->l('Copy images too?', __CLASS__, TRUE, FALSE);
  1558. $duplicate = self::$currentIndex.'&'.$this->identifier.'='.$id.'&duplicate'.$this->table;
  1559. echo '
  1560. <a class="pointer" onclick="if (confirm(\''.$_cacheLang['Copy images too?'].'\')) document.location = \''.$duplicate.'&token='.($token!=NULL ? $token : $this->token).'\'; else document.location = \''.$duplicate.'&noimage=1&token='.($token ? $token : $this->token).'\';">
  1561. <img src="../img/admin/duplicate.png" alt="'.$_cacheLang['Duplicate'].'" title="'.$_cacheLang['Duplicate'].'" /></a>';
  1562. }
  1563. protected function _displayViewLink($token = NULL, $id)
  1564. {
  1565. $_cacheLang['View'] = $this->l('View');
  1566. echo '
  1567. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id.'&view'.$this->table.'&token='.($token!=NULL ? $token : $this->token).'">
  1568. <img src="../img/admin/details.gif" alt="'.$_cacheLang['View'].'" title="'.$_cacheLang['View'].'" /></a>';
  1569. }
  1570. protected function _displayEditLink($token = NULL, $id)
  1571. {
  1572. $_cacheLang['Edit'] = $this->l('Edit');
  1573. echo '
  1574. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id.'&update'.$this->table.'&token='.($token!=NULL ? $token : $this->token).'">
  1575. <img src="../img/admin/edit.gif" alt="" title="'.$_cacheLang['Edit'].'" /></a>';
  1576. }
  1577. protected function _displayDeleteLink($token = NULL, $id)
  1578. {
  1579. $_cacheLang['Delete'] = $this->l('Delete');
  1580. $_cacheLang['DeleteItem'] = $this->l('Delete item #', __CLASS__, TRUE, FALSE);
  1581. echo '
  1582. <a href="'.self::$currentIndex.'&'.$this->identifier.'='.$id.'&delete'.$this->table.'&token='.($token!=NULL ? $token : $this->token).'" onclick="return confirm(\''.$_cacheLang['DeleteItem'].$id.' ?'.
  1583. (!is_null($this->specificConfirmDelete) ? '\r'.$this->specificConfirmDelete : '').'\');">
  1584. <img src="../img/admin/delete.gif" alt="'.$_cacheLang['Delete'].'" title="'.$_cacheLang['Delete'].'" /></a>';
  1585. }
  1586. /**
  1587. * Close list table and submit button
  1588. */
  1589. public function displayListFooter($token = NULL)
  1590. {
  1591. echo '</table>';
  1592. if ($this->delete)
  1593. echo '<p><input type="submit" class="button" name="submitDel'.$this->table.'" value="'.$this->l('Delete selection').'" onclick="return confirm(\''.$this->l('Delete selected items?', __CLASS__, TRUE, FALSE).'\');" /></p>';
  1594. echo '
  1595. </td>
  1596. </tr>
  1597. </table>
  1598. <input type="hidden" name="token" value="'.($token ? $token : $this->token).'" />
  1599. </form>';
  1600. if (isset($this->_includeTab) && count($this->_includeTab))
  1601. echo '<br /><br />';
  1602. }
  1603. /**
  1604. * Options lists
  1605. */
  1606. public function displayOptionsList()
  1607. {
  1608. $tab = Tab::getTab($this->context->language->id, $this->id);
  1609. // Retrocompatibility < 1.5.0
  1610. if (!$this->optionsList && $this->_fieldsOptions)
  1611. {
  1612. $this->optionsList = array(
  1613. 'options' => array(
  1614. 'title' => ($this->optionTitle) ? $this->optionTitle : $this->l('Options'),
  1615. 'fields' => $this->_fieldsOptions,
  1616. ),
  1617. );
  1618. }
  1619. if (!$this->optionsList)
  1620. return ;
  1621. echo '<br />';
  1622. echo '<script type="text/javascript">
  1623. id_language = Number('.$this->context->language->id.');
  1624. </script>';
  1625. echo '<form action="'.self::$currentIndex.'&submitOptions'.$this->table.'=1&token='.$this->token.'" method="post" enctype="multipart/form-data">';
  1626. foreach ($this->optionsList as $category => $categoryData)
  1627. {
  1628. $required = false;
  1629. $this->displayTopOptionCategory($category, $categoryData);
  1630. echo '<fieldset>';
  1631. // Options category title
  1632. $legend = '<img src="'.(!empty($tab['module']) && file_exists($_SERVER['DOCUMENT_ROOT']._MODULE_DIR_.$tab['module'].'/'.$tab['class_name'].'.gif') ? _MODULE_DIR_.$tab['module'].'/' : '../img/t/').$tab['class_name'].'.gif" /> ';
  1633. $legend .= ((isset($categoryData['title'])) ? $categoryData['title'] : $this->l('Options'));
  1634. echo '<legend>'.$legend.'</legend>';
  1635. // Category fields
  1636. if (!isset($categoryData['fields']))
  1637. continue;
  1638. // Category description
  1639. if (isset($categoryData['description']) && $categoryData['description'])
  1640. echo '<p class="optionsDescription">'.$categoryData['description'].'</p>';
  1641. foreach ($categoryData['fields'] as $key => $field)
  1642. {
  1643. // Field value
  1644. $value = Tools::getValue($key, Configuration::get($key));
  1645. if (!Validate::isCleanHtml($value))
  1646. $value = Configuration::get($key);
  1647. if (isset($field['defaultValue']) && !$value)
  1648. $value = $field['defaultValue'];
  1649. // Check if var is invisible (can't edit it in current shop context), or disable (use default value for multishop)
  1650. $isDisabled = $isInvisible = false;
  1651. if (Shop::isFeatureActive())
  1652. {
  1653. if (isset($field['visibility']) && $field['visibility'] > Shop::getContext())
  1654. {
  1655. $isDisabled = true;
  1656. $isInvisible = true;
  1657. }
  1658. else if (Shop::getContext() != Shop::CONTEXT_ALL && !Configuration::isOverridenByCurrentContext($key))
  1659. $isDisabled = true;
  1660. }
  1661. // Display title
  1662. echo '<div style="clear: both; padding-top:15px;" id="conf_id_'.$key.'" '.(($isInvisible) ? 'class="isInvisible"' : '').'>';
  1663. if ($field['title'])
  1664. {
  1665. echo '<label class="conf_title">';
  1666. // Is this field required ?
  1667. if (isset($field['required']) && $field['required'])
  1668. {
  1669. $required = true;
  1670. echo '<sup>*</sup> ';
  1671. }
  1672. echo $field['title'].'</label>';
  1673. }
  1674. echo '<div class="margin-form" style="padding-top:5px;">';
  1675. // Display option inputs
  1676. $method = 'displayOptionType'.Tools::toCamelCase($field['type'], true);
  1677. if (!method_exists($this, $method))
  1678. $this->displayOptionTypeText($key, $field, $value);//default behavior
  1679. else
  1680. $this->$method($key, $field, $value);
  1681. // Multishop default value
  1682. if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL && !$isInvisible)
  1683. echo '<div class="preference_default_multishop">
  1684. <label>
  1685. <input type="checkbox" name="multishopOverrideOption['.$key.']" value="1" '.(($isDisabled) ? 'checked="checked"' : '').' onclick="checkMultishopDefaultValue(this, \''.$key.'\')" /> '.$this->l('Use default value').'
  1686. </label>
  1687. </div>';
  1688. // Field description
  1689. //echo (isset($field['desc']) ? '<p class="preference_description">'.((isset($field['thumb']) AND $field['thumb'] AND $field['thumb']['pos'] == 'after') ? '<img src="'.$field['thumb']['file'].'" alt="'.$field['title'].'" title="'.$field['title'].'" style="float:left;" />' : '' ).$field['desc'].'</p>' : '');
  1690. echo (isset($field['desc']) ? '<p class="preference_description">'.$field['desc'].'</p>' : '');
  1691. // Is this field invisible in current shop context ?
  1692. echo ($isInvisible) ? '<p class="multishop_warning">'.$this->l('You cannot change the value of this configuration field in this shop context').'</p>' : '';
  1693. echo '</div></div>';
  1694. }
  1695. echo '<div align="center" style="margin-top: 20px;">';
  1696. echo '<input type="submit" value="'.$this->l(' Save ').'" name="submit'.ucfirst($category).$this->table.'" class="button" />';
  1697. echo '</div>';
  1698. if ($required)
  1699. echo '<div class="small"><sup>*</sup> '.$this->l('Required field').'</div>';
  1700. echo '</fieldset><br />';
  1701. $this->displayBottomOptionCategory($category, $categoryData);
  1702. }
  1703. echo '</form>';
  1704. }
  1705. /**
  1706. * Can be overriden
  1707. */
  1708. public function displayTopOptionCategory($category, $data)
  1709. {
  1710. }
  1711. /**
  1712. * Can be overriden
  1713. */
  1714. public function displayBottomOptionCategory($category, $data)
  1715. {
  1716. }
  1717. /**
  1718. * Type = select
  1719. */
  1720. public function displayOptionTypeSelect($key, $field, $value)
  1721. {
  1722. echo '<select name="'.$key.'"'.(isset($field['js']) === true ? ' onchange="'.$field['js'].'"' : '').' id="'.$key.'">';
  1723. foreach ($field['list'] as $k => $option)
  1724. echo '<option value="'.(isset($option['cast']) ? $option['cast']($option[$field['identifier']]) : $option[$field['identifier']]).'"'.(($value == $option[$field['identifier']]) ? ' selected="selected"' : '').'>'.$option['name'].'</option>';
  1725. echo '</select>';
  1726. }
  1727. /**
  1728. * Type = bool
  1729. */
  1730. public function displayOptionTypeBool($key, $field, $value)
  1731. {
  1732. echo '<label class="t" for="'.$key.'_on"><img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /></label>';
  1733. echo '<input type="radio" name="'.$key.'" id="'.$key.'_on" value="1" '.($value ? ' checked="checked" ' : '').(isset($field['js']['on']) ? $field['js']['on'] : '').' />';
  1734. echo '<label class="t" for="'.$key.'_on"> '.$this->l('Yes').'</label>';
  1735. echo '<label class="t" for="'.$key.'_off"><img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /></label>';
  1736. echo '<input type="radio" name="'.$key.'" id="'.$key.'_off" value="0" '.(!$value ? ' checked="checked" ' : '').(isset($field['js']['off']) ? $field['js']['off'] : '').' />';
  1737. echo '<label class="t" for="'.$key.'_off"> '.$this->l('No').'</label>';
  1738. }
  1739. /**
  1740. * Type = radio
  1741. */
  1742. public function displayOptionTypeRadio($key, $field, $value)
  1743. {
  1744. foreach ($field['choices'] as $k => $v)
  1745. echo '<input type="radio" name="'.$key.'" id="'.$key.$k.'_on" value="'.(int)$k.'"'.(($k == $value) ? ' checked="checked"' : '').(isset($field['js'][$k]) ? ' '.$field['js'][$k] : '').' /><label class="t" for="'.$key.$k.'_on"> '.$v.'</label><br />';
  1746. echo '<br />';
  1747. }
  1748. /**
  1749. * Type = text
  1750. */
  1751. public function displayOptionTypeText($key, $field, $value)
  1752. {
  1753. echo '<input type="'.$field['type'].'"'.(isset($field['id']) ? ' id="'.$field['id'].'"' : '').' size="'.(isset($field['size']) ? (int)$field['size'] : 5).'" name="'.$key.'" value="'.htmlentities($value, ENT_COMPAT, 'UTF-8').'" />'.(isset($field['next']) ? '&nbsp;'.(string)$field['next'] : '');
  1754. }
  1755. /**
  1756. * Type = password
  1757. */
  1758. public function displayOptionTypePassword($key, $field, $value)
  1759. {
  1760. $this->displayOptionTypeText($key, $field, '');
  1761. }
  1762. /**
  1763. * Type = textarea
  1764. */
  1765. public function displayOptionTypeTextarea($key, $field, $value)
  1766. {
  1767. echo '<textarea name='.$key.' cols="'.$field['cols'].'" rows="'.$field['rows'].'">'.htmlentities($value, ENT_COMPAT, 'UTF-8').'</textarea>';
  1768. }
  1769. /**
  1770. * Type = file
  1771. */
  1772. public function displayOptionTypeFile($key, $field, $value)
  1773. {
  1774. if (isset($field['thumb']) && $field['thumb'] && $field['thumb']['pos'] == 'before')
  1775. echo '<img src="'.$field['thumb']['file'].'" alt="'.$field['title'].'" title="'.$field['title'].'" /><br />';
  1776. echo '<input type="file" name="'.$key.'" />';
  1777. }
  1778. /**
  1779. * Type = image
  1780. */
  1781. public function displayOptionTypeImage($key, $field, $value)
  1782. {
  1783. echo '<table cellspacing="0" cellpadding="0">';
  1784. echo '<tr>';
  1785. /*if ($name == 'themes')
  1786. echo '
  1787. <td colspan="'.sizeof($field['list']).'">
  1788. <b>'.$this->l('In order to use a new theme, please follow these steps:', get_class()).'</b>
  1789. <ul>
  1790. <li>'.$this->l('Import your theme using this module:', get_class()).' <a href="index.php?tab=AdminModules&token='.Tools::getAdminTokenLite('AdminModules').'&filtername=themeinstallator" style="text-decoration: underline;">'.$this->l('Theme installer', get_class()).'</a></li>
  1791. <li>'.$this->l('When your theme is imported, please select the theme in this page', get_class()).'</li>
  1792. </ul>
  1793. </td>
  1794. </tr>
  1795. <tr>
  1796. ';*/
  1797. $i = 0;
  1798. foreach ($field['list'] as $theme)
  1799. {
  1800. echo '<td class="center" style="width: 180px; padding:0px 20px 20px 0px;">';
  1801. echo '<input type="radio" name="'.$key.'" id="'.$key.'_'.$theme['name'].'_on" style="vertical-align: text-bottom;" value="'.$theme['name'].'"'.(_THEME_NAME_ == $theme['name'] ? 'checked="checked"' : '').' />';
  1802. echo '<label class="t" for="'.$key.'_'.$theme['name'].'_on"> '.Tools::strtolower($theme['name']).'</label>';
  1803. echo '<br />';
  1804. echo '<label class="t" for="'.$key.'_'.$theme['name'].'_on">';
  1805. echo '<img src="../themes/'.$theme['name'].'/preview.jpg" alt="'.Tools::strtolower($theme['name']).'">';
  1806. echo '</label>';
  1807. echo '</td>';
  1808. if (isset($field['max']) && ($i +1 ) % $field['max'] == 0)
  1809. echo '</tr><tr>';
  1810. $i++;
  1811. }
  1812. echo '</tr>';
  1813. echo '</table>';
  1814. }
  1815. /**
  1816. * Type = textLang
  1817. */
  1818. public function displayOptionTypeTextLang($key, $field, $value)
  1819. {
  1820. $languages = Language::getLanguages(false);
  1821. foreach ($languages as $language)
  1822. {
  1823. $value = Tools::getValue($key.'_'.$language['id_lang'], Configuration::get($key, $language['id_lang']));
  1824. echo '<div id="'.$key.'_'.$language['id_lang'].'" style="margin-bottom:8px; display: '.($language['id_lang'] == $this->context->language->id ? 'block' : 'none').'; float: left; vertical-align: top;">';
  1825. echo '<input type="text" size="'.(isset($field['size']) ? (int)$field['size'] : 5).'" name="'.$key.'_'.$language['id_lang'].'" value="'.htmlentities($value, ENT_COMPAT, 'UTF-8').'" />';
  1826. echo '</div>';
  1827. }
  1828. $this->displayFlags($languages, $this->context->language->id, $key, $key);
  1829. }
  1830. /**
  1831. * Type = TextareaLang
  1832. */
  1833. public function displayOptionTypeTextareaLang($key, $field, $value)
  1834. {
  1835. $languages = Language::getLanguages(false);
  1836. foreach ($languages as $language)
  1837. {
  1838. $value = Configuration::get($key, $language['id_lang']);
  1839. echo '<div id="'.$key.'_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $this->context->language->id ? 'block' : 'none').'; float: left;">';
  1840. echo '<textarea rows="'.(int)($field['rows']).'" cols="'.(int)($field['cols']).'" name="'.$key.'_'.$language['id_lang'].'">'.str_replace('\r\n', "\n", $value).'</textarea>';
  1841. echo '</div>';
  1842. }
  1843. $this->displayFlags($languages, $this->context->language->id, $key, $key);
  1844. echo '<br style="clear:both">';
  1845. }
  1846. /**
  1847. * Type = selectLang
  1848. */
  1849. public function displayOptionTypeSelectLang($key, $field, $value)
  1850. {
  1851. $languages = Language::getLanguages(false);
  1852. foreach ($languages as $language)
  1853. {
  1854. echo '<div id="'.$key.'_'.$language['id_lang'].'" style="margin-bottom:8px; display: '.($language['id_lang'] == $this->context->language->id ? 'block' : 'none').'; float: left; vertical-align: top;">';
  1855. echo '<select name="'.$key.'_'.strtoupper($language['iso_code']).'">';
  1856. foreach ($field['list'] as $k => $v)
  1857. echo '<option value="'.(isset($v['cast']) ? $v['cast']($v[$field['identifier']]) : $v[$field['identifier']]).'"'.((htmlentities(Tools::getValue($key.'_'.strtoupper($language['iso_code']), (Configuration::get($key.'_'.strtoupper($language['iso_code'])) ? Configuration::get($key.'_'.strtoupper($language['iso_code'])) : '')), ENT_COMPAT, 'UTF-8') == $v[$field['identifier']]) ? ' selected="selected"' : '').'>'.$v['name'].'</option>';
  1858. echo '</select>';
  1859. echo '</div>';
  1860. }
  1861. $this->displayFlags($languages, $this->context->language->id, $key, $key);
  1862. }
  1863. /**
  1864. * Type = price
  1865. */
  1866. public function displayOptionTypePrice($key, $field, $value)
  1867. {
  1868. echo $this->context->currency->getSign('left');
  1869. $this->displayOptionTypeText($key, $field, $value);
  1870. echo $this->context->currency->getSign('right').' '.$this->l('(tax excl.)');
  1871. }
  1872. /**
  1873. * Type = disabled
  1874. */
  1875. public function displayOptionTypeDisabled($key, $field, $value)
  1876. {
  1877. echo $field['disabled'];
  1878. }
  1879. /**
  1880. * Load class object using identifier in $_GET (if possible)
  1881. * otherwise return an empty object, or die
  1882. *
  1883. * @param boolean $opt Return an empty object if load fail
  1884. * @return object
  1885. */
  1886. protected function loadObject($opt = false)
  1887. {
  1888. if ($id = (int)(Tools::getValue($this->identifier)) AND Validate::isUnsignedId($id))
  1889. {
  1890. if (!$this->_object)
  1891. $this->_object = new $this->className($id);
  1892. if (Validate::isLoadedObject($this->_object))
  1893. return $this->_object;
  1894. $this->_errors[] = Tools::displayError('Object cannot be loaded (not found)');
  1895. }
  1896. elseif ($opt)
  1897. {
  1898. $this->_object = new $this->className();
  1899. return $this->_object;
  1900. }
  1901. else
  1902. $this->_errors[] = Tools::displayError('Object cannot be loaded (identifier missing or invalid)');
  1903. $this->displayErrors();
  1904. }
  1905. /**
  1906. * Return field value if possible (both classical and multilingual fields)
  1907. *
  1908. * Case 1 : Return value if present in $_POST / $_GET
  1909. * Case 2 : Return object value
  1910. *
  1911. * @param object $obj Object
  1912. * @param string $key Field name
  1913. * @param integer $id_lang Language id (optional)
  1914. * @return string
  1915. */
  1916. public function getFieldValue($obj, $key, $id_lang = NULL, $id_shop = null)
  1917. {
  1918. if (!$id_shop && $obj->isLangMultishop())
  1919. $id_shop = Context::getContext()->shop->id;
  1920. if ($id_lang)
  1921. $defaultValue = ($obj->id && isset($obj->{$key}[$id_lang])) ? $obj->{$key}[$id_lang] : '';
  1922. else
  1923. $defaultValue = isset($obj->{$key}) ? $obj->{$key} : '';
  1924. return Tools::getValue($key.($id_lang ? '_'.$id_shop.'_'.$id_lang : ''), $defaultValue);
  1925. }
  1926. /**
  1927. * Display form
  1928. */
  1929. public function displayForm($firstCall = true)
  1930. {
  1931. $allowEmployeeFormLang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
  1932. if ($allowEmployeeFormLang && !$this->context->cookie->employee_form_lang)
  1933. $this->context->cookie->employee_form_lang = (int)(Configuration::get('PS_LANG_DEFAULT'));
  1934. $useLangFromCookie = false;
  1935. $this->_languages = Language::getLanguages(false);
  1936. if ($allowEmployeeFormLang)
  1937. foreach ($this->_languages as $lang)
  1938. if ($this->context->cookie->employee_form_lang == $lang['id_lang'])
  1939. $useLangFromCookie = true;
  1940. if (!$useLangFromCookie)
  1941. $this->_defaultFormLanguage = (int)(Configuration::get('PS_LANG_DEFAULT'));
  1942. else
  1943. $this->_defaultFormLanguage = (int)($this->context->cookie->employee_form_lang);
  1944. // Only if it is the first call to displayForm, otherwise it has already been defined
  1945. if ($firstCall)
  1946. {
  1947. echo '
  1948. <script type="text/javascript">
  1949. $(document).ready(function() {
  1950. id_language = '.$this->_defaultFormLanguage.';
  1951. languages = new Array();';
  1952. foreach ($this->_languages as $k => $language)
  1953. echo '
  1954. languages['.$k.'] = {
  1955. id_lang: '.(int)$language['id_lang'].',
  1956. iso_code: \''.$language['iso_code'].'\',
  1957. name: \''.htmlentities($language['name'], ENT_COMPAT, 'UTF-8').'\'
  1958. };';
  1959. echo '
  1960. displayFlags(languages, id_language, '.$allowEmployeeFormLang.');
  1961. });
  1962. </script>';
  1963. }
  1964. }
  1965. /**
  1966. * Display object details
  1967. */
  1968. public function viewDetails() {}
  1969. /**
  1970. * Called before deletion
  1971. *
  1972. * @param object $object Object
  1973. * @return boolean
  1974. */
  1975. protected function beforeDelete($object) { return true; }
  1976. /**
  1977. * Called before deletion
  1978. *
  1979. * @param object $object Object
  1980. * @return boolean
  1981. */
  1982. protected function afterDelete($object, $oldId) { return true; }
  1983. protected function afterAdd($object) { return true; }
  1984. protected function afterUpdate($object) { return true; }
  1985. /**
  1986. * Check rights to view the current tab
  1987. *
  1988. * @return boolean
  1989. */
  1990. protected function afterImageUpload() {
  1991. return true;
  1992. }
  1993. /**
  1994. * Check rights to view the current tab
  1995. *
  1996. * @return boolean
  1997. */
  1998. public function viewAccess($disable = false)
  1999. {
  2000. if ($disable)
  2001. return true;
  2002. $this->tabAccess = Profile::getProfileAccess($this->context->employee->id_profile, $this->id);
  2003. if ($this->tabAccess['view'] === '1')
  2004. return true;
  2005. return false;
  2006. }
  2007. /**
  2008. * Check for security token
  2009. */
  2010. public function checkToken()
  2011. {
  2012. $token = Tools::getValue('token');
  2013. return (!empty($token) && $token === $this->token);
  2014. }
  2015. /**
  2016. * Display flags in forms for translations
  2017. *
  2018. * @param array $languages All languages available
  2019. * @param integer $default_language Default language id
  2020. * @param string $ids Multilingual div ids in form
  2021. * @param string $id Current div id]
  2022. * @param boolean $return define the return way : false for a display, true for a return
  2023. * @param boolean $use_vars_instead_of_ids use an js vars instead of ids seperate by "?"
  2024. */
  2025. public function displayFlags($languages, $default_language, $ids, $id, $return = false, $use_vars_instead_of_ids = false)
  2026. {
  2027. if (count($languages) == 1)
  2028. return false;
  2029. $output = '
  2030. <div class="displayed_flag">
  2031. <img src="../img/l/'.$default_language.'.jpg" class="pointer" id="language_current_'.$id.'" onclick="toggleLanguageFlags(this);" alt="" />
  2032. </div>
  2033. <div id="languages_'.$id.'" class="language_flags">
  2034. '.$this->l('Choose language:').'<br /><br />';
  2035. foreach ($languages as $language)
  2036. if($use_vars_instead_of_ids)
  2037. $output .= '<img src="../img/l/'.(int)($language['id_lang']).'.jpg" class="pointer" alt="'.$language['name'].'" title="'.$language['name'].'" onclick="changeLanguage(\''.$id.'\', '.$ids.', '.$language['id_lang'].', \''.$language['iso_code'].'\');" /> ';
  2038. else
  2039. $output .= '<img src="../img/l/'.(int)($language['id_lang']).'.jpg" class="pointer" alt="'.$language['name'].'" title="'.$language['name'].'" onclick="changeLanguage(\''.$id.'\', \''.$ids.'\', '.$language['id_lang'].', \''.$language['iso_code'].'\');" /> ';
  2040. $output .= '</div>';
  2041. if ($return)
  2042. return $output;
  2043. echo $output;
  2044. }
  2045. protected function filterToField($key, $filter)
  2046. {
  2047. foreach ($this->fieldsDisplay as $field)
  2048. if (array_key_exists('filter_key', $field) && $field['filter_key'] == $key)
  2049. return $field;
  2050. if (array_key_exists($filter, $this->fieldsDisplay))
  2051. return $this->fieldsDisplay[$filter];
  2052. return false;
  2053. }
  2054. protected function warnDomainName()
  2055. {
  2056. if ($_SERVER['HTTP_HOST'] != Configuration::get('PS_SHOP_DOMAIN') && $_SERVER['HTTP_HOST'] != Configuration::get('PS_SHOP_DOMAIN_SSL'))
  2057. $this->displayWarning($this->l('Your are currently connected with the following domain name:').' <span style="color: #CC0000;">'.$_SERVER['HTTP_HOST'].'</span><br />'.
  2058. $this->l('This one is different from the main shop domain name set in "Preferences > SEO & URLs":').' <span style="color: #CC0000;">'.Configuration::get('PS_SHOP_DOMAIN').'</span><br />
  2059. <a href="index.php?tab=AdminMeta&token='.Tools::getAdminTokenLite('AdminMeta').'#SEO%20%26%20URLs">'.
  2060. $this->l('Click here if you want to modify the main shop domain name').'</a>');
  2061. }
  2062. protected function displayAssoShop()
  2063. {
  2064. if (!Shop::isFeatureActive() || (!$this->_object && Shop::getContext() != Shop::CONTEXT_ALL))
  2065. return;
  2066. $assos = array();
  2067. $sql = 'SELECT id_shop, `'.pSQL($this->identifier).'`
  2068. FROM `'._DB_PREFIX_.pSQL($this->table).'_shop`';
  2069. foreach (Db::getInstance()->executeS($sql) as $row)
  2070. $assos[$row['id_shop']][] = $row[$this->identifier];
  2071. $html = <<<EOF
  2072. <script type="text/javascript">
  2073. $().ready(function()
  2074. {
  2075. // Click on "all shop"
  2076. $('.input_all_shop').click(function()
  2077. {
  2078. var checked = $(this).prop('checked');
  2079. $('.input_shop_group').attr('checked', checked);
  2080. $('.input_shop').attr('checked', checked);
  2081. });
  2082. // Click on a group shop
  2083. $('.input_shop_group').click(function()
  2084. {
  2085. $('.input_shop[value='+$(this).val()+']').attr('checked', $(this).prop('checked'));
  2086. check_all_shop();
  2087. });
  2088. // Click on a shop
  2089. $('.input_shop').click(function()
  2090. {
  2091. check_shop_group_status($(this).val());
  2092. check_all_shop();
  2093. });
  2094. // Initialize checkbox
  2095. $('.input_shop').each(function(k, v)
  2096. {
  2097. check_shop_group_status($(v).val());
  2098. check_all_shop();
  2099. });
  2100. });
  2101. function check_shop_group_status(id_group)
  2102. {
  2103. var groupChecked = true;
  2104. $('.input_shop[value='+id_group+']').each(function(k, v)
  2105. {
  2106. if (!$(v).prop('checked'))
  2107. groupChecked = false;
  2108. });
  2109. $('.input_shop_group[value='+id_group+']').attr('checked', groupChecked);
  2110. }
  2111. function check_all_shop()
  2112. {
  2113. var allChecked = true;
  2114. $('.input_shop_group').each(function(k, v)
  2115. {
  2116. if (!$(v).prop('checked'))
  2117. allChecked = false;
  2118. });
  2119. $('.input_all_shop').attr('checked', allChecked);
  2120. }
  2121. </script>
  2122. EOF;
  2123. $html .= '<div class="assoShop">';
  2124. $html .= '<table class="table" cellpadding="0" cellspacing="0" width="100%">
  2125. <tr><th>'.$this->l('Shop').'</th></tr>';
  2126. $html .= '<tr><td><label class="t"><input class="input_all_shop" type="checkbox" /> '.$this->l('All shops').'</label></td></tr>';
  2127. foreach (Shop::getTree() as $groupID => $groupData)
  2128. {
  2129. $html .= '<tr class="alt_row">';
  2130. $html .= '<td><img style="vertical-align: middle;" alt="" src="../img/admin/lv2_b.gif" /><label class="t"><input class="input_shop_group" type="checkbox" name="checkBoxShopGroupAsso_'.$this->table.'_'.$this->_object->id.'_'.$groupID.'" value="'.$groupID.'" '.($groupChecked ? 'checked="checked"' : '').' /> '.$groupData['name'].'</label></td>';
  2131. $html .= '</tr>';
  2132. $total = count($groupData['shops']);
  2133. $j = 0;
  2134. foreach ($groupData['shops'] as $shopID => $shopData)
  2135. {
  2136. $checked = ((isset($assos[$shopID]) && in_array($this->_object->id, $assos[$shopID])) || !$this->_object->id);
  2137. $html .= '<tr>';
  2138. $html .= '<td><img style="vertical-align: middle;" alt="" src="../img/admin/lv3_'.(($j < $total - 1) ? 'b' : 'f').'.png" /><label class="child">';
  2139. $html .= '<input class="input_shop" type="checkbox" value="'.$groupID.'" name="checkBoxShopAsso_'.$this->table.'_'.$this->_object->id.'_'.$shopID.'" id="checkedBox_'.$shopID.'" '.($checked ? 'checked="checked"' : '').' /> ';
  2140. $html .= $shopData['name'].'</label></td>';
  2141. $html .= '</tr>';
  2142. $j++;
  2143. }
  2144. }
  2145. $html .= '</table></div>';
  2146. echo $html;
  2147. }
  2148. /**
  2149. * Get current URL
  2150. *
  2151. * @param array $remove List of keys to remove from URL
  2152. * @return string
  2153. */
  2154. protected function getCurrentUrl($remove = array())
  2155. {
  2156. $url = $_SERVER['REQUEST_URI'];
  2157. if (!$remove)
  2158. return $url;
  2159. if (!is_array($remove))
  2160. $remove = array($remove);
  2161. $url = preg_replace('#(?<=&|\?)(' . implode('|', $remove) . ')=.*?(&|$)#i', '', $url);
  2162. $len = strlen($url);
  2163. if ($url[$len - 1] == '&')
  2164. $url = substr($url, 0, $len - 1);
  2165. return $url;
  2166. }
  2167. }