1<?php 2/** 3 * Copyright since 2007 PrestaShop SA and Contributors 4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA 5 * 6 * NOTICE OF LICENSE 7 * 8 * This source file is subject to the Open Software License (OSL 3.0) 9 * that is bundled with this package in the file LICENSE.md. 10 * It is also available through the world-wide-web at this URL: 11 * https://opensource.org/licenses/OSL-3.0 12 * If you did not receive a copy of the license and are unable to 13 * obtain it through the world-wide-web, please send an email 14 * to license@prestashop.com so we can send you a copy immediately. 15 * 16 * DISCLAIMER 17 * 18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 19 * versions in the future. If you wish to customize PrestaShop for your 20 * needs please refer to https://devdocs.prestashop.com/ for more information. 21 * 22 * @author PrestaShop SA and Contributors <contact@prestashop.com> 23 * @copyright Since 2007 PrestaShop SA and Contributors 24 * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) 25 */ 26class TreeCore 27{ 28 const DEFAULT_TEMPLATE_DIRECTORY = 'helpers/tree'; 29 const DEFAULT_TEMPLATE = 'tree.tpl'; 30 const DEFAULT_HEADER_TEMPLATE = 'tree_header.tpl'; 31 const DEFAULT_NODE_FOLDER_TEMPLATE = 'tree_node_folder.tpl'; 32 const DEFAULT_NODE_ITEM_TEMPLATE = 'tree_node_item.tpl'; 33 34 protected $_attributes; 35 private $_context; 36 protected $_data; 37 protected $_data_search; 38 protected $_headerTemplate; 39 protected $_id_tree; 40 private $_id; 41 protected $_node_folder_template; 42 protected $_node_item_template; 43 protected $_template; 44 45 /** @var string */ 46 private $_template_directory; 47 private $_title; 48 private $_no_js; 49 50 /** @var TreeToolbar|ITreeToolbar */ 51 private $_toolbar; 52 53 /** @var Translator */ 54 public $translator; 55 56 public function __construct($id, $data = null) 57 { 58 $this->translator = Context::getContext()->getTranslator(); 59 $this->setId($id); 60 61 if (isset($data)) { 62 $this->setData($data); 63 } 64 } 65 66 public function __toString() 67 { 68 return $this->render(); 69 } 70 71 public function setActions($value) 72 { 73 if (!isset($this->_toolbar)) { 74 $this->setToolbar(new TreeToolbarCore()); 75 } 76 77 $this->getToolbar()->setTemplateDirectory($this->getTemplateDirectory())->setActions($value); 78 79 return $this; 80 } 81 82 public function getActions() 83 { 84 if (!isset($this->_toolbar)) { 85 $this->setToolbar(new TreeToolbarCore()); 86 } 87 88 return $this->getToolbar()->setTemplateDirectory($this->getTemplateDirectory())->getActions(); 89 } 90 91 public function setAttribute($name, $value) 92 { 93 if (!isset($this->_attributes)) { 94 $this->_attributes = []; 95 } 96 97 $this->_attributes[$name] = $value; 98 99 return $this; 100 } 101 102 public function getAttribute($name) 103 { 104 return $this->hasAttribute($name) ? $this->_attributes[$name] : null; 105 } 106 107 public function setAttributes($value) 108 { 109 if (!is_array($value) && !$value instanceof Traversable) { 110 throw new PrestaShopException('Data value must be an traversable array'); 111 } 112 113 $this->_attributes = $value; 114 115 return $this; 116 } 117 118 public function setIdTree($id_tree) 119 { 120 $this->_id_tree = $id_tree; 121 122 return $this; 123 } 124 125 public function getIdTree() 126 { 127 return $this->_id_tree; 128 } 129 130 public function getAttributes() 131 { 132 if (!isset($this->_attributes)) { 133 $this->_attributes = []; 134 } 135 136 return $this->_attributes; 137 } 138 139 public function setContext($value) 140 { 141 $this->_context = $value; 142 143 return $this; 144 } 145 146 public function getContext() 147 { 148 if (!isset($this->_context)) { 149 $this->_context = Context::getContext(); 150 } 151 152 return $this->_context; 153 } 154 155 public function setDataSearch($value) 156 { 157 if (!is_array($value) && !$value instanceof Traversable) { 158 throw new PrestaShopException('Data value must be an traversable array'); 159 } 160 161 $this->_data_search = $value; 162 163 return $this; 164 } 165 166 public function getDataSearch() 167 { 168 if (!isset($this->_data_search)) { 169 $this->_data_search = []; 170 } 171 172 return $this->_data_search; 173 } 174 175 public function setData($value) 176 { 177 if (!is_array($value) && !$value instanceof Traversable) { 178 throw new PrestaShopException('Data value must be an traversable array'); 179 } 180 181 $this->_data = $value; 182 183 return $this; 184 } 185 186 public function getData() 187 { 188 if (!isset($this->_data)) { 189 $this->_data = []; 190 } 191 192 return $this->_data; 193 } 194 195 public function setHeaderTemplate($value) 196 { 197 $this->_headerTemplate = $value; 198 199 return $this; 200 } 201 202 public function getHeaderTemplate() 203 { 204 if (!isset($this->_headerTemplate)) { 205 $this->setHeaderTemplate(self::DEFAULT_HEADER_TEMPLATE); 206 } 207 208 return $this->_headerTemplate; 209 } 210 211 public function setId($value) 212 { 213 $this->_id = $value; 214 215 return $this; 216 } 217 218 public function getId() 219 { 220 return $this->_id; 221 } 222 223 public function setNodeFolderTemplate($value) 224 { 225 $this->_node_folder_template = $value; 226 227 return $this; 228 } 229 230 public function getNodeFolderTemplate() 231 { 232 if (!isset($this->_node_folder_template)) { 233 $this->setNodeFolderTemplate(self::DEFAULT_NODE_FOLDER_TEMPLATE); 234 } 235 236 return $this->_node_folder_template; 237 } 238 239 public function setNodeItemTemplate($value) 240 { 241 $this->_node_item_template = $value; 242 243 return $this; 244 } 245 246 public function getNodeItemTemplate() 247 { 248 if (!isset($this->_node_item_template)) { 249 $this->setNodeItemTemplate(self::DEFAULT_NODE_ITEM_TEMPLATE); 250 } 251 252 return $this->_node_item_template; 253 } 254 255 public function setTemplate($value) 256 { 257 $this->_template = $value; 258 259 return $this; 260 } 261 262 public function getTemplate() 263 { 264 if (!isset($this->_template)) { 265 $this->setTemplate(self::DEFAULT_TEMPLATE); 266 } 267 268 return $this->_template; 269 } 270 271 /** 272 * @param $value 273 * 274 * @return Tree 275 */ 276 public function setTemplateDirectory($value) 277 { 278 $this->_template_directory = $this->_normalizeDirectory($value); 279 280 return $this; 281 } 282 283 /** 284 * @return string 285 */ 286 public function getTemplateDirectory() 287 { 288 if (!isset($this->_template_directory)) { 289 $this->_template_directory = $this->_normalizeDirectory( 290 self::DEFAULT_TEMPLATE_DIRECTORY 291 ); 292 } 293 294 return $this->_template_directory; 295 } 296 297 public function getTemplateFile($template) 298 { 299 if (preg_match_all('/((?:^|[A-Z])[a-z]+)/', get_class($this->getContext()->controller), $matches) !== false) { 300 $controller_name = strtolower($matches[0][1]); 301 } 302 303 if ($this->getContext()->controller instanceof ModuleAdminController && isset($controller_name) && file_exists($this->_normalizeDirectory( 304 $this->getContext()->controller->getTemplatePath() 305 ) . $controller_name . DIRECTORY_SEPARATOR . $this->getTemplateDirectory() . $template)) { 306 return $this->_normalizeDirectory($this->getContext()->controller->getTemplatePath()) . 307 $controller_name . DIRECTORY_SEPARATOR . $this->getTemplateDirectory() . $template; 308 } elseif ($this->getContext()->controller instanceof ModuleAdminController && file_exists($this->_normalizeDirectory( 309 $this->getContext()->controller->getTemplatePath() 310 ) . $this->getTemplateDirectory() . $template)) { 311 return $this->_normalizeDirectory($this->getContext()->controller->getTemplatePath()) 312 . $this->getTemplateDirectory() . $template; 313 } elseif ($this->getContext()->controller instanceof AdminController && isset($controller_name) 314 && file_exists($this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(0)) . 'controllers' 315 . DIRECTORY_SEPARATOR . $controller_name . DIRECTORY_SEPARATOR . $this->getTemplateDirectory() . $template)) { 316 return $this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(0)) . 'controllers' 317 . DIRECTORY_SEPARATOR . $controller_name . DIRECTORY_SEPARATOR . $this->getTemplateDirectory() . $template; 318 } elseif (file_exists($this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(1)) 319 . $this->getTemplateDirectory() . $template)) { 320 return $this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(1)) 321 . $this->getTemplateDirectory() . $template; 322 } elseif (file_exists($this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(0)) 323 . $this->getTemplateDirectory() . $template)) { 324 return $this->_normalizeDirectory($this->getContext()->smarty->getTemplateDir(0)) 325 . $this->getTemplateDirectory() . $template; 326 } else { 327 return $this->getTemplateDirectory() . $template; 328 } 329 } 330 331 public function setNoJS($value) 332 { 333 $this->_no_js = $value; 334 335 return $this; 336 } 337 338 public function setTitle($value) 339 { 340 $this->_title = $value; 341 342 return $this; 343 } 344 345 public function getTitle() 346 { 347 return $this->_title; 348 } 349 350 public function setToolbar($value) 351 { 352 if (!is_object($value)) { 353 throw new PrestaShopException('Toolbar must be a class object'); 354 } 355 356 $reflection = new ReflectionClass($value); 357 358 if (!$reflection->implementsInterface('ITreeToolbarCore')) { 359 throw new PrestaShopException('Toolbar class must implements ITreeToolbarCore interface'); 360 } 361 362 $this->_toolbar = $value; 363 364 return $this; 365 } 366 367 public function getToolbar() 368 { 369 if (isset($this->_toolbar)) { 370 if ($this->getDataSearch()) { 371 $this->_toolbar->setData($this->getDataSearch()); 372 } else { 373 $this->_toolbar->setData($this->getData()); 374 } 375 } 376 377 return $this->_toolbar; 378 } 379 380 public function addAction($action) 381 { 382 if (!isset($this->_toolbar)) { 383 $this->setToolbar(new TreeToolbarCore()); 384 } 385 386 $this->getToolbar()->setTemplateDirectory($this->getTemplateDirectory())->addAction($action); 387 388 return $this; 389 } 390 391 public function removeActions() 392 { 393 if (!isset($this->_toolbar)) { 394 $this->setToolbar(new TreeToolbarCore()); 395 } 396 397 $this->getToolbar()->setTemplateDirectory($this->getTemplateDirectory())->removeActions(); 398 399 return $this; 400 } 401 402 public function render($data = null) 403 { 404 //Adding tree.js 405 $admin_webpath = str_ireplace(_PS_CORE_DIR_, '', _PS_ADMIN_DIR_); 406 $admin_webpath = preg_replace('/^' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', '', $admin_webpath); 407 $bo_theme = ((Validate::isLoadedObject($this->getContext()->employee) 408 && $this->getContext()->employee->bo_theme) ? $this->getContext()->employee->bo_theme : 'default'); 409 410 if (!file_exists(_PS_BO_ALL_THEMES_DIR_ . $bo_theme . DIRECTORY_SEPARATOR . 'template')) { 411 $bo_theme = 'default'; 412 } 413 414 $js_path = __PS_BASE_URI__ . $admin_webpath . '/themes/' . $bo_theme . '/js/tree.js'; 415 if ($this->getContext()->controller->ajax) { 416 if (!$this->_no_js) { 417 $html = '<script type="text/javascript" src="' . $js_path . '"></script>'; 418 } 419 } else { 420 $this->getContext()->controller->addJs($js_path); 421 } 422 423 //Create Tree Template 424 $template = $this->getContext()->smarty->createTemplate( 425 $this->getTemplateFile($this->getTemplate()), 426 $this->getContext()->smarty 427 ); 428 429 if (trim($this->getTitle()) != '' || $this->useToolbar()) { 430 //Create Tree Header Template 431 $headerTemplate = $this->getContext()->smarty->createTemplate( 432 $this->getTemplateFile($this->getHeaderTemplate()), 433 $this->getContext()->smarty 434 ); 435 $headerTemplate->assign($this->getAttributes()) 436 ->assign( 437 [ 438 'title' => $this->getTitle(), 439 'toolbar' => $this->useToolbar() ? $this->renderToolbar() : null, 440 ] 441 ); 442 $template->assign('header', $headerTemplate->fetch()); 443 } 444 445 //Assign Tree nodes 446 $template->assign($this->getAttributes())->assign([ 447 'id' => $this->getId(), 448 'nodes' => $this->renderNodes($data), 449 'id_tree' => $this->getIdTree(), 450 ]); 451 452 return (isset($html) ? $html : '') . $template->fetch(); 453 } 454 455 public function renderNodes($data = null) 456 { 457 if (!isset($data)) { 458 $data = $this->getData(); 459 } 460 461 if (!is_array($data) && !$data instanceof Traversable) { 462 throw new PrestaShopException('Data value must be an traversable array'); 463 } 464 465 $html = ''; 466 467 foreach ($data as $item) { 468 if (array_key_exists('children', $item) 469 && !empty($item['children'])) { 470 $html .= $this->getContext()->smarty->createTemplate( 471 $this->getTemplateFile($this->getNodeFolderTemplate()), 472 $this->getContext()->smarty 473 )->assign([ 474 'children' => $this->renderNodes($item['children']), 475 'node' => $item, 476 ])->fetch(); 477 } else { 478 $html .= $this->getContext()->smarty->createTemplate( 479 $this->getTemplateFile($this->getNodeItemTemplate()), 480 $this->getContext()->smarty 481 )->assign([ 482 'node' => $item, 483 ])->fetch(); 484 } 485 } 486 487 return $html; 488 } 489 490 public function renderToolbar() 491 { 492 return $this->getToolbar()->render(); 493 } 494 495 public function useInput() 496 { 497 return isset($this->_input_type); 498 } 499 500 public function useToolbar() 501 { 502 return isset($this->_toolbar); 503 } 504 505 private function _normalizeDirectory($directory) 506 { 507 $last = $directory[strlen($directory) - 1]; 508 509 if (in_array($last, ['/', '\\'])) { 510 $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR; 511 512 return $directory; 513 } 514 515 $directory .= DIRECTORY_SEPARATOR; 516 517 return $directory; 518 } 519} 520