1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16namespace Fisharebest\Webtrees\Module; 17 18use Fisharebest\Webtrees\Auth; 19use Fisharebest\Webtrees\Database; 20use Fisharebest\Webtrees\Tree; 21 22/** 23 * Class AbstractModule - common functions for blocks 24 */ 25abstract class AbstractModule 26{ 27 /** @var string The directory where the module is installed */ 28 private $directory; 29 30 /** @var string[] A cached copy of the module settings */ 31 private $settings; 32 33 /** @var string For custom modules - optional (recommended) version number */ 34 const CUSTOM_VERSION = ''; 35 36 /** @var string For custom modules - link for support, upgrades, etc. */ 37 const CUSTOM_WEBSITE = ''; 38 39 /** 40 * Create a new module. 41 * 42 * @param string $directory Where is this module installed 43 */ 44 public function __construct($directory) 45 { 46 $this->directory = $directory; 47 } 48 49 /** 50 * Get a block setting. 51 * 52 * @param int $block_id 53 * @param string $setting_name 54 * @param string|null $default_value 55 * 56 * @return null|string 57 */ 58 public function getBlockSetting($block_id, $setting_name, $default_value = null) 59 { 60 $setting_value = Database::prepare( 61 "SELECT setting_value FROM `##block_setting` WHERE block_id = :block_id AND setting_name = :setting_name" 62 )->execute(array( 63 'block_id' => $block_id, 64 'setting_name' => $setting_name, 65 ))->fetchOne(); 66 67 return $setting_value === null ? $default_value : $setting_value; 68 } 69 70 /** 71 * Set a block setting. 72 * 73 * @param int $block_id 74 * @param string $setting_name 75 * @param string|null $setting_value 76 * 77 * @return $this 78 */ 79 public function setBlockSetting($block_id, $setting_name, $setting_value) 80 { 81 if ($setting_value === null) { 82 Database::prepare( 83 "DELETE FROM `##block_setting` WHERE block_id = :block_id AND setting_name = :setting_name" 84 )->execute(array( 85 'block_id' => $block_id, 86 'setting_name' => $setting_name, 87 )); 88 } else { 89 Database::prepare( 90 "REPLACE INTO `##block_setting` (block_id, setting_name, setting_value) VALUES (:block_id, :setting_name, :setting_value)" 91 )->execute(array( 92 'block_id' => $block_id, 93 'setting_name' => $setting_name, 94 'setting_value' => $setting_value, 95 )); 96 } 97 98 return $this; 99 } 100 101 /** 102 * How should this module be labelled on tabs, menus, etc.? 103 * 104 * @return string 105 */ 106 abstract public function getTitle(); 107 108 /** 109 * A sentence describing what this module does. 110 * 111 * @return string 112 */ 113 abstract public function getDescription(); 114 115 /** 116 * What is the default access level for this module? 117 * 118 * Some modules are aimed at admins or managers, and are not generally shown to users. 119 * 120 * @return int 121 */ 122 public function defaultAccessLevel() 123 { 124 // Returns one of: Auth::PRIV_HIDE, Auth::PRIV_PRIVATE, Auth::PRIV_USER, WT_PRIV_ADMIN 125 return Auth::PRIV_PRIVATE; 126 } 127 128 /** 129 * Provide a unique internal name for this module 130 * 131 * @return string 132 */ 133 public function getName() 134 { 135 return basename($this->directory); 136 } 137 138 /** 139 * Load all the settings for the module into a cache. 140 * 141 * Since modules may have many settings, and will probably want to use 142 * lots of them, load them all at once and cache them. 143 */ 144 private function loadAllSettings() 145 { 146 if ($this->settings === null) { 147 $this->settings = Database::prepare( 148 "SELECT setting_name, setting_value FROM `##module_setting` WHERE module_name = ?" 149 )->execute(array($this->getName()))->fetchAssoc(); 150 } 151 } 152 153 /** 154 * Get a module setting. Return a default if the setting is not set. 155 * 156 * @param string $setting_name 157 * @param string $default 158 * 159 * @return string|null 160 */ 161 public function getSetting($setting_name, $default = null) 162 { 163 $this->loadAllSettings(); 164 165 if (array_key_exists($setting_name, $this->settings)) { 166 return $this->settings[$setting_name]; 167 } else { 168 return $default; 169 } 170 } 171 172 /** 173 * Set a module setting. 174 * 175 * Since module settings are NOT NULL, setting a value to NULL will cause 176 * it to be deleted. 177 * 178 * @param string $setting_name 179 * @param string $setting_value 180 */ 181 public function setSetting($setting_name, $setting_value) 182 { 183 $this->loadAllSettings(); 184 185 if ($setting_value === null) { 186 Database::prepare( 187 "DELETE FROM `##module_setting` WHERE module_name = ? AND setting_name = ?" 188 )->execute(array($this->getName(), $setting_name)); 189 unset($this->settings[$setting_name]); 190 } elseif (!array_key_exists($setting_name, $this->settings)) { 191 Database::prepare( 192 "INSERT INTO `##module_setting` (module_name, setting_name, setting_value) VALUES (?, ?, ?)" 193 )->execute(array($this->getName(), $setting_name, $setting_value)); 194 $this->settings[$setting_name] = $setting_value; 195 } elseif ($setting_value != $this->settings[$setting_name]) { 196 Database::prepare( 197 "UPDATE `##module_setting` SET setting_value = ? WHERE module_name = ? AND setting_name = ?" 198 )->execute(array($setting_value, $this->getName(), $setting_name)); 199 $this->settings[$setting_name] = $setting_value; 200 } else { 201 // Setting already exists, but with the same value - do nothing. 202 } 203 } 204 205 /** 206 * This is a general purpose hook, allowing modules to respond to routes 207 * of the form module.php?mod=FOO&mod_action=BAR 208 * 209 * @param string $mod_action 210 */ 211 public function modAction($mod_action) 212 { 213 } 214 215 /** 216 * Get a the current access level for a module 217 * 218 * @param Tree $tree 219 * @param string $component tab, block, menu, etc 220 * 221 * @return int 222 */ 223 public function getAccessLevel(Tree $tree, $component) 224 { 225 $access_level = Database::prepare( 226 "SELECT access_level FROM `##module_privacy` WHERE gedcom_id = :gedcom_id AND module_name = :module_name AND component = :component" 227 )->execute(array( 228 'gedcom_id' => $tree->getTreeId(), 229 'module_name' => $this->getName(), 230 'component' => $component, 231 ))->fetchOne(); 232 233 if ($access_level === null) { 234 return $this->defaultAccessLevel(); 235 } else { 236 return (int) $access_level; 237 } 238 } 239} 240