Cancelled
Pull Request — master (#11549)
by Steve
57:05
created

engine/classes/Elgg/BootService.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Elgg;
4
5
use Elgg\Database\SiteSecret;
6
use Elgg\Di\ServiceProvider;
7
use ElggCache;
8
use Stash\Invalidation;
9
10
/**
11
 * Boots Elgg and manages a cache of data needed during boot
12
 *
13
 * @access private
14
 * @since 2.1
15
 */
16
class BootService {
17
	use Profilable;
18
19
	/**
20
	 * Under load, a short TTL gives nearly all of the benefits of a longer TTL, but it also ensures
21
	 * that, should cache invalidation fail for some reason, it'll be rebuilt quickly anyway.
22
	 *
23
	 * In 2.x we do not cache by default. This will likely change to 10 in 3.0.
24
	 */
25
	const DEFAULT_BOOT_CACHE_TTL = 0;
26
27
	/**
28
	 * Has the cache already been invalidated this request? Avoids thrashing
29
	 *
30
	 * @var bool
31
	 */
32
	private $was_cleared = false;
33
34
	/**
35
	 * @var ElggCache
36
	 */
37
	protected $cache;
38
39
	/**
40
	 * Cache
41
	 *
42
	 * @param ElggCache $cache Cache
43
	 */
44 4365
	public function __construct(ElggCache $cache) {
45 4365
		$this->cache = $cache;
46 4365
	}
47
48
	/**
49
	 * Boots the engine
50
	 *
51
	 * @param ServiceProvider $services Services
52
	 *
53
	 * @return void
54
	 * @throws \ClassException
55
	 * @throws \DatabaseException
56
	 * @throws \InstallationException
57
	 * @throws \InvalidParameterException
58
	 * @throws \SecurityException
59
	 */
60 4734
	public function boot(ServiceProvider $services) {
61 4725
		$db = $services->db;
62 4725
		$config = $services->config;
63
64
		// set cookie values for session and remember me
65 4725
		$config->getCookieConfig();
66
67
		// defaults in case these aren't in config table
68 4725
		if ($config->boot_cache_ttl === null) {
69 5
			$config->boot_cache_ttl = self::DEFAULT_BOOT_CACHE_TTL;
70
		}
71 4725
		if ($config->simplecache_enabled === null) {
72 5
			$config->simplecache_enabled = 0;
73
		}
74 4725
		if ($config->system_cache_enabled === null) {
75 5
			$config->system_cache_enabled = false;
76
		}
77 4725
		if ($config->simplecache_lastupdate === null) {
78 4365
			$config->simplecache_lastupdate = 0;
79
		}
80
81
		// we were using NOTICE temporarily so we can't just check for null
82 4725
		if (!$config->hasInitialValue('debug') && !$config->debug) {
83 5
			$config->debug = '';
84
		}
85
86
		// copy all table values into config
87 4725
		$config->mergeValues($services->configTable->getAll());
88
89
		// needs to be set before [init, system] for links in html head
90 4725
		$config->lastcache = (int) $config->simplecache_lastupdate;
91
92 4725
		if (!$config->elgg_config_set_secret) {
93 4725
			$site_secret = SiteSecret::fromConfig($config);
94 4725
			if (!$site_secret) {
95
				// The 2.3 installer doesn't create a site key (it's created on-demand on the first request)
96
				// so for our Travis upgrade testing we need to check for this and create one on the spot.
97
				if (defined('UPGRADING')) {
98
					$site_secret = SiteSecret::regenerate($services->crypto, $services->configTable);
99
				}
100
			}
101 4725
			if ($site_secret) {
102 4725
				$services->setValue('siteSecret', $site_secret);
103
			} else {
104
				throw new \RuntimeException('The site secret is not set.');
105
			}
106
		}
107
108 4725
		$installed = isset($config->installed);
109
110 4725
		if ($this->timer) {
111
			$this->timer->begin([__CLASS__ . '::getBootData']);
112
		}
113
114
		// early config is done, now get the core boot data
115 4725
		$data = $this->getBootData($config, $db, $installed);
116
117 4725
		$site = $data->getSite();
118 4725
		if (!$site) {
119
			// must be set in config
120
			$site = $config->site;
121
			if (!$site instanceof \ElggSite) {
122
				throw new \RuntimeException('Before installation, config->site must have an unsaved ElggSite.');
123
			}
124
		}
125 4725
		$config->site = $site;
126 4725
		$config->sitename = $site->name;
127 4725
		$config->sitedescription = $site->description;
128
129 4725
		$services->plugins->setBootPlugins($data->getActivePlugins());
130
131 4725
		$settings = $data->getPluginSettings();
132 4725
		foreach ($settings as $guid => $entity_settings) {
133 13
			$services->privateSettingsCache->save($guid, $entity_settings);
134
		}
135
136 4725
		foreach ($data->getPluginMetadata() as $guid => $metadata) {
137 13
			$services->dataCache->metadata->save($guid, $metadata);
138
		}
139
140 4725
		$services->logger->setLevel($config->debug);
0 ignored issues
show
$config->debug of type string is incompatible with the type integer expected by parameter $level of Elgg\Logger::setLevel(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
		$services->logger->setLevel(/** @scrutinizer ignore-type */ $config->debug);
Loading history...
141 4725
		if ($config->debug) {
142 4725
			$services->logger->setDisplay(true);
143
		}
144
145
		// finish boot sequence
146 4725
		_elgg_session_boot($services);
147
148 4725
		if ($config->system_cache_enabled) {
149 13
			$config->system_cache_loaded = false;
150
151 13
			if ($services->views->configureFromCache($services->systemCache)) {
152 11
				$config->system_cache_loaded = true;
153
			}
154
		}
155
156
		// we don't store langs in boot data because it varies by user
157 4725
		$services->translator->loadTranslations();
158
159
		// invalidate on some actions just in case other invalidation triggers miss something
160 4734
		$services->hooks->registerHandler('action', 'all', function ($action) {
161 17
			if (0 === strpos($action, 'admin/' || $action === 'plugins/settings/save')) {
162
				$this->invalidateCache();
163
			}
164 4734
		}, 1);
165 4725
	}
166
167
	/**
168
	 * Invalidate the cache item
169
	 *
170
	 * @return void
171
	 */
172 1053
	public function invalidateCache() {
173 1053
		if (!$this->was_cleared) {
174 389
			$this->cache->clear();
175 389
			$this->was_cleared = true;
176
		}
177 1053
	}
178
179
	/**
180
	 * Get the boot data
181
	 *
182
	 * @param Config   $config    Elgg config object
183
	 * @param Database $db        Elgg database
184
	 * @param bool     $installed Is the site installed?
185
	 *
186
	 * @return BootData
187
	 *
188
	 * @throws \ClassException
189
	 * @throws \DatabaseException
190
	 * @throws \InstallationException
191
	 * @throws \InvalidParameterException
192
	 */
193 4725
	private function getBootData(Config $config, Database $db, $installed) {
194 4725
		$config->_boot_cache_hit = false;
195
196 4725
		$data = $this->cache->load('boot_data');
197 4725
		if (!isset($data)) {
198 4725
			$data = new BootData();
199 4725
			$data->populate($db, _elgg_services()->entityTable, _elgg_services()->plugins, $installed);
200 4725
			if ($config->boot_cache_ttl) {
201 4725
				$this->cache->save('boot_data', $data, $config->boot_cache_ttl, [Invalidation::NONE]);
202
			}
203
		} else {
204
			$config->_boot_cache_hit = true;
205
		}
206
207 4725
		return $data;
208
	}
209
210
}
211