Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

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

1
<?php
2
3
namespace Elgg;
4
5
use Elgg\Database\SiteSecret;
6
use Elgg\Di\ServiceProvider;
7
use Elgg\Project\Paths;
8
use ElggCache;
9
use Stash\Invalidation;
10
11
/**
12
 * Boots Elgg and manages a cache of data needed during boot
13
 *
14
 * @access private
15
 * @since 2.1
16
 */
17
class BootService {
18
	use Profilable;
19
20
	/**
21
	 * Under load, a short TTL gives nearly all of the benefits of a longer TTL, but it also ensures
22
	 * that, should cache invalidation fail for some reason, it'll be rebuilt quickly anyway.
23
	 *
24
	 * In 2.x we do not cache by default. This will likely change to 10 in 3.0.
25
	 */
26
	const DEFAULT_BOOT_CACHE_TTL = 0;
27
28
	/**
29
	 * Has the cache already been invalidated this request? Avoids thrashing
30
	 *
31
	 * @var bool
32
	 */
33
	private $was_cleared = false;
34
35
	/**
36
	 * @var ElggCache
37
	 */
38
	protected $cache;
39
40
	/**
41
	 * Cache
42
	 *
43
	 * @param ElggCache $cache Cache
44
	 */
45 4417
	public function __construct(ElggCache $cache) {
46 4417
		$this->cache = $cache;
47 4417
	}
48
49
	/**
50
	 * Boots the engine
51
	 *
52
	 * @param ServiceProvider $services Services
53
	 *
54
	 * @return void
55
	 * @throws \ClassException
56
	 * @throws \DatabaseException
57
	 * @throws \InstallationException
58
	 * @throws \InvalidParameterException
59
	 * @throws \SecurityException
60
	 */
61 4786
	public function boot(ServiceProvider $services) {
62 4777
		$db = $services->db;
63 4777
		$config = $services->config;
64
65
		// set cookie values for session and remember me
66 4777
		$config->getCookieConfig();
67
68
		// defaults in case these aren't in config table
69 4777
		if ($config->boot_cache_ttl === null) {
70 5
			$config->boot_cache_ttl = self::DEFAULT_BOOT_CACHE_TTL;
71
		}
72 4777
		if ($config->simplecache_enabled === null) {
73 5
			$config->simplecache_enabled = 0;
74
		}
75 4777
		if ($config->system_cache_enabled === null) {
76 5
			$config->system_cache_enabled = false;
77
		}
78 4777
		if ($config->simplecache_lastupdate === null) {
79 4417
			$config->simplecache_lastupdate = 0;
80
		}
81
82
		// we were using NOTICE temporarily so we can't just check for null
83 4777
		if (!$config->hasInitialValue('debug') && !$config->debug) {
84 5
			$config->debug = '';
85
		}
86
87
		// copy all table values into config
88 4777
		$config->mergeValues($services->configTable->getAll());
89
90
		// needs to be set before [init, system] for links in html head
91 4777
		$config->lastcache = (int) $config->simplecache_lastupdate;
92
93 4777
		if (!$config->elgg_config_set_secret) {
94 4777
			$site_secret = SiteSecret::fromConfig($config);
95 4777
			if (!$site_secret) {
96
				// The 2.3 installer doesn't create a site key (it's created on-demand on the first request)
97
				// so for our Travis upgrade testing we need to check for this and create one on the spot.
98
				if (defined('UPGRADING')) {
99
					$site_secret = SiteSecret::regenerate($services->crypto, $services->configTable);
100
				}
101
			}
102 4777
			if ($site_secret) {
103 4777
				$services->setValue('siteSecret', $site_secret);
104
			} else {
105
				throw new \RuntimeException('The site secret is not set.');
106
			}
107
		}
108
109 4777
		$installed = isset($config->installed);
110
111 4777
		if ($this->timer) {
112
			$this->timer->begin([__CLASS__ . '::getBootData']);
113
		}
114
115
		// early config is done, now get the core boot data
116 4777
		$data = $this->getBootData($config, $db, $installed);
117
118 4777
		$site = $data->getSite();
119 4777
		if (!$site) {
120
			// must be set in config
121
			$site = $config->site;
122
			if (!$site instanceof \ElggSite) {
123
				throw new \RuntimeException('Before installation, config->site must have an unsaved ElggSite.');
124
			}
125
		}
126 4777
		$config->site = $site;
127 4777
		$config->sitename = $site->name;
128 4777
		$config->sitedescription = $site->description;
129
130 4777
		$services->plugins->setBootPlugins($data->getActivePlugins());
131
132 4777
		$settings = $data->getPluginSettings();
133 4777
		foreach ($settings as $guid => $entity_settings) {
134 13
			$services->privateSettingsCache->save($guid, $entity_settings);
135
		}
136
137 4777
		foreach ($data->getPluginMetadata() as $guid => $metadata) {
138 13
			$services->dataCache->metadata->save($guid, $metadata);
139
		}
140
141
		// use value in settings.php if available
142 4777
		$debug = $config->hasInitialValue('debug') ? $config->getInitialValue('debug') : $config->debug;
143 4777
		$services->logger->setLevel($debug);
144
145
		// finish boot sequence
146 4777
		_elgg_session_boot($services);
147
148 4777
		if ($config->system_cache_enabled) {
149 13
			$config->system_cache_loaded = false;
150
151 13
			if ($services->views->configureFromCache($services->systemCache)) {
152 12
				$config->system_cache_loaded = true;
153
			}
154
		}
155
156
		// we don't store langs in boot data because it varies by user
157 4777
		$services->translator->loadTranslations();
158
159
		// invalidate on some actions just in case other invalidation triggers miss something
160 4786
		$services->hooks->registerHandler('action', 'all', function ($action) {
161 17
			if (0 === strpos($action, 'admin/' || $action === 'plugins/settings/save')) {
162
				$this->invalidateCache();
163
			}
164 4786
		}, 1);
165 4777
	}
166
167
	/**
168
	 * Invalidate the cache item
169
	 *
170
	 * @return void
171
	 */
172 1081
	public function invalidateCache() {
173 1081
		if (!$this->was_cleared) {
174 417
			$this->cache->clear();
175 417
			$this->was_cleared = true;
176
		}
177 1081
	}
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 4777
	private function getBootData(Config $config, Database $db, $installed) {
194 4777
		$config->_boot_cache_hit = false;
195
196 4777
		$data = $this->cache->load('boot_data');
197 4777
		if (!isset($data)) {
198 4777
			$data = new BootData();
199 4777
			$data->populate($db, _elgg_services()->entityTable, _elgg_services()->plugins, $installed);
200 4777
			if ($config->boot_cache_ttl) {
201 4777
				$this->cache->save('boot_data', $data, $config->boot_cache_ttl, [Invalidation::NONE]);
0 ignored issues
show
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

201
				$this->cache->/** @scrutinizer ignore-call */ 
202
                  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...
202
			}
203
		} else {
204
			$config->_boot_cache_hit = true;
205
		}
206
207 4777
		return $data;
208
	}
209
210
}
211