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

BootService   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Test Coverage

Coverage 87.67%

Importance

Changes 0
Metric Value
dl 0
loc 191
ccs 64
cts 73
cp 0.8767
rs 10
c 0
b 0
f 0
wmc 27

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A getBootData() 0 15 3
A invalidateCache() 0 4 2
F boot() 0 104 21
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
		// use value in settings.php if available
141 4725
		$debug = $config->hasInitialValue('debug') ? $config->getInitialValue('debug') : $config->debug;
142 4725
		$services->logger->setLevel($debug);
0 ignored issues
show
Bug introduced by
It seems like $debug can also be of type string; however, parameter $level of Elgg\Logger::setLevel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

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

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

200
				$this->cache->/** @scrutinizer ignore-call */ 
201
                  save('boot_data', $data, $config->boot_cache_ttl, [Invalidation::NONE]);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
201
			}
202
		} else {
203
			$config->_boot_cache_hit = true;
204
		}
205
206 4725
		return $data;
207
	}
208
209
}
210