xref: /webtrees/app/Module/AbstractModule.php (revision ad2f0e13109a624a158c7532c312bc08f1d45af8)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2015 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	/** @var string A user-friendly, localized name for this module */
27	private $title;
28
29	/** @var string The directory where the module is installed */
30	private $directory;
31
32	/** @var string[] A cached copy of the module settings */
33	private $settings;
34
35	/**
36	 * Create a new module.
37	 *
38	 * @param string $directory Where is this module installed
39	 */
40	public function __construct($directory) {
41		$this->directory = $directory;
42		$this->title     = $this->getTitle();
43	}
44
45	/**
46	 * Get a block setting.
47	 *
48	 * @param int         $block_id
49	 * @param string      $setting_name
50	 * @param string|null $default_value
51	 *
52	 * @return null|string
53	 */
54	public function getBlockSetting($block_id, $setting_name, $default_value = null) {
55		$setting_value = Database::prepare(
56			"SELECT SQL_CACHE setting_value FROM `##block_setting` WHERE block_id = :block_id AND setting_name = :setting_name"
57		)->execute(array(
58			'block_id'     => $block_id,
59			'setting_name' => $setting_name,
60		))->fetchOne();
61
62		return $setting_value === null ? $default_value : $setting_value;
63	}
64
65	/**
66	 * Set a block setting.
67	 *
68	 * @param int         $block_id
69	 * @param string      $setting_name
70	 * @param string|null $setting_value
71	 *
72	 * @return $this
73	 */
74	public function setBlockSetting($block_id, $setting_name, $setting_value) {
75		if ($setting_value === null) {
76			Database::prepare(
77				"DELETE FROM `##block_setting` WHERE block_id = :block_id AND setting_name = :setting_name"
78			)->execute(array(
79					'block_id'     => $block_id,
80					'setting_name' => $setting_name,
81			));
82		} else {
83			Database::prepare(
84				"REPLACE INTO `##block_setting` (block_id, setting_name, setting_value) VALUES (:block_id, :setting_name, :setting_value)"
85			)->execute(array(
86				'block_id'      => $block_id,
87				'setting_name'  => $setting_name,
88				'setting_value' => $setting_value,
89			));
90		}
91
92		return $this;
93	}
94
95	/**
96	 * How should this module be labelled on tabs, menus, etc.?
97	 *
98	 * @return string
99	 */
100	abstract public function getTitle();
101
102	/**
103	 * A sentence describing what this module does.
104	 *
105	 * @return string
106	 */
107	abstract public function getDescription();
108
109	/**
110	 * What is the default access level for this module?
111	 *
112	 * Some modules are aimed at admins or managers, and are not generally shown to users.
113	 *
114	 * @return int
115	 */
116	public function defaultAccessLevel() {
117		// Returns one of: Auth::PRIV_HIDE, Auth::PRIV_PRIVATE, Auth::PRIV_USER, WT_PRIV_ADMIN
118		return Auth::PRIV_PRIVATE;
119	}
120
121	/**
122	 * Provide a unique internal name for this module
123	 *
124	 * @return string
125	 */
126	public function getName() {
127		return basename($this->directory);
128	}
129
130	/**
131	 * Load all the settings for the module into a cache.
132	 *
133	 * Since modules may have many settings, and will probably want to use
134	 * lots of them, load them all at once and cache them.
135	 */
136	private function loadAllSettings() {
137		if ($this->settings === null) {
138			$this->settings = Database::prepare(
139				"SELECT SQL_CACHE setting_name, setting_value FROM `##module_setting` WHERE module_name = ?"
140			)->execute(array($this->getName()))->fetchAssoc();
141		}
142	}
143
144	/**
145	 * Get a module setting. Return a default if the setting is not set.
146	 *
147	 * @param string $setting_name
148	 * @param string $default
149	 *
150	 * @return string|null
151	 */
152	public function getSetting($setting_name, $default = null) {
153		$this->loadAllSettings();
154
155		if (array_key_exists($setting_name, $this->settings)) {
156			return $this->settings[$setting_name];
157		} else {
158			return $default;
159		}
160	}
161
162	/**
163	 * Set a module setting.
164	 *
165	 * Since module settings are NOT NULL, setting a value to NULL will cause
166	 * it to be deleted.
167	 *
168	 * @param string $setting_name
169	 * @param string $setting_value
170	 */
171	public function setSetting($setting_name, $setting_value) {
172		$this->loadAllSettings();
173
174		if ($setting_value === null) {
175			Database::prepare(
176				"DELETE FROM `##module_setting` WHERE module_name = ? AND setting_name = ?"
177			)->execute(array($this->getName(), $setting_name));
178			unset($this->settings[$setting_name]);
179		} elseif (!array_key_exists($setting_name, $this->settings)) {
180			Database::prepare(
181				"INSERT INTO `##module_setting` (module_name, setting_name, setting_value) VALUES (?, ?, ?)"
182			)->execute(array($this->getName(), $setting_name, $setting_value));
183			$this->settings[$setting_name] = $setting_value;
184		} elseif ($setting_value != $this->settings[$setting_name]) {
185			Database::prepare(
186				"UPDATE `##module_setting` SET setting_value = ? WHERE module_name = ? AND setting_name = ?"
187			)->execute(array($setting_value, $this->getName(), $setting_name));
188			$this->settings[$setting_name] = $setting_value;
189		} else {
190			// Setting already exists, but with the same value - do nothing.
191		}
192	}
193
194	/**
195	 * This is a general purpose hook, allowing modules to respond to routes
196	 * of the form module.php?mod=FOO&mod_action=BAR
197	 *
198	 * @param string $mod_action
199	 */
200	public function modAction($mod_action) {
201	}
202
203	/**
204	 * Get a the current access level for a module
205	 *
206	 * @param Tree   $tree
207	 * @param string $component tab, block, menu, etc
208	 *
209	 * @return int
210	 */
211	public function getAccessLevel(Tree $tree, $component) {
212		$access_level = Database::prepare(
213			"SELECT access_level FROM `##module_privacy` WHERE gedcom_id = :gedcom_id AND module_name = :module_name AND component = :component"
214		)->execute(array(
215			'gedcom_id'   => $tree->getTreeId(),
216			'module_name' => $this->getName(),
217			'component'   => $component,
218		))->fetchOne();
219
220		if ($access_level === null) {
221			return $this->defaultAccessLevel();
222		} else {
223			return (int) $access_level;
224		}
225	}
226}
227