1<?php 2/** 3 * Copyright (C) 2017-2019 thirty bees 4 * Copyright (C) 2007-2016 PrestaShop 5 * 6 * thirty bees is an extension to the PrestaShop software by PrestaShop SA. 7 * 8 * NOTICE OF LICENSE 9 * 10 * This source file is subject to the Open Software License (OSL 3.0) 11 * that is bundled with this package in the file LICENSE.md. 12 * It is also available through the world-wide-web at this URL: 13 * https://opensource.org/licenses/osl-3.0.php 14 * If you did not receive a copy of the license and are unable to 15 * obtain it through the world-wide-web, please send an email 16 * to license@thirtybees.com so we can send you a copy immediately. 17 * 18 * @author thirty bees <contact@thirtybees.com> 19 * @author PrestaShop SA <contact@prestashop.com> 20 * @copyright 2017-2019 thirty bees 21 * @copyright 2007-2016 PrestaShop SA 22 * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 23 * PrestaShop is an internationally registered trademark of PrestaShop SA. 24 */ 25 26namespace TbUpdaterModule; 27 28/** 29 * Class HookCore 30 * 31 * @since 1.0.0 32 */ 33class Hook extends ObjectModel 34{ 35 // @codingStandardsIgnoreStart 36 /** 37 * @var array List of executed hooks on this page 38 */ 39 public static $executed_hooks = []; 40 public static $native_module; 41 /** 42 * @deprecated 1.0.0 43 */ 44 protected static $_hook_modules_cache = null; 45 /** 46 * @deprecated 1.0.0 47 */ 48 protected static $_hook_modules_cache_exec = null; 49 /** 50 * @var string Hook name identifier 51 */ 52 public $name; 53 /** 54 * @var string Hook title (displayed in BO) 55 */ 56 public $title; 57 /** 58 * @var string Hook description 59 */ 60 public $description; 61 /** 62 * @var bool 63 */ 64 public $position = false; 65 /** 66 * @var bool Is this hook usable with live edit ? 67 */ 68 public $live_edit = false; 69 // @codingStandardsIgnoreEnd 70 71 /** 72 * @see ObjectModel::$definition 73 */ 74 public static $definition = [ 75 'table' => 'hook', 76 'primary' => 'id_hook', 77 'fields' => [ 78 'name' => ['type' => self::TYPE_STRING, 'validate' => 'isHookName', 'required' => true, 'size' => 64], 79 'title' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName'], 80 'description' => ['type' => self::TYPE_HTML, 'validate' => 'isCleanHtml'], 81 'position' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 82 'live_edit' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 83 ], 84 ]; 85 86 /** 87 * Return Hooks List 88 * 89 * @param bool $position 90 * 91 * @return array Hooks List 92 * 93 * @since 1.0.0 94 * @version 1.0.0 Initial version 95 */ 96 public static function getHooks($position = false) 97 { 98 return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 99 ' 100 SELECT * FROM `'._DB_PREFIX_.'hook` h 101 '.($position ? 'WHERE h.`position` = 1' : '').' 102 ORDER BY `name`' 103 ); 104 } 105 106 /** 107 * Return hook ID from name 108 * 109 * @since 1.0.0 110 * @version 1.0.0 Initial version 111 */ 112 public static function getNameById($hookId) 113 { 114 $cacheId = 'hook_namebyid_'.$hookId; 115 if (!Cache::isStored($cacheId)) { 116 $result = Db::getInstance()->getValue( 117 ' 118 SELECT `name` 119 FROM `'._DB_PREFIX_.'hook` 120 WHERE `id_hook` = '.(int) $hookId 121 ); 122 Cache::store($cacheId, $result); 123 124 return $result; 125 } 126 127 return Cache::retrieve($cacheId); 128 } 129 130 /** 131 * Return hook live edit bool from ID 132 * 133 * @since 1.0.0 134 * @version 1.0.0 Initial version 135 */ 136 public static function getLiveEditById($hookId) 137 { 138 $cacheId = 'hook_live_editbyid_'.$hookId; 139 if (!Cache::isStored($cacheId)) { 140 $result = Db::getInstance()->getValue( 141 ' 142 SELECT `live_edit` 143 FROM `'._DB_PREFIX_.'hook` 144 WHERE `id_hook` = '.(int) $hookId 145 ); 146 Cache::store($cacheId, $result); 147 148 return $result; 149 } 150 151 return Cache::retrieve($cacheId); 152 } 153 154 /** 155 * Return Hooks List 156 * 157 * @since 1.5.0 158 * 159 * @param int $idHook 160 * @param int $idModule 161 * 162 * @return array Modules List 163 * 164 * @since 1.0.0 165 * @version 1.0.0 Initial version 166 */ 167 public static function getModulesFromHook($idHook, $idModule = null) 168 { 169 $hmList = Hook::getHookModuleList(); 170 $moduleList = (isset($hmList[$idHook])) ? $hmList[$idHook] : []; 171 172 if ($idModule) { 173 return (isset($moduleList[$idModule])) ? [$moduleList[$idModule]] : []; 174 } 175 176 return $moduleList; 177 } 178 179 /** 180 * Get list of all registered hooks with modules 181 * 182 * @return array 183 * 184 * @since 1.0.0 185 * @version 1.0.0 Initial version 186 */ 187 public static function getHookModuleList() 188 { 189 $cacheId = 'hook_module_list'; 190 if (!Cache::isStored($cacheId)) { 191 $results = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 192 ' 193 SELECT h.id_hook, h.name AS h_name, title, description, h.position, live_edit, hm.position AS hm_position, m.id_module, m.name, active 194 FROM `'._DB_PREFIX_.'hook_module` hm 195 STRAIGHT_JOIN `'._DB_PREFIX_.'hook` h ON (h.id_hook = hm.id_hook AND hm.id_shop = '.(int) Context::getContext()->shop->id.') 196 STRAIGHT_JOIN `'._DB_PREFIX_.'module` AS m ON (m.id_module = hm.id_module) 197 ORDER BY hm.position' 198 ); 199 $list = []; 200 foreach ($results as $result) { 201 if (!isset($list[$result['id_hook']])) { 202 $list[$result['id_hook']] = []; 203 } 204 205 $list[$result['id_hook']][$result['id_module']] = [ 206 'id_hook' => $result['id_hook'], 207 'title' => $result['title'], 208 'description' => $result['description'], 209 'hm.position' => $result['position'], 210 'live_edit' => $result['live_edit'], 211 'm.position' => $result['hm_position'], 212 'id_module' => $result['id_module'], 213 'name' => $result['name'], 214 'active' => $result['active'], 215 ]; 216 } 217 Cache::store($cacheId, $list); 218 219 // @todo remove this in 1.6, we keep it in 1.5 for retrocompatibility 220 Hook::$_hook_modules_cache = $list; 221 222 return $list; 223 } 224 225 return Cache::retrieve($cacheId); 226 } 227 228 /** 229 * @deprecated 1.0.0 230 * 231 * @param $newOrderStatusId 232 * @param $idOrder 233 * 234 * @return bool|string 235 */ 236 public static function updateOrderStatus($newOrderStatusId, $idOrder) 237 { 238 Tools::displayAsDeprecated(); 239 $order = new Order((int) $idOrder); 240 $new_os = new OrderState((int) $newOrderStatusId, $order->id_lang); 241 242 $return = ((int) $new_os->id == Configuration::get('PS_OS_PAYMENT')) ? Hook::exec('paymentConfirm', ['id_order' => (int) ($order->id)]) : true; 243 $return = Hook::exec('updateOrderStatus', ['newOrderStatus' => $new_os, 'id_order' => (int) ($order->id)]) && $return; 244 245 return $return; 246 } 247 248 /** 249 * Execute modules for specified hook 250 * 251 * @param string $hookName Hook Name 252 * @param array $hookArgs Parameters for the functions 253 * @param int $idModule Execute hook for this module only 254 * @param bool $arrayReturn If specified, module output will be set by name in an array 255 * @param bool $checkExceptions Check permission exceptions 256 * @param bool $usePush Force change to be refreshed on Dashboard widgets 257 * @param int $idShop If specified, hook will be execute the shop with this ID 258 * 259 * @throws \Exception 260 * 261 * @return string|array modules output 262 * 263 * @since 1.0.0 264 * @version 1.0.0 Initial version 265 */ 266 public static function exec( 267 $hookName, 268 $hookArgs = [], 269 $idModule = null, 270 $arrayReturn = false, 271 $checkExceptions = true, 272 $usePush = false, 273 $idShop = null 274 ) { 275 if (!Configuration::get('TB_PAGE_CACHE_ENABLED')) { 276 return static::execWithoutCache($hookName, $hookArgs, $idModule, $arrayReturn, $checkExceptions, $usePush, $idShop); 277 } 278 279 $activehooks = json_decode(Configuration::get('TB_PAGE_CACHE_HOOKS'), true); 280 281 $found = false; 282 if (is_array($activehooks)) { 283 foreach ($activehooks as $hookArr) { 284 if (is_array($hookArr) && in_array($hookName, $hookArr)) { 285 $found = true; 286 break; 287 } 288 } 289 } 290 291 if (!$found) { 292 return static::execWithoutCache($hookName, $hookArgs, $idModule, $arrayReturn, $checkExceptions, $usePush, $idShop); 293 } 294 295 if (!$moduleList = static::getHookModuleExecList($hookName)) { 296 return ''; 297 } 298 299 if ($arrayReturn) { 300 $return = array(); 301 } else { 302 $return = ''; 303 } 304 305 if (!$idModule) { 306 foreach ($moduleList as $m) { 307 try { 308 $data = static::execWithoutCache($hookName, $hookArgs, $m['id_module'], $arrayReturn, $checkExceptions, $usePush, $idShop); 309 } catch (Exception $e) { 310 $data = sprintf(Tools::displayError('Error while displaying module "%s"'), Module::getInstanceById($m['id_module'])->displayName); 311 } 312 if (is_array($data)) { 313 $data = array_shift($data); 314 } 315 if (is_array($data)) { 316 $return[$m['module']] = $data; 317 } else { 318 if (isset($activehooks[$m['id_module']]) && in_array($hookName, $activehooks[$m['id_module']])) { 319 $dataWrapped = '<!--[hook '.$hookName.'] [id_module '.$m['id_module'].']-->'.$data.'<!--[hook '.$hookName.'] [id_module '.$m['id_module'].']-->'; 320 } else { 321 $dataWrapped = $data; 322 } 323 324 if ($arrayReturn) { 325 $return[$m['module']] = $dataWrapped; 326 } else { 327 $return .= $dataWrapped; 328 } 329 } 330 } 331 } else { 332 try { 333 $return = static::execWithoutCache($hookName, $hookArgs, $idModule, $arrayReturn, $checkExceptions, $usePush, $idShop); 334 } catch (Exception $e) { 335 $return = sprintf(Tools::displayError('Error while displaying module "%s"'), Module::getInstanceById($idModule)->displayName); 336 } 337 } 338 339 return $return; 340 } 341 342 /** 343 * Execute modules for specified hook 344 * 345 * @param string $hookName Hook Name 346 * @param array $hookArgs Parameters for the functions 347 * @param int $idModule Execute hook for this module only 348 * @param bool $arrayReturn If specified, module output will be set by name in an array 349 * @param bool $checkExceptions Check permission exceptions 350 * @param bool $usePush Force change to be refreshed on Dashboard widgets 351 * @param int $idShop If specified, hook will be execute the shop with this ID 352 * 353 * @throws \Exception 354 * 355 * @return string/array modules output 356 * 357 * @since 1.0.0 358 * @version 1.0.0 Initial version 359 */ 360 public static function execWithoutCache( 361 $hookName, 362 $hookArgs = [], 363 $idModule = null, 364 $arrayReturn = false, 365 $checkExceptions = true, 366 $usePush = false, 367 $idShop = null 368 ) { 369 if (defined('TB_INSTALLATION_IN_PROGRESS')) { 370 return; 371 } 372 373 static $disableNonNativeModules = null; 374 if ($disableNonNativeModules === null) { 375 $disableNonNativeModules = (bool) Configuration::get('PS_DISABLE_NON_NATIVE_MODULE'); 376 } 377 378 // Check arguments validity 379 if (($idModule && !is_numeric($idModule)) || !Validate::isHookName($hookName)) { 380 throw new \Exception('Invalid id_module or hook_name'); 381 } 382 383 // If no modules associated to hook_name or recompatible hook name, we stop the function 384 385 if (!$moduleList = Hook::getHookModuleExecList($hookName)) { 386 return ''; 387 } 388 389 // Check if hook exists 390 if (!$idHook = Hook::getIdByName($hookName)) { 391 return false; 392 } 393 394 // Store list of executed hooks on this page 395 Hook::$executed_hooks[$idHook] = $hookName; 396 397 $liveEdit = false; 398 $context = Context::getContext(); 399 if (!isset($hookArgs['cookie']) || !$hookArgs['cookie']) { 400 $hookArgs['cookie'] = $context->cookie; 401 } 402 if (!isset($hookArgs['cart']) || !$hookArgs['cart']) { 403 $hookArgs['cart'] = $context->cart; 404 } 405 406 $retroHookName = Hook::getRetroHookName($hookName); 407 408 // Look on modules list 409 $altern = 0; 410 if ($arrayReturn) { 411 $output = []; 412 } else { 413 $output = ''; 414 } 415 416 if ($disableNonNativeModules && !isset(Hook::$native_module)) { 417 Hook::$native_module = Module::getNativeModuleList(); 418 } 419 420 $differentShop = false; 421 if ($idShop !== null && Validate::isUnsignedId($idShop) && $idShop != $context->shop->getContextShopID()) { 422 $oldContext = $context->shop->getContext(); 423 $oldShop = clone $context->shop; 424 $shop = new Shop((int) $idShop); 425 if (Validate::isLoadedObject($shop)) { 426 $context->shop = $shop; 427 $context->shop->setContext(Shop::CONTEXT_SHOP, $shop->id); 428 $differentShop = true; 429 } 430 } 431 432 foreach ($moduleList as $array) { 433 // Check errors 434 if ($idModule && $idModule != $array['id_module']) { 435 continue; 436 } 437 438 if ((bool) $disableNonNativeModules && Hook::$native_module && count(Hook::$native_module) && !in_array($array['module'], Hook::$native_module)) { 439 continue; 440 } 441 442 // Check permissions 443 if ($checkExceptions) { 444 $exceptions = Module::getExceptionsStatic($array['id_module'], $array['id_hook']); 445 446 $controller = Dispatcher::getInstance()->getController(); 447 $controllerObj = Context::getContext()->controller; 448 449 //check if current controller is a module controller 450 if (isset($controllerObj->module) && Validate::isLoadedObject($controllerObj->module)) { 451 $controller = 'module-'.$controllerObj->module->name.'-'.$controller; 452 } 453 454 if (in_array($controller, $exceptions)) { 455 continue; 456 } 457 458 //Backward compatibility of controller names 459 $matchingName = [ 460 'authentication' => 'auth', 461 'productscomparison' => 'compare', 462 ]; 463 if (isset($matchingName[$controller]) && in_array($matchingName[$controller], $exceptions)) { 464 continue; 465 } 466 if (Validate::isLoadedObject($context->employee) && !Module::getPermissionStatic($array['id_module'], 'view', $context->employee)) { 467 continue; 468 } 469 } 470 471 if (!($moduleInstance = Module::getInstanceByName($array['module']))) { 472 continue; 473 } 474 475 if ($usePush && !$moduleInstance->allow_push) { 476 continue; 477 } 478 // Check which / if method is callable 479 $hookCallable = is_callable([$moduleInstance, 'hook'.$hookName]); 480 $hookRetroCallable = is_callable([$moduleInstance, 'hook'.$retroHookName]); 481 482 if (($hookCallable || $hookRetroCallable) && Module::preCall($moduleInstance->name)) { 483 $hookArgs['altern'] = ++$altern; 484 485 if ($usePush && isset($moduleInstance->push_filename) && file_exists($moduleInstance->push_filename)) { 486 Tools::waitUntilFileIsModified($moduleInstance->push_filename, $moduleInstance->push_time_limit); 487 } 488 489 // Call hook method 490 if ($hookCallable) { 491 $display = Hook::coreCallHook($moduleInstance, 'hook'.$hookName, $hookArgs); 492 } elseif ($hookRetroCallable) { 493 $display = Hook::coreCallHook($moduleInstance, 'hook'.$retroHookName, $hookArgs); 494 } 495 496 // Live edit 497 if (!$arrayReturn && $array['live_edit'] && Tools::isSubmit('live_edit') && Tools::getValue('ad') 498 && Tools::getValue('liveToken') == Tools::getAdminToken( 499 'AdminModulesPositions' 500 .(int) Tab::getIdFromClassName('AdminModulesPositions').(int) Tools::getValue('id_employee') 501 ) 502 ) { 503 $liveEdit = true; 504 $output .= static::wrapLiveEdit($display, $moduleInstance, $array['id_hook']); 505 } elseif ($arrayReturn) { 506 $output[$moduleInstance->name] = $display; 507 } else { 508 $output .= $display; 509 } 510 } 511 } 512 513 if ($differentShop) { 514 $context->shop = $oldShop; 515 $context->shop->setContext($oldContext, $shop->id); 516 } 517 518 if ($arrayReturn) { 519 return $output; 520 } else { 521 return ($liveEdit ? '<script type="text/javascript">hooks_list.push(\''.$hookName.'\');</script> 522 <div id="'.$hookName.'" class="dndHook" style="min-height:50px">' : '').$output.($liveEdit ? '</div>' : ''); 523 }// Return html string 524 } 525 526 /** 527 * Get list of modules we can execute per hook 528 * 529 * @param string $hookName Get list of modules for this hook if given 530 * 531 * @return array 532 * 533 * @since 1.0.0 534 * @version 1.0.0 Initial version 535 */ 536 public static function getHookModuleExecList($hookName = null) 537 { 538 $context = Context::getContext(); 539 $cacheId = 'hook_module_exec_list_'.(isset($context->shop->id) ? '_'.$context->shop->id : '').((isset($context->customer)) ? '_'.$context->customer->id : ''); 540 if (!Cache::isStored($cacheId) || $hookName == 'displayPayment' || $hookName == 'displayPaymentEU' || $hookName == 'displayBackOfficeHeader') { 541 $frontend = true; 542 $groups = []; 543 $useGroups = Group::isFeatureActive(); 544 if (isset($context->employee)) { 545 $frontend = false; 546 } else { 547 // Get groups list 548 if ($useGroups) { 549 if (isset($context->customer) && $context->customer->isLogged()) { 550 $groups = $context->customer->getGroups(); 551 } elseif (isset($context->customer) && $context->customer->isLogged(true)) { 552 $groups = [(int) Configuration::get('PS_GUEST_GROUP')]; 553 } else { 554 $groups = [(int) Configuration::get('PS_UNIDENTIFIED_GROUP')]; 555 } 556 } 557 } 558 559 // SQL Request 560 $sql = new DbQuery(); 561 $sql->select('h.`name` as hook, m.`id_module`, h.`id_hook`, m.`name` as module, h.`live_edit`'); 562 $sql->from('module', 'm'); 563 if ($hookName != 'displayBackOfficeHeader') { 564 $sql->join(Shop::addSqlAssociation('module', 'm', true, 'module_shop.enable_device & '.(int) Context::getContext()->getDevice())); 565 $sql->innerJoin('module_shop', 'ms', 'ms.`id_module` = m.`id_module`'); 566 } 567 $sql->innerJoin('hook_module', 'hm', 'hm.`id_module` = m.`id_module`'); 568 $sql->innerJoin('hook', 'h', 'hm.`id_hook` = h.`id_hook`'); 569 if ($hookName != 'displayPayment' && $hookName != 'displayPaymentEU') { 570 $sql->where('h.`name` != "displayPayment" AND h.`name` != "displayPaymentEU"'); 571 } // For payment modules, we check that they are available in the contextual country 572 elseif ($frontend) { 573 if (Validate::isLoadedObject($context->country)) { 574 $sql->where('((h.`name` = "displayPayment" OR h.`name` = "displayPaymentEU") AND (SELECT `id_country` FROM `'._DB_PREFIX_.'module_country` mc WHERE mc.`id_module` = m.`id_module` AND `id_country` = '.(int) $context->country->id.' AND `id_shop` = '.(int) $context->shop->id.' LIMIT 1) = '.(int) $context->country->id.')'); 575 } 576 if (Validate::isLoadedObject($context->currency)) { 577 $sql->where('((h.`name` = "displayPayment" OR h.`name` = "displayPaymentEU") AND (SELECT `id_currency` FROM `'._DB_PREFIX_.'module_currency` mcr WHERE mcr.`id_module` = m.`id_module` AND `id_currency` IN ('.(int) $context->currency->id.', -1, -2) LIMIT 1) IN ('.(int) $context->currency->id.', -1, -2))'); 578 } 579 if (Validate::isLoadedObject($context->cart)) { 580 $carrier = new Carrier($context->cart->id_carrier); 581 if (Validate::isLoadedObject($carrier)) { 582 $sql->where('((h.`name` = "displayPayment" OR h.`name` = "displayPaymentEU") AND (SELECT `id_reference` FROM `'._DB_PREFIX_.'module_carrier` mcar WHERE mcar.`id_module` = m.`id_module` AND `id_reference` = '.(int) $carrier->id_reference.' AND `id_shop` = '.(int) $context->shop->id.' LIMIT 1) = '.(int) $carrier->id_reference.')'); 583 } 584 } 585 } 586 if (Validate::isLoadedObject($context->shop)) { 587 $sql->where('hm.`id_shop` = '.(int) $context->shop->id); 588 } 589 590 if ($frontend) { 591 if ($useGroups) { 592 $sql->leftJoin('module_group', 'mg', 'mg.`id_module` = m.`id_module`'); 593 if (Validate::isLoadedObject($context->shop)) { 594 $sql->where('mg.`id_shop` = '.((int) $context->shop->id).(count($groups) ? ' AND mg.`id_group` IN ('.implode(', ', $groups).')' : '')); 595 } elseif (count($groups)) { 596 $sql->where('mg.`id_group` IN ('.implode(', ', $groups).')'); 597 } 598 } 599 } 600 601 $sql->groupBy('hm.id_hook, hm.id_module'); 602 $sql->orderBy('hm.`position`'); 603 604 $list = []; 605 if ($result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql)) { 606 foreach ($result as $row) { 607 $row['hook'] = strtolower($row['hook']); 608 if (!isset($list[$row['hook']])) { 609 $list[$row['hook']] = []; 610 } 611 612 $list[$row['hook']][] = [ 613 'id_hook' => $row['id_hook'], 614 'module' => $row['module'], 615 'id_module' => $row['id_module'], 616 'live_edit' => $row['live_edit'], 617 ]; 618 } 619 } 620 if ($hookName != 'displayPayment' && $hookName != 'displayPaymentEU' && $hookName != 'displayBackOfficeHeader') { 621 Cache::store($cacheId, $list); 622 // @todo remove this in 1.6, we keep it in 1.5 for backward compatibility 623 static::$_hook_modules_cache_exec = $list; 624 } 625 } else { 626 $list = Cache::retrieve($cacheId); 627 } 628 629 // If hook_name is given, just get list of modules for this hook 630 if ($hookName) { 631 $retroHookName = strtolower(Hook::getRetroHookName($hookName)); 632 $hookName = strtolower($hookName); 633 634 $return = []; 635 $insertedModules = []; 636 if (isset($list[$hookName])) { 637 $return = $list[$hookName]; 638 } 639 foreach ($return as $module) { 640 $insertedModules[] = $module['id_module']; 641 } 642 if (isset($list[$retroHookName])) { 643 foreach ($list[$retroHookName] as $retroModuleCall) { 644 if (!in_array($retroModuleCall['id_module'], $insertedModules)) { 645 $return[] = $retroModuleCall; 646 } 647 } 648 } 649 650 return (count($return) > 0 ? $return : false); 651 } else { 652 return $list; 653 } 654 } 655 656 /** 657 * Return backward compatibility hook name 658 * 659 * 660 * @param string $hookName Hook name 661 * 662 * @return int Hook ID 663 * 664 * @since 1.0.0 665 * @version 1.0.0 Initial version 666 */ 667 public static function getRetroHookName($hookName) 668 { 669 $aliasList = Hook::getHookAliasList(); 670 if (isset($aliasList[strtolower($hookName)])) { 671 return $aliasList[strtolower($hookName)]; 672 } 673 674 $retroHookName = array_search($hookName, $aliasList); 675 if ($retroHookName === false) { 676 return ''; 677 } 678 679 return $retroHookName; 680 } 681 682 /** 683 * Get list of hook alias 684 * 685 * 686 * @return array 687 * 688 * @since 1.0.0 689 * @version 1.0.0 Initial version 690 */ 691 public static function getHookAliasList() 692 { 693 $cacheId = 'hook_alias'; 694 if (!Cache::isStored($cacheId)) { 695 $hookAliasList = Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'hook_alias`'); 696 $hookAlias = []; 697 if ($hookAliasList) { 698 foreach ($hookAliasList as $ha) { 699 $hookAlias[strtolower($ha['alias'])] = $ha['name']; 700 } 701 } 702 Cache::store($cacheId, $hookAlias); 703 704 return $hookAlias; 705 } 706 707 return Cache::retrieve($cacheId); 708 } 709 710 /** 711 * Return hook ID from name 712 * 713 * @param string $hookName Hook name 714 * 715 * @return int Hook ID 716 * 717 * @since 1.0.0 718 * @version 1.0.0 Initial version 719 */ 720 public static function getIdByName($hookName) 721 { 722 $hookName = strtolower($hookName); 723 if (!Validate::isHookName($hookName)) { 724 return false; 725 } 726 727 $cacheId = 'hook_idsbyname'; 728 if (!Cache::isStored($cacheId)) { 729 // Get all hook ID by name and alias 730 $hookIds = []; 731 $db = Db::getInstance(); 732 $result = $db->ExecuteS( 733 ' 734 SELECT `id_hook`, `name` 735 FROM `'._DB_PREFIX_.'hook` 736 UNION 737 SELECT `id_hook`, ha.`alias` AS name 738 FROM `'._DB_PREFIX_.'hook_alias` ha 739 INNER JOIN `'._DB_PREFIX_.'hook` h ON ha.name = h.name', false 740 ); 741 while ($row = $db->nextRow($result)) { 742 $hookIds[strtolower($row['name'])] = $row['id_hook']; 743 } 744 Cache::store($cacheId, $hookIds); 745 } else { 746 $hookIds = Cache::retrieve($cacheId); 747 } 748 749 return (isset($hookIds[$hookName]) ? $hookIds[$hookName] : false); 750 } 751 752 /** 753 * @param $module 754 * @param $method 755 * @param $params 756 * 757 * @return mixed 758 * 759 * @since 1.0.0 760 * @version 1.0.0 Initial version 761 */ 762 public static function coreCallHook($module, $method, $params) 763 { 764 // Define if we will log modules performances for this session 765 if (Module::$_log_modules_perfs === null) { 766 $modulo = _PS_DEBUG_PROFILING_ ? 1 : Configuration::get('PS_log_modules_perfs_MODULO'); 767 Module::$_log_modules_perfs = ($modulo && mt_rand(0, $modulo - 1) == 0); 768 if (Module::$_log_modules_perfs) { 769 Module::$_log_modules_perfs_session = mt_rand(); 770 } 771 } 772 773 // Immediately return the result if we do not log performances 774 if (!Module::$_log_modules_perfs) { 775 return $module->{$method}($params); 776 } 777 778 // Store time and memory before and after hook call and save the result in the database 779 $timeStart = microtime(true); 780 $memoryStart = memory_get_usage(true); 781 782 // Call hook 783 $r = $module->{$method}($params); 784 785 $timeEnd = microtime(true); 786 $memoryEnd = memory_get_usage(true); 787 788 Db::getInstance()->execute( 789 ' 790 INSERT INTO '._DB_PREFIX_.'modules_perfs (session, module, method, time_start, time_end, memory_start, memory_end) 791 VALUES ('.(int) Module::$_log_modules_perfs_session.', "'.pSQL($module->name).'", "'.pSQL($method).'", "'.pSQL($timeStart).'", "'.pSQL($timeEnd).'", '.(int) $memoryStart.', '.(int) $memoryEnd.')' 792 ); 793 794 return $r; 795 } 796 797 /** 798 * @param $display 799 * @param $moduleInstance 800 * @param $idHook 801 * 802 * @return string 803 * 804 * @since 1.0.0 805 * @version 1.0.0 Initial version 806 */ 807 public static function wrapLiveEdit($display, $moduleInstance, $idHook) 808 { 809 return '<script type="text/javascript"> modules_list.push(\''.Tools::safeOutput($moduleInstance->name).'\');</script> 810 <div id="hook_'.(int) $idHook.'_module_'.(int) $moduleInstance->id.'_moduleName_'.str_replace('_', '-', Tools::safeOutput($moduleInstance->name)).'" 811 class="dndModule" style="border: 1px dotted red;'.(!strlen($display) ? 'height:50px;' : '').'"> 812 <span style="font-family: Georgia;font-size:13px;font-style:italic;"> 813 <img style="padding-right:5px;" src="'._MODULE_DIR_.Tools::safeOutput($moduleInstance->name).'/logo.gif">' 814 .Tools::safeOutput($moduleInstance->displayName).'<span style="float:right"> 815 <a href="#" id="'.(int) $idHook.'_'.(int) $moduleInstance->id.'" class="moveModule"> 816 <img src="'._PS_ADMIN_IMG_.'arrow_out.png"></a> 817 <a href="#" id="'.(int) $idHook.'_'.(int) $moduleInstance->id.'" class="unregisterHook"> 818 <img src="'._PS_ADMIN_IMG_.'delete.gif"></a></span> 819 </span>'.$display.'</div>'; 820 } 821 822 /** 823 * @deprecated 1.0.0 824 * 825 * @param int $newOrderStatusId 826 * @param int $idOrder 827 * 828 * @return string 829 */ 830 public static function postUpdateOrderStatus($newOrderStatusId, $idOrder) 831 { 832 Tools::displayAsDeprecated(); 833 $order = new Order((int) $idOrder); 834 $newOs = new OrderState((int) $newOrderStatusId, $order->id_lang); 835 $return = Hook::exec('postUpdateOrderStatus', ['newOrderStatus' => $newOs, 'id_order' => (int) ($order->id)]); 836 837 return $return; 838 } 839 840 /** 841 * @deprecated 1.0.0 842 * 843 * @param int $idOrder 844 * 845 * @return bool|string 846 */ 847 public static function orderConfirmation($idOrder) 848 { 849 Tools::displayAsDeprecated(); 850 if (Validate::isUnsignedId($idOrder)) { 851 $params = []; 852 $order = new Order((int) $idOrder); 853 $currency = new Currency((int) $order->id_currency); 854 855 if (Validate::isLoadedObject($order)) { 856 $cart = new Cart((int) $order->id_cart); 857 $params['total_to_pay'] = $cart->getOrderTotal(); 858 $params['currency'] = $currency->sign; 859 $params['objOrder'] = $order; 860 $params['currencyObj'] = $currency; 861 862 return Hook::exec('orderConfirmation', $params); 863 } 864 } 865 866 return false; 867 } 868 869 /** 870 * @deprecated 1.0.0 871 * 872 * @param $idOrder 873 * @param $id_module 874 * 875 * @return bool|string 876 */ 877 public static function paymentReturn($idOrder, $id_module) 878 { 879 Tools::displayAsDeprecated(); 880 if (Validate::isUnsignedId($idOrder) && Validate::isUnsignedId($id_module)) { 881 $params = []; 882 $order = new Order((int) ($idOrder)); 883 $currency = new Currency((int) ($order->id_currency)); 884 885 if (Validate::isLoadedObject($order)) { 886 $cart = new Cart((int) $order->id_cart); 887 $params['total_to_pay'] = $cart->getOrderTotal(); 888 $params['currency'] = $currency->sign; 889 $params['objOrder'] = $order; 890 $params['currencyObj'] = $currency; 891 892 return Hook::exec('paymentReturn', $params, (int) ($id_module)); 893 } 894 } 895 896 return false; 897 } 898 899 /** 900 * @deprecated 1.0.0 901 * 902 * @param $pdf 903 * @param $id_order 904 * 905 * @return bool|string 906 */ 907 public static function PDFInvoice($pdf, $id_order) 908 { 909 Tools::displayAsDeprecated(); 910 if (!is_object($pdf) || !Validate::isUnsignedId($id_order)) { 911 return false; 912 } 913 914 return Hook::exec('PDFInvoice', ['pdf' => $pdf, 'id_order' => $id_order]); 915 } 916 917 /** 918 * @deprecated 1.0.0 919 * 920 * @param $module 921 * 922 * @return string 923 */ 924 public static function backBeforePayment($module) 925 { 926 Tools::displayAsDeprecated(); 927 if ($module) { 928 return Hook::exec('backBeforePayment', ['module' => strval($module)]); 929 } 930 } 931 932 /** 933 * @deprecated 1.0.0 934 * 935 * @param $idCarrier 936 * @param $carrier 937 * 938 * @return bool|string 939 */ 940 public static function updateCarrier($idCarrier, $carrier) 941 { 942 Tools::displayAsDeprecated(); 943 if (!Validate::isUnsignedId($idCarrier) || !is_object($carrier)) { 944 return false; 945 } 946 947 return Hook::exec('updateCarrier', ['id_carrier' => $idCarrier, 'carrier' => $carrier]); 948 } 949 950 /** 951 * Preload hook modules cache 952 * 953 * @deprecated 1.0.0 use Hook::getHookModuleList() instead 954 * 955 * @return bool preload_needed 956 */ 957 public static function preloadHookModulesCache() 958 { 959 Tools::displayAsDeprecated('Use Hook::getHookModuleList() instead'); 960 961 if (!is_null(static::$_hook_modules_cache)) { 962 return false; 963 } 964 965 static::$_hook_modules_cache = Hook::getHookModuleList(); 966 967 return true; 968 } 969 970 /** 971 * Return hook ID from name 972 * 973 * @param string $hookName Hook name 974 * 975 * @return int Hook ID 976 * 977 * @deprecated 1.0.0 use Hook::getIdByName() instead 978 */ 979 public static function get($hookName) 980 { 981 Tools::displayAsDeprecated('Use Hook::getIdByName() instead'); 982 if (!Validate::isHookName($hookName)) { 983 die(Tools::displayError()); 984 } 985 986 $result = Db::getInstance()->getRow( 987 ' 988 SELECT `id_hook`, `name` 989 FROM `'._DB_PREFIX_.'hook` 990 WHERE `name` = \''.pSQL($hookName).'\'' 991 ); 992 993 return ($result ? $result['id_hook'] : false); 994 } 995 996 /** 997 * Called when quantity of a product is updated. 998 * 999 * @deprecated 1.0.0 1000 * 1001 * @param Cart $cart 1002 * @param Order $order 1003 * @param Customer $customer 1004 * @param Currency $currency 1005 * @param $orderStatus 1006 * 1007 * @throws \Exception 1008 * 1009 * @return string 1010 */ 1011 public static function newOrder($cart, $order, $customer, $currency, $orderStatus) 1012 { 1013 Tools::displayAsDeprecated(); 1014 1015 return Hook::exec( 1016 'newOrder', [ 1017 'cart' => $cart, 1018 'order' => $order, 1019 'customer' => $customer, 1020 'currency' => $currency, 1021 'orderStatus' => $orderStatus, 1022 ] 1023 ); 1024 } 1025 1026 /** 1027 * @deprecated 1.0.0 1028 * 1029 * @param $product 1030 * @param null $order 1031 * 1032 * @return string 1033 */ 1034 public static function updateQuantity($product, $order = null) 1035 { 1036 Tools::displayAsDeprecated(); 1037 1038 return Hook::exec('updateQuantity', ['product' => $product, 'order' => $order]); 1039 } 1040 1041 /** 1042 * @deprecated 1.0.0 1043 * 1044 * @param $product 1045 * @param $category 1046 * 1047 * @return string 1048 */ 1049 public static function productFooter($product, $category) 1050 { 1051 Tools::displayAsDeprecated(); 1052 1053 return Hook::exec('productFooter', ['product' => $product, 'category' => $category]); 1054 } 1055 1056 /** 1057 * @deprecated 1.0.0 1058 * 1059 * @param $product 1060 * 1061 * @return string 1062 */ 1063 public static function productOutOfStock($product) 1064 { 1065 Tools::displayAsDeprecated(); 1066 1067 return Hook::exec('productOutOfStock', ['product' => $product]); 1068 } 1069 1070 /** 1071 * @deprecated 1.0.0 1072 * 1073 * @param $product 1074 * 1075 * @return string 1076 */ 1077 public static function addProduct($product) 1078 { 1079 Tools::displayAsDeprecated(); 1080 1081 return Hook::exec('addProduct', ['product' => $product]); 1082 } 1083 1084 /** 1085 * @deprecated 1.0.0 1086 * 1087 * @param $product 1088 * 1089 * @return string 1090 */ 1091 public static function updateProduct($product) 1092 { 1093 Tools::displayAsDeprecated(); 1094 1095 return Hook::exec('updateProduct', ['product' => $product]); 1096 } 1097 1098 /** 1099 * @deprecated 1.0.0 1100 * 1101 * @param $product 1102 * 1103 * @return string 1104 */ 1105 public static function deleteProduct($product) 1106 { 1107 Tools::displayAsDeprecated(); 1108 1109 return Hook::exec('deleteProduct', ['product' => $product]); 1110 } 1111 1112 /** 1113 * @deprecated 1.0.0 1114 */ 1115 public static function updateProductAttribute($idProductAttribute) 1116 { 1117 Tools::displayAsDeprecated(); 1118 1119 return Hook::exec('updateProductAttribute', ['id_product_attribute' => $idProductAttribute]); 1120 } 1121 1122 /** 1123 * @param bool $autodate 1124 * @param bool $nullValues 1125 * 1126 * @return bool 1127 * 1128 * @since 1.0.0 1129 * @version 1.0.0 Initial version 1130 */ 1131 public function add($autodate = true, $nullValues = false) 1132 { 1133 Cache::clean('hook_idsbyname'); 1134 1135 return parent::add($autodate, $nullValues); 1136 } 1137} 1138