PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 1ms

/classes/controller/AdminController.php

https://github.com/cokarmando/PrestaShop
PHP | 2979 lines | 2125 code | 357 blank | 497 comment | 583 complexity | eeaf6d4c756876622106026044b04d10 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * 2007-2013 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-2013 PrestaShop SA
  23. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. class AdminControllerCore extends Controller
  27. {
  28. public $path;
  29. public static $currentIndex;
  30. public $content;
  31. public $warnings = array();
  32. public $informations = array();
  33. public $confirmations = array();
  34. public $shopShareDatas = false;
  35. public $_languages = array();
  36. public $default_form_language;
  37. public $allow_employee_form_lang;
  38. public $layout = 'layout.tpl';
  39. protected $meta_title;
  40. public $template = 'content.tpl';
  41. /** @var string Associated table name */
  42. public $table;
  43. /** @var string Object identifier inside the associated table */
  44. protected $identifier = false;
  45. /** @var string Tab name */
  46. public $className;
  47. /** @var array tabAccess */
  48. public $tabAccess;
  49. /** @var integer Tab id */
  50. public $id = -1;
  51. public $required_database = false;
  52. /** @var string Security token */
  53. public $token;
  54. /** @var string shop | group_shop */
  55. public $shopLinkType;
  56. /** @var string Default ORDER BY clause when $_orderBy is not defined */
  57. protected $_defaultOrderBy = false;
  58. protected $_defaultOrderWay = 'ASC';
  59. public $tpl_form_vars = array();
  60. public $tpl_list_vars = array();
  61. public $tpl_delete_link_vars = array();
  62. public $tpl_option_vars = array();
  63. public $tpl_view_vars = array();
  64. public $tpl_required_fields_vars = array();
  65. public $base_tpl_view = null;
  66. public $base_tpl_form = null;
  67. /** @var bool if you want more fieldsets in the form */
  68. public $multiple_fieldsets = false;
  69. public $fields_value = false;
  70. /** @var array Errors displayed after post processing */
  71. public $errors = array();
  72. /** @var define if the header of the list contains filter and sorting links or not */
  73. protected $list_simple_header;
  74. /** @var array list to be generated */
  75. protected $fields_list;
  76. /** @var array modules list filters */
  77. protected $filter_modules_list = null;
  78. /** @var array modules list filters */
  79. protected $modules_list = array();
  80. /** @var array edit form to be generated */
  81. protected $fields_form;
  82. /** @var override of $fields_form */
  83. protected $fields_form_override;
  84. /** @var array list of option forms to be generated */
  85. protected $fields_options;
  86. protected $shopLink;
  87. /** @var string SQL query */
  88. protected $_listsql = '';
  89. /** @var array Cache for query results */
  90. protected $_list = array();
  91. /** @var define if the header of the list contains filter and sorting links or not */
  92. protected $toolbar_title;
  93. /** @var array list of toolbar buttons */
  94. protected $toolbar_btn = null;
  95. /** @var boolean scrolling toolbar */
  96. protected $toolbar_scroll = true;
  97. /** @var boolean set to false to hide toolbar and page title */
  98. protected $show_toolbar = true;
  99. /** @var boolean set to true to show toolbar and page title for options */
  100. protected $show_toolbar_options = false;
  101. /** @var integer Number of results in list */
  102. protected $_listTotal = 0;
  103. /** @var boolean Automatically join language table if true */
  104. public $lang = false;
  105. /** @var array WHERE clause determined by filter fields */
  106. protected $_filter;
  107. /** @var array Temporary SQL table WHERE clause determinated by filter fields */
  108. protected $_tmpTableFilter = '';
  109. /** @var array Number of results in list per page (used in select field) */
  110. protected $_pagination = array(20, 50, 100, 300);
  111. /** @var string ORDER BY clause determined by field/arrows in list header */
  112. protected $_orderBy;
  113. /** @var string Order way (ASC, DESC) determined by arrows in list header */
  114. protected $_orderWay;
  115. /** @var array list of available actions for each list row - default actions are view, edit, delete, duplicate */
  116. protected $actions_available = array('view', 'edit', 'delete', 'duplicate');
  117. /** @var array list of required actions for each list row */
  118. protected $actions = array();
  119. /** @var array list of row ids associated with a given action for witch this action have to not be available */
  120. protected $list_skip_actions = array();
  121. /* @var boolean don't show header & footer */
  122. protected $lite_display = false;
  123. /** @var bool boolean List content lines are clickable if true */
  124. protected $list_no_link = false;
  125. protected $allow_export = false;
  126. /** @var array $cache_lang cache for traduction */
  127. public static $cache_lang = array();
  128. /** @var array required_fields to display in the Required Fields form */
  129. public $required_fields = array();
  130. /** @var Helper */
  131. protected $helper;
  132. /**
  133. * @var array actions to execute on multiple selections
  134. * Usage:
  135. * array(
  136. * 'actionName' => array(
  137. * 'text' => $this->l('Message displayed on the submit button (mandatory)'),
  138. * 'confirm' => $this->l('If set, this confirmation message will pop-up (optional)')),
  139. * 'anotherAction' => array(...)
  140. * );
  141. *
  142. * If your action is named 'actionName', you need to have a method named bulkactionName() that will be executed when the button is clicked.
  143. */
  144. protected $bulk_actions;
  145. /**
  146. * @var array ids of the rows selected
  147. */
  148. protected $boxes;
  149. /** @var string Do not automatically select * anymore but select only what is necessary */
  150. protected $explicitSelect = false;
  151. /** @var string Add fields into data query to display list */
  152. protected $_select;
  153. /** @var string Join tables into data query to display list */
  154. protected $_join;
  155. /** @var string Add conditions into data query to display list */
  156. protected $_where;
  157. /** @var string Group rows into data query to display list */
  158. protected $_group;
  159. /** @var string Having rows into data query to display list */
  160. protected $_having;
  161. protected $is_cms = false;
  162. /** @var string identifier to use for changing positions in lists (can be omitted if positions cannot be changed) */
  163. protected $position_identifier;
  164. /** @var boolean Table records are not deleted but marked as deleted if set to true */
  165. protected $deleted = false;
  166. /**
  167. * @var bool is a list filter set
  168. */
  169. protected $filter;
  170. protected $noLink;
  171. protected $specificConfirmDelete = null;
  172. protected $colorOnBackground;
  173. /** @var bool If true, activates color on hover */
  174. protected $row_hover = true;
  175. /** @string Action to perform : 'edit', 'view', 'add', ... */
  176. protected $action;
  177. protected $display;
  178. protected $_includeContainer = true;
  179. protected $tab_modules_list = array('default_list' => array(), 'slider_list' => array());
  180. public $tpl_folder;
  181. protected $bo_theme;
  182. /** @var bool Redirect or not ater a creation */
  183. protected $_redirect = true;
  184. /** @var array Name and directory where class image are located */
  185. public $fieldImageSettings = array();
  186. /** @var string Image type */
  187. public $imageType = 'jpg';
  188. /** @var instanciation of the class associated with the AdminController */
  189. protected $object;
  190. /** @var current object ID */
  191. protected $id_object;
  192. /**
  193. * @var current controller name without suffix
  194. */
  195. public $controller_name;
  196. public $multishop_context = -1;
  197. public $multishop_context_group = true;
  198. /**
  199. * Current breadcrumb position as an array of tab names
  200. */
  201. protected $breadcrumbs;
  202. public function __construct()
  203. {
  204. global $timer_start;
  205. $this->timer_start = $timer_start;
  206. // Has to be remove for the next Prestashop version
  207. global $token;
  208. $this->controller_type = 'admin';
  209. $this->controller_name = get_class($this);
  210. if (strpos($this->controller_name, 'Controller'))
  211. $this->controller_name = substr($this->controller_name, 0, -10);
  212. parent::__construct();
  213. if ($this->multishop_context == -1)
  214. $this->multishop_context = Shop::CONTEXT_ALL | Shop::CONTEXT_GROUP | Shop::CONTEXT_SHOP;
  215. $this->bo_theme = ((Validate::isLoadedObject($this->context->employee) && $this->context->employee->bo_theme) ? $this->context->employee->bo_theme : 'default');
  216. if (!file_exists(_PS_BO_ALL_THEMES_DIR_.$this->bo_theme.DIRECTORY_SEPARATOR.'template'))
  217. $this->bo_theme = 'default';
  218. $this->context->smarty->setTemplateDir(array(
  219. _PS_BO_ALL_THEMES_DIR_.$this->bo_theme.DIRECTORY_SEPARATOR.'template',
  220. _PS_OVERRIDE_DIR_.'controllers'.DIRECTORY_SEPARATOR.'admin'.DIRECTORY_SEPARATOR.'templates'
  221. ));
  222. $this->id = Tab::getIdFromClassName($this->controller_name);
  223. $this->token = Tools::getAdminToken($this->controller_name.(int)$this->id.(int)$this->context->employee->id);
  224. $token = $this->token;
  225. $this->_conf = array(
  226. 1 => $this->l('Deletion successful'), 2 => $this->l('The selection has been successfully deleted.'),
  227. 3 => $this->l('Creation successful'), 4 => $this->l('Update successful'),
  228. 5 => $this->l('The status has been updated successfully.'), 6 => $this->l('The settings have been updated successfully.'),
  229. 7 => $this->l('The image was successfully deleted.'), 8 => $this->l('The module was downloaded successfully.'),
  230. 9 => $this->l('The thumbnails were successfully regenerated.'), 10 => $this->l('Message sent to the customer.'),
  231. 11 => $this->l('Comment added'), 12 => $this->l('Module(s) installed successfully.'),
  232. 13 => $this->l('Module(s) uninstalled successfully.'), 14 => $this->l('The translation was successfully copied.'),
  233. 15 => $this->l('The translations have been successfully added.'), 16 => $this->l('The module transplanted successfully to the hook.'),
  234. 17 => $this->l('The module was successfully removed from the hook.'), 18 => $this->l('Upload successful'),
  235. 19 => $this->l('Duplication was completed successfully.'), 20 => $this->l('The translation was added successfully, but the language has not been created.'),
  236. 21 => $this->l('Module reset successfully.'), 22 => $this->l('Module deleted successfully.'),
  237. 23 => $this->l('Localization pack imported successfully.'), 24 => $this->l('Localization pack imported successfully.'),
  238. 25 => $this->l('The selcted images have successfully been moved.'),
  239. 26 => $this->l('Your cover selection has been saved.'),
  240. 27 => $this->l('The image shop association has been modified.'),
  241. 28 => $this->l('A zone has been assigned to the selection successfully.'),
  242. 29 => $this->l('Upgrade successful'),
  243. 30 => $this->l('A partial refund was successfully created.'),
  244. 31 => $this->l('The discount was successfully generated.')
  245. );
  246. if (!$this->identifier) $this->identifier = 'id_'.$this->table;
  247. if (!$this->_defaultOrderBy) $this->_defaultOrderBy = $this->identifier;
  248. $this->tabAccess = Profile::getProfileAccess($this->context->employee->id_profile, $this->id);
  249. // Fix for AdminHome
  250. if ($this->controller_name == 'AdminHome')
  251. $_POST['token'] = $this->token;
  252. if (!Shop::isFeatureActive())
  253. $this->shopLinkType = '';
  254. //$this->base_template_folder = _PS_BO_ALL_THEMES_DIR_.$this->bo_theme.'/template';
  255. $this->override_folder = Tools::toUnderscoreCase(substr($this->controller_name, 5)).'/';
  256. // Get the name of the folder containing the custom tpl files
  257. $this->tpl_folder = Tools::toUnderscoreCase(substr($this->controller_name, 5)).'/';
  258. $this->initShopContext();
  259. $this->context->currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT'));
  260. }
  261. /**
  262. * Set breadcrumbs array for the controller page
  263. */
  264. public function initBreadcrumbs()
  265. {
  266. $tabs = array();
  267. $tabs = Tab::recursiveTab($this->id, $tabs);
  268. $tabs = array_reverse($tabs);
  269. foreach ($tabs as $tab)
  270. $this->breadcrumbs[] = $tab['name'];
  271. }
  272. /**
  273. * set default toolbar_title to admin breadcrumb
  274. *
  275. * @return void
  276. */
  277. public function initToolbarTitle()
  278. {
  279. $bread_extended = array_unique($this->breadcrumbs);
  280. switch ($this->display)
  281. {
  282. case 'edit':
  283. $bread_extended[] = $this->l('Edit');
  284. break;
  285. case 'add':
  286. $bread_extended[] = $this->l('Add new');
  287. break;
  288. case 'view':
  289. $bread_extended[] = $this->l('View');
  290. break;
  291. }
  292. $this->toolbar_title = $bread_extended;
  293. }
  294. /**
  295. * Check rights to view the current tab
  296. *
  297. * @param bool $disable
  298. * @return boolean
  299. */
  300. public function viewAccess($disable = false)
  301. {
  302. if ($disable)
  303. return true;
  304. if ($this->tabAccess['view'] === '1')
  305. return true;
  306. return false;
  307. }
  308. /**
  309. * Check for security token
  310. */
  311. public function checkToken()
  312. {
  313. $token = Tools::getValue('token');
  314. return (!empty($token) && $token === $this->token);
  315. }
  316. public function ajaxProcessHelpAccess()
  317. {
  318. $this->json = true;
  319. $item = Tools::getValue('item');
  320. $iso_user = Tools::getValue('isoUser');
  321. $country = Tools::getValue('country');
  322. $version = Tools::getValue('version');
  323. if (isset($item) && isset($iso_user) && isset($country))
  324. {
  325. $helper = new HelperHelpAccess($item, $iso_user, $country, $version);
  326. $this->content = $helper->generate();
  327. }
  328. else
  329. $this->content = 'none';
  330. $this->display = 'content';
  331. }
  332. /**
  333. * Set the filters used for the list display
  334. */
  335. public function processFilter()
  336. {
  337. $prefix = str_replace(array('admin', 'controller'), '', Tools::strtolower(get_class($this)));
  338. // Filter memorization
  339. if (isset($_POST) && !empty($_POST) && isset($this->table))
  340. foreach ($_POST as $key => $value)
  341. {
  342. if (stripos($key, $this->table.'Filter_') === 0)
  343. $this->context->cookie->{$prefix.$key} = !is_array($value) ? $value : serialize($value);
  344. elseif(stripos($key, 'submitFilter') === 0)
  345. $this->context->cookie->$key = !is_array($value) ? $value : serialize($value);
  346. }
  347. if (isset($_GET) && !empty($_GET) && isset($this->table))
  348. foreach ($_GET as $key => $value)
  349. if (stripos($key, $this->table.'OrderBy') === 0 || stripos($key, $this->table.'Orderway') === 0)
  350. $this->context->cookie->{$prefix.$key} = $value;
  351. $filters = $this->context->cookie->getFamily($prefix.$this->table.'Filter_');
  352. foreach ($filters as $key => $value)
  353. {
  354. /* Extracting filters from $_POST on key filter_ */
  355. if ($value != null && !strncmp($key, $prefix.$this->table.'Filter_', 7 + Tools::strlen($prefix.$this->table)))
  356. {
  357. $key = Tools::substr($key, 7 + Tools::strlen($prefix.$this->table));
  358. /* Table alias could be specified using a ! eg. alias!field */
  359. $tmp_tab = explode('!', $key);
  360. $filter = count($tmp_tab) > 1 ? $tmp_tab[1] : $tmp_tab[0];
  361. if ($field = $this->filterToField($key, $filter))
  362. {
  363. $type = (array_key_exists('filter_type', $field) ? $field['filter_type'] : (array_key_exists('type', $field) ? $field['type'] : false)); if (($type == 'date' || $type == 'datetime') && is_string($value))
  364. $value = Tools::unSerialize($value);
  365. $key = isset($tmp_tab[1]) ? $tmp_tab[0].'.`'.$tmp_tab[1].'`' : '`'.$tmp_tab[0].'`';
  366. // Assignement by reference
  367. if (array_key_exists('tmpTableFilter', $field))
  368. $sql_filter = & $this->_tmpTableFilter;
  369. elseif (array_key_exists('havingFilter', $field))
  370. $sql_filter = & $this->_filterHaving;
  371. else
  372. $sql_filter = & $this->_filter;
  373. /* Only for date filtering (from, to) */
  374. if (is_array($value))
  375. {
  376. if (isset($value[0]) && !empty($value[0]))
  377. {
  378. if (!Validate::isDate($value[0]))
  379. $this->errors[] = Tools::displayError('The \'From\' date format is invalid (YYYY-MM-DD)');
  380. else
  381. $sql_filter .= ' AND '.pSQL($key).' >= \''.pSQL(Tools::dateFrom($value[0])).'\'';
  382. }
  383. if (isset($value[1]) && !empty($value[1]))
  384. {
  385. if (!Validate::isDate($value[1]))
  386. $this->errors[] = Tools::displayError('The \'To\' date format is invalid (YYYY-MM-DD)');
  387. else
  388. $sql_filter .= ' AND '.pSQL($key).' <= \''.pSQL(Tools::dateTo($value[1])).'\'';
  389. }
  390. }
  391. else
  392. {
  393. $sql_filter .= ' AND ';
  394. $check_key = ($key == $this->identifier || $key == '`'.$this->identifier.'`');
  395. if ($type == 'int' || $type == 'bool')
  396. $sql_filter .= (($check_key || $key == '`active`') ? 'a.' : '').pSQL($key).' = '.(int)$value.' ';
  397. elseif ($type == 'decimal')
  398. $sql_filter .= ($check_key ? 'a.' : '').pSQL($key).' = '.(float)$value.' ';
  399. elseif ($type == 'select')
  400. $sql_filter .= ($check_key ? 'a.' : '').pSQL($key).' = \''.pSQL($value).'\' ';
  401. else
  402. $sql_filter .= ($check_key ? 'a.' : '').pSQL($key).' LIKE \'%'.pSQL($value).'%\' ';
  403. }
  404. }
  405. }
  406. }
  407. }
  408. /**
  409. * @todo uses redirectAdmin only if !$this->ajax
  410. */
  411. public function postProcess()
  412. {
  413. if ($this->ajax)
  414. {
  415. // from ajax-tab.php
  416. $action = Tools::getValue('action');
  417. // no need to use displayConf() here
  418. if (!empty($action) && method_exists($this, 'ajaxProcess'.Tools::toCamelCase($action)))
  419. return $this->{'ajaxProcess'.Tools::toCamelCase($action)}();
  420. elseif (method_exists($this, 'ajaxProcess'))
  421. return $this->ajaxProcess();
  422. }
  423. else
  424. {
  425. // Process list filtering
  426. if ($this->filter)
  427. $this->processFilter();
  428. // If the method named after the action exists, call "before" hooks, then call action method, then call "after" hooks
  429. if (!empty($this->action) && method_exists($this, 'process'.ucfirst(Tools::toCamelCase($this->action))))
  430. {
  431. // Hook before action
  432. Hook::exec('actionAdmin'.ucfirst($this->action).'Before', array('controller' => $this));
  433. Hook::exec('action'.get_class($this).ucfirst($this->action).'Before', array('controller' => $this));
  434. // Call process
  435. $return = $this->{'process'.Tools::toCamelCase($this->action)}();
  436. // Hook After Action
  437. Hook::exec('actionAdmin'.ucfirst($this->action).'After', array('controller' => $this, 'return' => $return));
  438. Hook::exec('action'.get_class($this).ucfirst($this->action).'After', array('controller' => $this, 'return' => $return));
  439. return $return;
  440. }
  441. }
  442. }
  443. /**
  444. * Object Delete images
  445. */
  446. public function processDeleteImage()
  447. {
  448. if (Validate::isLoadedObject($object = $this->loadObject()))
  449. {
  450. if (($object->deleteImage()))
  451. {
  452. $redirect = self::$currentIndex.'&add'.$this->table.'&'.$this->identifier.'='.Tools::getValue($this->identifier).'&conf=7&token='.$this->token;
  453. if (!$this->ajax)
  454. $this->redirect_after = $redirect;
  455. else
  456. $this->content = 'ok';
  457. }
  458. }
  459. $this->errors[] = Tools::displayError('An error occurred while attempting to delet the image. (cannot load object).');
  460. return $object;
  461. }
  462. public function processExport()
  463. {
  464. // clean buffer
  465. if (ob_get_level() && ob_get_length() > 0)
  466. ob_clean();
  467. $this->getList($this->context->language->id);
  468. if (!count($this->_list))
  469. return;
  470. header('Content-type: text/csv');
  471. header('Content-Type: application/force-download; charset=UTF-8');
  472. header('Cache-Control: no-store, no-cache');
  473. header('Content-disposition: attachment; filename="'.$this->table.'_'.date('Y-m-d_His').'.csv"');
  474. $headers = array();
  475. foreach ($this->fields_list as $datas)
  476. $headers[] = Tools::htmlentitiesDecodeUTF8($datas['title']);
  477. $content = array();
  478. foreach ($this->_list as $i => $row)
  479. {
  480. $content[$i] = array();
  481. foreach ($this->fields_list as $key => $value)
  482. if (isset($row[$key]))
  483. $content[$i][] = Tools::htmlentitiesDecodeUTF8($row[$key]);
  484. }
  485. $this->context->smarty->assign(array(
  486. 'export_precontent' => "\xEF\xBB\xBF",
  487. 'export_headers' => $headers,
  488. 'export_content' => $content
  489. )
  490. );
  491. $this->layout = 'layout-export.tpl';
  492. }
  493. /**
  494. * Object Delete
  495. */
  496. public function processDelete()
  497. {
  498. if (Validate::isLoadedObject($object = $this->loadObject()))
  499. {
  500. $res = true;
  501. // check if request at least one object with noZeroObject
  502. if (isset($object->noZeroObject) && count(call_user_func(array($this->className, $object->noZeroObject))) <= 1)
  503. {
  504. $this->errors[] = Tools::displayError('You need at least one object.').
  505. ' <b>'.$this->table.'</b><br />'.
  506. Tools::displayError('You cannot delete all of the items.');
  507. }
  508. elseif (array_key_exists('delete', $this->list_skip_actions) && in_array($object->id, $this->list_skip_actions['delete'])) //check if some ids are in list_skip_actions and forbid deletion
  509. $this->errors[] = Tools::displayError('You cannot delete this item.');
  510. else
  511. {
  512. if ($this->deleted)
  513. {
  514. if (!empty($this->fieldImageSettings))
  515. $res = $object->deleteImage();
  516. if (!$res)
  517. $this->errors[] = Tools::displayError('Unable to delete associated images.');
  518. $object->deleted = 1;
  519. if ($object->update())
  520. $this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token;
  521. }
  522. elseif ($object->delete())
  523. $this->redirect_after = self::$currentIndex.'&conf=1&token='.$this->token;
  524. $this->errors[] = Tools::displayError('An error occurred during deletion.');
  525. }
  526. }
  527. else
  528. {
  529. $this->errors[] = Tools::displayError('An error occurred while deleting the object.').
  530. ' <b>'.$this->table.'</b> '.
  531. Tools::displayError('(cannot load object)');
  532. }
  533. return $object;
  534. }
  535. /**
  536. * Call the right method for creating or updating object
  537. *
  538. * @return mixed
  539. */
  540. public function processSave()
  541. {
  542. if ($this->id_object)
  543. {
  544. $this->object = $this->loadObject();
  545. return $this->processUpdate();
  546. }
  547. else
  548. return $this->processAdd();
  549. }
  550. /**
  551. * Object creation
  552. */
  553. public function processAdd()
  554. {
  555. /* Checking fields validity */
  556. $this->validateRules();
  557. if (count($this->errors) <= 0)
  558. {
  559. $this->object = new $this->className();
  560. $this->copyFromPost($this->object, $this->table);
  561. $this->beforeAdd($this->object);
  562. if (method_exists($this->object, 'add') && !$this->object->add())
  563. {
  564. $this->errors[] = Tools::displayError('An error occurred while creating an object.').
  565. ' <b>'.$this->table.' ('.Db::getInstance()->getMsgError().')</b>';
  566. }
  567. /* voluntary do affectation here */
  568. elseif (($_POST[$this->identifier] = $this->object->id) && $this->postImage($this->object->id) && !count($this->errors) && $this->_redirect)
  569. {
  570. $parent_id = (int)Tools::getValue('id_parent', 1);
  571. $this->afterAdd($this->object);
  572. $this->updateAssoShop($this->object->id);
  573. // Save and stay on same form
  574. if (empty($this->redirect_after) && $this->redirect_after !== false && Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
  575. $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$this->object->id.'&conf=3&update'.$this->table.'&token='.$this->token;
  576. // Save and back to parent
  577. if (empty($this->redirect_after) && $this->redirect_after !== false && Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
  578. $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=3&token='.$this->token;
  579. // Default behavior (save and back)
  580. if (empty($this->redirect_after) && $this->redirect_after !== false)
  581. $this->redirect_after = self::$currentIndex.($parent_id ? '&'.$this->identifier.'='.$this->object->id : '').'&conf=3&token='.$this->token;
  582. }
  583. }
  584. $this->errors = array_unique($this->errors);
  585. if (!empty($this->errors))
  586. {
  587. // if we have errors, we stay on the form instead of going back to the list
  588. $this->display = 'edit';
  589. return false;
  590. }
  591. return $this->object;
  592. }
  593. /**
  594. * Object update
  595. */
  596. public function processUpdate()
  597. {
  598. /* Checking fields validity */
  599. $this->validateRules();
  600. if (empty($this->errors))
  601. {
  602. $id = (int)Tools::getValue($this->identifier);
  603. /* Object update */
  604. if (isset($id) && !empty($id))
  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. $object_new = $object->duplicateObject();
  614. if (Validate::isLoadedObject($object_new))
  615. {
  616. // Update old object to deleted
  617. $object->deleted = 1;
  618. $object->update();
  619. // Update new object with post values
  620. $this->copyFromPost($object_new, $this->table);
  621. $result = $object_new->update();
  622. if (Validate::isLoadedObject($object_new))
  623. $this->afterDelete($object_new, $object->id);
  624. }
  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. {
  636. $this->errors[] = Tools::displayError('An error occurred while updating an object.').
  637. ' <b>'.$this->table.'</b> ('.Db::getInstance()->getMsgError().')';
  638. }
  639. elseif ($this->postImage($object->id) && !count($this->errors) && $this->_redirect)
  640. {
  641. $parent_id = (int)Tools::getValue('id_parent', 1);
  642. // Specific back redirect
  643. if ($back = Tools::getValue('back'))
  644. $this->redirect_after = urldecode($back).'&conf=4';
  645. // Specific scene feature
  646. // @todo change stay_here submit name (not clear for redirect to scene ... )
  647. if (Tools::getValue('stay_here') == 'on' || Tools::getValue('stay_here') == 'true' || Tools::getValue('stay_here') == '1')
  648. $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&updatescene&token='.$this->token;
  649. // Save and stay on same form
  650. // @todo on the to following if, we may prefer to avoid override redirect_after previous value
  651. if (Tools::isSubmit('submitAdd'.$this->table.'AndStay'))
  652. $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$object->id.'&conf=4&update'.$this->table.'&token='.$this->token;
  653. // Save and back to parent
  654. if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent'))
  655. $this->redirect_after = self::$currentIndex.'&'.$this->identifier.'='.$parent_id.'&conf=4&token='.$this->token;
  656. // Default behavior (save and back)
  657. if (empty($this->redirect_after))
  658. $this->redirect_after = self::$currentIndex.($parent_id ? '&'.$this->identifier.'='.$object->id : '').'&conf=4&token='.$this->token;
  659. }
  660. }
  661. else
  662. $this->errors[] = Tools::displayError('An error occurred while updating an object.').
  663. ' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  664. }
  665. }
  666. $this->errors = array_unique($this->errors);
  667. if (!empty($this->errors))
  668. {
  669. // if we have errors, we stay on the form instead of going back to the list
  670. $this->display = 'edit';
  671. return false;
  672. }
  673. if (isset($object))
  674. return $object;
  675. return;
  676. }
  677. /**
  678. * Change object required fields
  679. */
  680. public function processUpdateFields()
  681. {
  682. if (!is_array($fields = Tools::getValue('fieldsBox')))
  683. $fields = array();
  684. $object = new $this->className();
  685. if (!$object->addFieldsRequiredDatabase($fields))
  686. $this->errors[] = Tools::displayError('An error occurred when attempting to update the required fields.');
  687. else
  688. $this->redirect_after = self::$currentIndex.'&conf=4&token='.$this->token;
  689. return $object;
  690. }
  691. /**
  692. * Change object status (active, inactive)
  693. */
  694. public function processStatus()
  695. {
  696. if (Validate::isLoadedObject($object = $this->loadObject()))
  697. {
  698. if ($object->toggleStatus())
  699. {
  700. $id_category = (($id_category = (int)Tools::getValue('id_category')) && Tools::getValue('id_product')) ? '&id_category='.$id_category : '';
  701. $this->redirect_after = self::$currentIndex.'&conf=5'.$id_category.'&token='.$this->token;
  702. }
  703. else
  704. $this->errors[] = Tools::displayError('An error occurred while updating the status.');
  705. }
  706. else
  707. $this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').
  708. ' <b>'.$this->table.'</b> '.
  709. Tools::displayError('(cannot load object)');
  710. return $object;
  711. }
  712. /**
  713. * Change object position
  714. */
  715. public function processPosition()
  716. {
  717. if (!Validate::isLoadedObject($object = $this->loadObject()))
  718. {
  719. $this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').
  720. ' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  721. }
  722. elseif (!$object->updatePosition((int)Tools::getValue('way'), (int)Tools::getValue('position')))
  723. $this->errors[] = Tools::displayError('Failed to update the position.');
  724. else
  725. {
  726. $id_identifier_str = ($id_identifier = (int)Tools::getValue($this->identifier)) ? '&'.$this->identifier.'='.$id_identifier : '';
  727. $redirect = self::$currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.$id_identifier_str.'&token='.$this->token;
  728. $this->redirect_after = $redirect;
  729. }
  730. return $object;
  731. }
  732. /**
  733. * Cancel all filters for this tab
  734. */
  735. public function processResetFilters()
  736. {
  737. $prefix = str_replace(array('admin', 'controller'), '', Tools::strtolower(get_class($this)));
  738. $filters = $this->context->cookie->getFamily($prefix.$this->table.'Filter_');
  739. foreach ($filters as $cookie_key => $filter)
  740. if (strncmp($cookie_key, $prefix.$this->table.'Filter_', 7 + Tools::strlen($prefix.$this->table)) == 0)
  741. {
  742. $key = substr($cookie_key, 7 + Tools::strlen($prefix.$this->table));
  743. /* Table alias could be specified using a ! eg. alias!field */
  744. $tmp_tab = explode('!', $key);
  745. $key = (count($tmp_tab) > 1 ? $tmp_tab[1] : $tmp_tab[0]);
  746. if (is_array($this->fields_list) && array_key_exists($key, $this->fields_list))
  747. unset($this->context->cookie->$cookie_key);
  748. }
  749. if (isset($this->context->cookie->{'submitFilter'.$this->table}))
  750. unset($this->context->cookie->{'submitFilter'.$this->table});
  751. if (isset($this->context->cookie->{$prefix.$this->table.'Orderby'}))
  752. unset($this->context->cookie->{$prefix.$this->table.'Orderby'});
  753. if (isset($this->context->cookie->{$prefix.$this->table.'Orderway'}))
  754. unset($this->context->cookie->{$prefix.$this->table.'Orderway'});
  755. unset($_POST);
  756. $this->_filter = false;
  757. unset($this->_filterHaving);
  758. unset($this->_having);
  759. }
  760. /**
  761. * Update options and preferences
  762. */
  763. protected function processUpdateOptions()
  764. {
  765. $this->beforeUpdateOptions();
  766. $languages = Language::getLanguages(false);
  767. $hide_multishop_checkbox = (Shop::getTotalShops(false, null) < 2) ? true : false;
  768. foreach ($this->fields_options as $category_data)
  769. {
  770. if (!isset($category_data['fields']))
  771. continue;
  772. $fields = $category_data['fields'];
  773. foreach ($fields as $field => $values)
  774. {
  775. if (isset($values['type']) && $values['type'] == 'selectLang')
  776. {
  777. foreach ($languages as $lang)
  778. if (Tools::getValue($field.'_'.strtoupper($lang['iso_code'])))
  779. $fields[$field.'_'.strtoupper($lang['iso_code'])] = array(
  780. 'type' => 'select',
  781. 'cast' => 'strval',
  782. 'identifier' => 'mode',
  783. 'list' => $values['list']
  784. );
  785. }
  786. }
  787. // Validate fields
  788. foreach ($fields as $field => $values)
  789. {
  790. // We don't validate fields with no visibility
  791. if (!$hide_multishop_checkbox && Shop::isFeatureActive() && isset($values['visibility']) && $values['visibility'] > Shop::getContext())
  792. continue;
  793. // Check if field is required
  794. if (isset($values['required']) && $values['required'] && !empty($_POST['multishopOverrideOption'][$field]))
  795. if (isset($values['type']) && $values['type'] == 'textLang')
  796. {
  797. foreach ($languages as $language)
  798. if (($value = Tools::getValue($field.'_'.$language['id_lang'])) == false && (string)$value != '0')
  799. $this->errors[] = sprintf(Tools::displayError('field %s is required.'), $values['title']);
  800. }
  801. elseif (($value = Tools::getValue($field)) == false && (string)$value != '0')
  802. $this->errors[] = sprintf(Tools::displayError('field %s is required.'), $values['title']);
  803. // Check field validator
  804. if (isset($values['type']) && $values['type'] == 'textLang')
  805. {
  806. foreach ($languages as $language)
  807. if (Tools::getValue($field.'_'.$language['id_lang']) && isset($values['validation']))
  808. if (!Validate::$values['validation'](Tools::getValue($field.'_'.$language['id_lang'])))
  809. $this->errors[] = sprintf(Tools::displayError('field %s is invalid.'), $values['title']);
  810. }
  811. elseif (Tools::getValue($field) && isset($values['validation']))
  812. if (!Validate::$values['validation'](Tools::getValue($field)))
  813. $this->errors[] = sprintf(Tools::displayError('field %s is invalid.'), $values['title']);
  814. // Set default value
  815. if (Tools::getValue($field) === false && isset($values['default']))
  816. $_POST[$field] = $values['default'];
  817. }
  818. if (!count($this->errors))
  819. {
  820. foreach ($fields as $key => $options)
  821. {
  822. if (!$hide_multishop_checkbox && Shop::isFeatureActive() && isset($options['visibility']) && $options['visibility'] > Shop::getContext())
  823. continue;
  824. if (!$hide_multishop_checkbox && Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL && empty($options['no_multishop_checkbox']) && empty($_POST['multishopOverrideOption'][$key]))
  825. {
  826. Configuration::deleteFromContext($key);
  827. continue;
  828. }
  829. // check if a method updateOptionFieldName is available
  830. $method_name = 'updateOption'.Tools::toCamelCase($key, true);
  831. if (method_exists($this, $method_name))
  832. $this->$method_name(Tools::getValue($key));
  833. elseif (isset($options['type']) && in_array($options['type'], array('textLang', 'textareaLang')))
  834. {
  835. $list = array();
  836. foreach ($languages as $language)
  837. {
  838. $key_lang = Tools::getValue($key.'_'.$language['id_lang']);
  839. $val = (isset($options['cast']) ? $options['cast']($key_lang) : $key_lang);
  840. if ($this->validateField($val, $options))
  841. {
  842. if (Validate::isCleanHtml($val))
  843. $list[$language['id_lang']] = $val;
  844. else
  845. $this->errors[] = Tools::displayError('Can not add configuration '.$key.' for lang '.Language::getIsoById((int)$language['id_lang']));
  846. }
  847. }
  848. Configuration::updateValue($key, $list);
  849. }
  850. else
  851. {
  852. $val = (isset($options['cast']) ? $options['cast'](Tools::getValue($key)) : Tools::getValue($key));
  853. if ($this->validateField($val, $options))
  854. {
  855. if (Validate::isCleanHtml($val))
  856. Configuration::updateValue($key, $val);
  857. else
  858. $this->errors[] = Tools::displayError('Can not add configuration '.$key);
  859. }
  860. }
  861. }
  862. }
  863. }
  864. $this->display = 'list';
  865. if (empty($this->errors))
  866. $this->confirmations[] = $this->_conf[6];
  867. }
  868. /**
  869. * assign default action in toolbar_btn smarty var, if they are not set.
  870. * uses override to specifically add, modify or remove items
  871. *
  872. */
  873. public function initToolbar()
  874. {
  875. switch ($this->display)
  876. {
  877. case 'add':
  878. case 'edit':
  879. // Default save button - action dynamically handled in javascript
  880. $this->toolbar_btn['save'] = array(
  881. 'href' => '#',
  882. 'desc' => $this->l('Save')
  883. );
  884. //no break
  885. case 'view':
  886. // Default cancel button - like old back link
  887. $back = Tools::safeOutput(Tools::getValue('back', ''));
  888. if (empty($back))
  889. $back = self::$currentIndex.'&token='.$this->token;
  890. if (!Validate::isCleanHtml($back))
  891. die(Tools::displayError());
  892. if (!$this->lite_display)
  893. $this->toolbar_btn['back'] = array(
  894. 'href' => $back,
  895. 'desc' => $this->l('Back to list')
  896. );
  897. break;
  898. case 'options':
  899. $this->toolbar_btn['save'] = array(
  900. 'href' => '#',
  901. 'desc' => $this->l('Save')
  902. );
  903. break;
  904. case 'view':
  905. break;
  906. default: // list
  907. $this->toolbar_btn['new'] = array(
  908. 'href' => self::$currentIndex.'&amp;add'.$this->table.'&amp;token='.$this->token,
  909. 'desc' => $this->l('Add new')
  910. );
  911. if ($this->allow_export)
  912. $this->toolbar_btn['export'] = array(
  913. 'href' => self::$currentIndex.'&amp;export'.$this->table.'&amp;token='.$this->token,
  914. 'desc' => $this->l('Export')
  915. );
  916. }
  917. $this->addToolBarModulesListButton();
  918. }
  919. /**
  920. * Load class object using identifier in $_GET (if possible)
  921. * otherwise return an empty object, or die
  922. *
  923. * @param boolean $opt Return an empty object if load fail
  924. * @return object
  925. */
  926. protected function loadObject($opt = false)
  927. {
  928. $id = (int)Tools::getValue($this->identifier);
  929. if ($id && Validate::isUnsignedId($id))
  930. {
  931. if (!$this->object)
  932. $this->object = new $this->className($id);
  933. if (Validate::isLoadedObject($this->object))
  934. return $this->object;
  935. // throw exception
  936. $this->errors[] = Tools::displayError('The object cannot be loaded (or found)');
  937. return false;
  938. }
  939. elseif ($opt)
  940. {
  941. if (!$this->object)
  942. $this->object = new $this->className();
  943. return $this->object;
  944. }
  945. else
  946. {
  947. $this->errors[] = Tools::displayError('The object cannot be loaded (ithe dentifier is missing or invalid)');
  948. return false;
  949. }
  950. return $this->object;
  951. }
  952. /**
  953. * Check if the token is valid, else display a warning page
  954. */
  955. public function checkAccess()
  956. {
  957. if (!$this->checkToken())
  958. {
  959. // If this is an XSS attempt, then we should only display a simple, secure page
  960. // ${1} in the replacement string of the regexp is required,
  961. // because the token may begin with a number and mix up with it (e.g. $17)
  962. $url = preg_replace('/([&?]token=)[^&]*(&.*)?$/', '${1}'.$this->token.'$2', $_SERVER['REQUEST_URI']);
  963. if (false === strpos($url, '?token=') && false === strpos($url, '&token='))
  964. $url .= '&token='.$this->token;
  965. if (strpos($url, '?') === false)
  966. $url = str_replace('&token', '?controller=AdminHome&token', $url);
  967. $this->context->smarty->assign('url', htmlentities($url));
  968. return false;
  969. }
  970. return true;
  971. }
  972. protected function filterToField($key, $filter)
  973. {
  974. foreach ($this->fields_list as $field)
  975. if (array_key_exists('filter_key', $field) && $field['filter_key'] == $key)
  976. return $field;
  977. if (array_key_exists($filter, $this->fields_list))
  978. return $this->fields_list[$filter];
  979. return false;
  980. }
  981. public function displayNoSmarty()
  982. {
  983. }
  984. public function displayAjax()
  985. {
  986. if ($this->json)
  987. {
  988. $this->context->smarty->assign(array(
  989. 'json' => true,
  990. 'status' => $this->status,
  991. ));
  992. }
  993. $this->layout = 'layout-ajax.tpl';
  994. return $this->display();
  995. }
  996. protected function redirect()
  997. {
  998. header('Location: '.$this->redirect_after);
  999. exit;
  1000. }
  1001. public function display()
  1002. {
  1003. $this->context->smarty->assign(array(
  1004. 'display_header' => $this->display_header,
  1005. 'display_footer' => $this->display_footer,
  1006. )
  1007. );
  1008. // Use page title from meta_title if it has been set else from the breadcrumbs array
  1009. if (!$this->meta_title)
  1010. $this->meta_title = isset($this->breadcrumbs[1]) ? $this->breadcrumbs[1] : $this->breadcrumbs[0];
  1011. $this->context->smarty->assign('meta_title', $this->meta_title);
  1012. $tpl_action = $this->tpl_folder.$this->display.'.tpl';
  1013. // Check if action template has been override
  1014. foreach ($this->context->smarty->getTemplateDir() as $template_dir)
  1015. if (file_exists($template_dir.DIRECTORY_SEPARATOR.$tpl_action) && $this->display != 'view' && $this->display != 'options')
  1016. {
  1017. if (method_exists($this, $this->display.Tools::toCamelCase($this->className)))
  1018. $this->{$this->display.Tools::toCamelCase($this->className)}();
  1019. $this->context->smarty->assign('content', $this->context->smarty->fetch($tpl_action));
  1020. break;
  1021. }
  1022. if (!$this->ajax)
  1023. {
  1024. $template = $this->createTemplate($this->template);
  1025. $page = $template->fetch();
  1026. }
  1027. else
  1028. $page = $this->content;
  1029. if ($conf = Tools::getValue('conf'))
  1030. if ($this->json)
  1031. $this->context->smarty->assign('conf', Tools::jsonEncode($this->_conf[(int)$conf]));
  1032. else
  1033. $this->context->smarty->assign('conf', $this->_conf[(int)$conf]);
  1034. $notifications_type = array('errors', 'warnings', 'informations', 'confirmations');
  1035. foreach($notifications_type as $type)
  1036. if ($this->json)
  1037. $this->context->smarty->assign($type, Tools::jsonEncode(array_unique($this->$type)));
  1038. else
  1039. $this->context->smarty->assign($type, array_unique($this->$type));
  1040. if ($this->json)
  1041. $this->context->smarty->assign('page', Tools::jsonEncode($page));
  1042. else
  1043. $this->context->smarty->assign('page', $page);
  1044. $this->smartyOutputContent($this->layout);
  1045. }
  1046. /**
  1047. * add a warning message to display at the top of the page
  1048. *
  1049. * @param string $msg
  1050. */
  1051. protected function displayWarning($msg)
  1052. {
  1053. $this->warnings[] = $msg;
  1054. }
  1055. /**
  1056. * add a info message to display at the top of the page
  1057. *
  1058. * @param string $msg
  1059. */
  1060. protected function displayInformation($msg)
  1061. {
  1062. $this->informations[] = $msg;
  1063. }
  1064. /**
  1065. * Assign smarty variables for the header
  1066. */
  1067. public function initHeader()
  1068. {
  1069. // Multishop
  1070. $is_multishop = Shop::isFeatureActive();
  1071. // Quick access
  1072. $quick_access = QuickAccess::getQuickAccesses($this->context->language->id);
  1073. foreach ($quick_access as $index => $quick)
  1074. {
  1075. if ($quick['link'] == '../' && Shop::getContext() == Shop::CONTEXT_SHOP)
  1076. {
  1077. $url = $this->context->shop->getBaseURL();
  1078. if (!$url)
  1079. {
  1080. unset($quick_access[$index]);
  1081. continue;
  1082. }
  1083. $quick_access[$index]['link'] = $url;
  1084. }
  1085. else
  1086. {
  1087. preg_match('/controller=(.+)(&.+)?$/', $quick['link'], $admin_tab);
  1088. if (isset($admin_tab[1]))
  1089. {
  1090. if (strpos($admin_tab[1], '&'))
  1091. $admin_tab[1] = substr($admin_tab[1], 0, strpos($admin_tab[1], '&'));
  1092. $token = Tools::getAdminToken($admin_tab[1].(int)Tab::getIdFromClassName($admin_tab[1]).(int)$this->context->employee->id);
  1093. $quick_access[$index]['link'] .= '&token='.$token;
  1094. }
  1095. }
  1096. }
  1097. // Tab list
  1098. $tabs = Tab::getTabs($this->context->language->id, 0);
  1099. $current_id = Tab::getCurrentParentId();
  1100. foreach ($tabs as $index => $tab)
  1101. {
  1102. if ($tab['class_name'] == 'AdminStock' && Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') == 0)
  1103. {
  1104. unset($tabs[$index]);
  1105. continue;
  1106. }
  1107. $img_cache_url = 'themes/'.$this->context->employee->bo_theme.'/img/t/'.$tab['class_name'].'.png';
  1108. $img_exists_cache = Tools::file_exists_cache(_PS_ADMIN_DIR_.$img_cache_url);
  1109. // retrocompatibility : change png to gif if icon not exists
  1110. if (!$img_exists_cache)
  1111. $img_exists_cache = Tools::file_exists_cache(_PS_ADMIN_DIR_.str_replace('.png', '.gif', $img_cache_url));
  1112. if ($img_exists_cache)
  1113. $path_img = $img = $img_exists_cache;
  1114. else
  1115. {
  1116. $path_img = _PS_IMG_DIR_.'t/'.$tab['class_name'].'.png';
  1117. // Relative link will always work, whatever the base uri set in the admin
  1118. $img = '../img/t/'.$tab['class_name'].'.png';
  1119. }
  1120. if (trim($tab['module']) != '')
  1121. {
  1122. $path_img = _PS_MODULE_DIR_.$tab['module'].'/'.$tab['class_name'].'.png';
  1123. // Relative link will always work, whatever the base uri set in the admin
  1124. $img = '../modules/'.$tab['module'].'/'.$tab['class_name'].'.png';
  1125. }
  1126. // retrocompatibility
  1127. if (!file_exists($path_img))
  1128. $img = str_replace('png', 'gif', $img);
  1129. // tab[class_name] does not contains the "Controller" suffix
  1130. $tabs[$index]['current'] = ($tab['class_name'].'Controller' == get_class($this)) || ($current_id == $tab['id_tab']);
  1131. $tabs[$index]['img'] = $img;
  1132. $tabs[$index]['href'] = $this->context->link->getAdminLink($tab['class_name']);
  1133. $sub_tabs = Tab::getTabs($this->context->language->id, $tab['id_tab']);
  1134. foreach ($sub_tabs as $index2 => $sub_tab)
  1135. {
  1136. // class_name is the name of the class controller
  1137. if (Tab::checkTabRights($sub_tab['id_tab']) === true
  1138. && (bool)$sub_tab['active'])
  1139. $sub_tabs[$index2]['href'] = $this->context->link->getAdminLink($sub_tab['class_name']);
  1140. else
  1141. unset($sub_tabs[$index2]);
  1142. }
  1143. $tabs[$index]['sub_tabs'] = $sub_tabs;
  1144. // If there are no subtabs, we don't want to display the parent tab in menu
  1145. if (empty($sub_tabs))
  1146. unset($tabs[$index]);
  1147. }
  1148. if (Validate::isLoadedObject($this->context->employee))
  1149. {
  1150. $accesses = Profile::getProfileAccesses($this->context->employee->id_profile, 'class_name');
  1151. /* Hooks are volontary out the initialize array (need those variables already assigned) */
  1152. $bo_color = empty($this->context->employee->bo_color) ? '#FFFFFF' : $this->context->employee->bo_color;
  1153. $this->context->smarty->assign(array(
  1154. 'autorefresh_notifications' => Configuration::get('PS_ADMIN_REFRESH_NOTIFICATION'),
  1155. 'help_box' => Configuration::get('PS_HELPBOX'),
  1156. 'round_mode' => Configuration::get('PS_PRICE_ROUND_MODE'),
  1157. 'brightness' => Tools::getBrightness($bo_color) < 128 ? 'white' : '#383838',
  1158. 'bo_width' => (int)$this->context->employee->bo_width,
  1159. 'bo_color' => isset($this->context->employee->bo_color) ? Tools::htmlentitiesUTF8($this->context->employee->bo_color) : null,
  1160. 'show_new_orders' => Configuration::get('PS_SHOW_NEW_ORDERS') && $accesses['AdminOrders']['view'],
  1161. 'show_new_customers' => Configuration::get('PS_SHOW_NEW_CUSTOMERS') && $accesses['AdminCustomers']['view'],
  1162. 'show_new_messages' => Configuration::get('PS_SHOW_NEW_MESSAGES') && $accesses['AdminCustomerThreads']['view'],
  1163. 'first_name' => Tools::substr($this->context->employee->firstname, 0, 1),
  1164. 'last_name' => htmlentities($this->context->employee->lastname, ENT_COMPAT, 'UTF-8'),
  1165. 'employee' => $this->context->employee,
  1166. 'search_type' => Tools::getValue('bo_search_type'),
  1167. 'bo_query' => Tools::safeOutput(Tools::stripslashes(Tools::getValue('bo_query'))),
  1168. 'quick_access' => $quick_access,
  1169. 'multi_shop' => Shop::isFeatureActive(),
  1170. 'shop_list' => Helper::renderShopList(),
  1171. 'shop' => $this->context->shop,
  1172. 'shop_group' => new ShopGroup((int)Shop::getContextShopGroupID()),
  1173. 'current_parent_id' => (int)Tab::getCurrentParentId(),
  1174. 'tabs' => $tabs,
  1175. 'is_multishop' => $is_multishop,
  1176. 'multishop_context' => $this->multishop_context,
  1177. ));
  1178. }
  1179. $this->context->smarty->assign(array(
  1180. 'img_dir' => _PS_IMG_,
  1181. 'iso' => $this->context->language->iso_code,
  1182. 'class_name' => $this->className,
  1183. 'iso_user' => $this->context->language->iso_code,
  1184. 'country_iso_code' => $this->context->country->iso_code,
  1185. 'version' => _PS_VERSION_,
  1186. 'lang_iso' => $this->context->language->iso_code,
  1187. 'link' => $this->context->link,
  1188. 'shop_name' => Configuration::get('PS_SHOP_NAME'),
  1189. 'base_url' => $this->context->shop->getBaseURL(),
  1190. 'tab' => $tab, // Deprecated, this tab is declared in the foreach, so it's the last tab in the foreach
  1191. 'current_parent_id' => (int)Tab::getCurrentParentId(),
  1192. 'tabs' => $tabs,
  1193. 'install_dir_exists' => file_exists(_PS_ADMIN_DIR_.'/../install'),
  1194. 'pic_dir' => _THEME_PROD_PIC_DIR_,
  1195. 'controller_name' => htmlentities(Tools::getValue('controller')),
  1196. 'currentIndex' => self::$currentIndex
  1197. ));
  1198. }
  1199. /**
  1200. * Declare an action to use for each row in the list
  1201. */
  1202. public function addRowAction($action)
  1203. {
  1204. $action = strtolower($action);
  1205. $this->actions[] = $action;
  1206. }
  1207. /**
  1208. * Add an action to use for each row in the list
  1209. */
  1210. public function addRowActionSkipList($action, $list)
  1211. {
  1212. $action = strtolower($action);
  1213. $list = (array)$list;
  1214. if (array_key_exists($action, $this->list_skip_actions))
  1215. $this->list_skip_actions[$action] = array_merge($this->list_skip_actions[$action], $list);
  1216. else
  1217. $this->list_skip_actions[$action] = $list;
  1218. }
  1219. /**
  1220. * Assign smarty variables for all default views, list and form, then call other init functions
  1221. */
  1222. public function initContent()
  1223. {
  1224. if (!$this->viewAccess())
  1225. {
  1226. $this->errors[] = Tools::displayError('You do not have permission to view this.');
  1227. return;
  1228. }
  1229. $this->getLanguages();
  1230. // toolbar (save, cancel, new, ..)
  1231. $this->initToolbar();
  1232. $this->initTabModuleList();
  1233. if ($this->display == 'edit' || $this->display == 'add')
  1234. {
  1235. if (!$this->loadObject(true))
  1236. return;
  1237. $this->content .= $this->renderForm();
  1238. }
  1239. elseif ($this->display == 'view')
  1240. {
  1241. // Some controllers use the view action without an object
  1242. if ($this->className)
  1243. $this->loadObject(true);
  1244. $this->content .= $this->renderView();
  1245. }
  1246. elseif (!$this->ajax)
  1247. {
  1248. $this->content .= $this->renderModulesList();
  1249. $this->content .= $this->renderList();
  1250. $this->content .= $this->renderOptions();
  1251. // if we have to display the required fields form
  1252. if ($this->required_database)
  1253. $this->content .= $this->displayRequiredFields();
  1254. }
  1255. $this->context->smarty->assign(array(
  1256. 'content' => $this->content,
  1257. 'url_post' => self::$currentIndex.'&token='.$this->token,
  1258. ));
  1259. }
  1260. /**
  1261. * init tab modules list and add button in toolbar
  1262. */
  1263. protected function initTabModuleList()
  1264. {
  1265. if (!$this->isFresh(Module::CACHE_FILE_TAB_MODULES_LIST, 604800))
  1266. $this->refresh(Module::CACHE_FILE_TAB_MODULES_LIST, 'http://'.Tab::TAB_MODULE_LIST_URL);
  1267. $this->tab_modules_list = Tab::getTabModulesList($this->id);
  1268. if (is_array($this->tab_modules_list['default_list']) && count($this->tab_modules_list['default_list']))
  1269. $this->filter_modules_list = $this->tab_modules_list['default_list'];
  1270. elseif (is_array($this->tab_modules_list['slider_list']) && count($this->tab_modules_list['slider_list']))
  1271. {
  1272. $this->addToolBarModulesListButton();
  1273. $this->context->smarty->assign(array(
  1274. 'tab_modules_list' => implode(',', $this->tab_modules_list['slider_list']),
  1275. 'admin_module_ajax_url' => $this->context->link->getAdminLink('AdminModules'),
  1276. 'back_tab_modules_list' => $this->context->link->getAdminLink(Tools::getValue('controller')),
  1277. 'tab_modules_open' => (int)Tools::getValue('tab_modules_open')
  1278. ));
  1279. }
  1280. }
  1281. protected function

Large files files are truncated, but you can click here to view the full file