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 */ 26 27namespace PrestaShop\PrestaShop\Core\Module; 28 29use Db; 30use Exception; 31use PrestaShop\PrestaShop\Adapter\Hook\HookInformationProvider; 32use Shop; 33 34class HookRepository 35{ 36 private $hookInfo; 37 private $shop; 38 private $db; 39 private $db_prefix; 40 41 public function __construct( 42 HookInformationProvider $hookInfo, 43 Shop $shop, 44 Db $db 45 ) { 46 $this->hookInfo = $hookInfo; 47 $this->shop = $shop; 48 $this->db = $db; 49 $this->db_prefix = $db->getPrefix(); 50 } 51 52 public function getIdByName($hook_name) 53 { 54 $escaped_hook_name = $this->db->escape($hook_name); 55 56 $id_hook = $this->db->getValue( 57 "SELECT id_hook FROM {$this->db_prefix}hook WHERE name = '$escaped_hook_name'" 58 ); 59 60 return (int) $id_hook; 61 } 62 63 public function createHook($hook_name, $title = '', $description = '', $position = 1) 64 { 65 $this->db->insert('hook', [ 66 'name' => $this->db->escape($hook_name), 67 'title' => $this->db->escape($title), 68 'description' => $this->db->escape($description), 69 'position' => $this->db->escape($position), 70 ], false, true, Db::REPLACE); 71 72 return $this->getIdByName($hook_name); 73 } 74 75 private function getIdModule($module_name) 76 { 77 $escaped_module_name = $this->db->escape($module_name); 78 79 $id_module = $this->db->getValue( 80 "SELECT id_module FROM {$this->db_prefix}module WHERE name = '$escaped_module_name'" 81 ); 82 83 return (int) $id_module; 84 } 85 86 public function unHookModulesFromHook($hook_name) 87 { 88 $id_hook = $this->getIdByName($hook_name); 89 $id_shop = (int) $this->shop->id; 90 91 $this->db->execute("DELETE FROM {$this->db_prefix}hook_module 92 WHERE id_hook = $id_hook AND id_shop = $id_shop 93 "); 94 95 $this->db->execute("DELETE FROM {$this->db_prefix}hook_module_exceptions 96 WHERE id_hook = $id_hook AND id_shop = $id_shop 97 "); 98 99 return $this; 100 } 101 102 /** 103 * Saves hook settings for a list of hooks. 104 * The $hooks array should have this format: 105 * [ 106 * "hookName" => [ 107 * "module1", 108 * "module2", 109 * "module3" => [ 110 * "except_pages" => [ 111 * "page1", 112 * "page2", 113 * "page3" 114 * ] 115 * ] 116 * ] 117 * ] 118 * Only hooks present as keys in the $hooks array are affected and all changes 119 * are only done for the shop this Repository belongs to. 120 */ 121 public function persistHooksConfiguration(array $hooks) 122 { 123 foreach ($hooks as $hook_name => $module_names) { 124 $id_hook = $this->getIdByName($hook_name); 125 if (!$id_hook) { 126 $id_hook = $this->createHook($hook_name); 127 } 128 if (!$id_hook) { 129 throw new Exception(sprintf('Could not create hook `%1$s`.', $hook_name)); 130 } 131 132 $this->unHookModulesFromHook($hook_name); 133 134 $position = 0; 135 foreach ($module_names as $key => $module) { 136 if (is_array($module)) { 137 $module_name = key($module); 138 $extra_data = current($module); 139 } else { 140 $module_name = $module; 141 $extra_data = []; 142 } 143 144 ++$position; 145 $id_module = $this->getIdModule($module_name); 146 if (!$id_module) { 147 continue; 148 } 149 150 $row = [ 151 'id_module' => $id_module, 152 'id_shop' => (int) $this->shop->id, 153 'id_hook' => $id_hook, 154 'position' => $position, 155 ]; 156 157 $this->db->insert('hook_module', $row); 158 159 if (!empty($extra_data['except_pages'])) { 160 $this->setModuleHookExceptions( 161 $id_module, 162 $id_hook, 163 $extra_data['except_pages'] 164 ); 165 } 166 } 167 } 168 169 return $this; 170 } 171 172 private function setModuleHookExceptions($id_module, $id_hook, array $pages) 173 { 174 $id_shop = (int) $this->shop->id; 175 $id_module = (int) $id_module; 176 $id_hook = (int) $id_hook; 177 178 $this->db->execute("DELETE FROM {$this->db_prefix}hook_module_exceptions 179 WHERE id_shop = $id_shop 180 AND id_module = $id_module 181 AND id_hook = $id_hook 182 "); 183 184 foreach ($pages as $page) { 185 $this->db->insert('hook_module_exceptions', [ 186 'id_shop' => $id_shop, 187 'id_module' => $id_module, 188 'id_hook' => $id_hook, 189 'file_name' => $page, 190 ]); 191 } 192 193 return $this; 194 } 195 196 private function getModuleHookExceptions($id_module, $id_hook) 197 { 198 $id_shop = (int) $this->shop->id; 199 $id_module = (int) $id_module; 200 $id_hook = (int) $id_hook; 201 202 $rows = $this->db->executeS("SELECT file_name 203 FROM {$this->db_prefix}hook_module_exceptions 204 WHERE id_shop = $id_shop 205 AND id_module = $id_module 206 AND id_hook = $id_hook 207 ORDER BY file_name ASC 208 "); 209 210 return array_map(function ($row) { 211 return $row['file_name']; 212 }, $rows); 213 } 214 215 public function getHooksWithModules() 216 { 217 $id_shop = (int) $this->shop->id; 218 219 $sql = "SELECT h.name as hook_name, h.id_hook, m.name as module_name, m.id_module 220 FROM {$this->db_prefix}hook_module hm 221 INNER JOIN {$this->db_prefix}hook h 222 ON h.id_hook = hm.id_hook 223 INNER JOIN {$this->db_prefix}module m 224 ON m.id_module = hm.id_module 225 WHERE hm.id_shop = $id_shop 226 ORDER BY h.name ASC, hm.position ASC 227 "; 228 229 $rows = $this->db->executeS($sql); 230 231 $hooks = []; 232 233 foreach ($rows as $row) { 234 $exceptions = $this->getModuleHookExceptions( 235 $row['id_module'], 236 $row['id_hook'] 237 ); 238 239 if (empty($exceptions)) { 240 $hooks[$row['hook_name']][] = $row['module_name']; 241 } else { 242 $hooks[$row['hook_name']][$row['module_name']] = [ 243 'except_pages' => $exceptions, 244 ]; 245 } 246 } 247 248 return $hooks; 249 } 250 251 public function getDisplayHooksWithModules() 252 { 253 $hooks = []; 254 foreach ($this->getHooksWithModules() as $hook_name => $modules) { 255 if ($this->hookInfo->isDisplayHookName($hook_name)) { 256 $hooks[$hook_name] = $modules; 257 } 258 } 259 260 return $hooks; 261 } 262} 263