Completed
Pull Request — 2.x (#10101)
by Ismayil
12:05
created

Application::isTestingApplication()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Elgg;
4
5
use Elgg\Di\ServiceProvider;
6
use Elgg\Filesystem\Directory;
7
8
/**
9
 * Load, boot, and implement a front controller for an Elgg application
10
 *
11
 * To run as PHP CLI server:
12
 * <code>php -S localhost:8888 /full/path/to/elgg/index.php</code>
13
 *
14
 * The full path is necessary to work around this: https://bugs.php.net/bug.php?id=55726
15
 *
16
 * @since 2.0.0
17
 *
18
 * @property-read \Elgg\Menu\Service $menus
19
 * @property-read \Elgg\Views\TableColumn\ColumnFactory $table_columns
20
 */
21
class Application {
22
23
	const GET_PATH_KEY = '__elgg_uri';
24
	const REWRITE_TEST_TOKEN = '__testing_rewrite';
25
	const REWRITE_TEST_OUTPUT = 'success';
26
27
	/**
28
	 * @var ServiceProvider
29
	 */
30
	private $services;
31
32
	/**
33
	 * @var string
34
	 */
35
	private $engine_dir;
36
37
	/**
38
	 * @var bool
39
	 */
40
	private static $testing_app;
41
42
	/**
43
	 * Property names of the service provider to be exposed via __get()
44
	 *
45
	 * E.g. the presence of `'foo' => true` in the list would allow _elgg_services()->foo to
46
	 * be accessed via elgg()->foo.
47
	 *
48
	 * @var string[]
49
	 */
50
	private static $public_services = [
51
		//'config' => true,
52
		'menus' => true,
53
		'table_columns' => true,
54
	];
55
56
	/**
57
	 * Reference to the loaded Application returned by elgg()
58
	 *
59
	 * @internal Do not use this. use elgg() to access the application
60
	 * @access private
61
	 * @var Application
62
	 */
63
	public static $_instance;
64
65
	/**
66
	 * Constructor
67
	 *
68
	 * Upon construction, no actions are taken to load or boot Elgg.
69
	 *
70
	 * @param ServiceProvider $services Elgg services provider
71
	 */
72 182
	public function __construct(ServiceProvider $services) {
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
73 182
		$this->services = $services;
74
75
		/**
76
		 * The time with microseconds when the Elgg engine was started.
77
		 *
78
		 * @global float
79
		 */
80 182
		if (!isset($GLOBALS['START_MICROTIME'])) {
81 1
			$GLOBALS['START_MICROTIME'] = microtime(true);
82 1
		}
83
84 182
		$services->timer->begin([]);
85
86
		/**
87
		 * This was introduced in 2.0 in order to remove all internal non-API state from $CONFIG. This will
88
		 * be a breaking change, but frees us to refactor in 2.x without fear of plugins depending on
89
		 * $CONFIG.
90
		 *
91
		 * @access private
92
		 */
93 182
		if (!isset($GLOBALS['_ELGG'])) {
94
			$GLOBALS['_ELGG'] = new \stdClass();
95
		}
96
97 182
		$this->engine_dir = __DIR__ . '/../..';
98 182
	}
99
100
	/**
101
	 * Load settings.php
102
	 *
103
	 * This is done automatically during the boot process or before requesting a database object
104
	 *
105
	 * @see Config::loadSettingsFile
106
	 * @return void
107
	 */
108
	public function loadSettings() {
109
		$this->services->config->loadSettingsFile();
110
	}
111
112
	/**
113
	 * Load all Elgg procedural code and wire up boot events, but don't boot
114
	 *
115
	 * This is used for internal testing purposes
116
	 *
117
	 * @return void
118
	 * @access private
119
	 * @internal
120
	 */
121 180
	public function loadCore() {
122 180
		if (function_exists('elgg')) {
123 180
			return;
124
		}
125
126
		$lib_dir = self::elggDir()->chroot("engine/lib");
127
128
		// load the rest of the library files from engine/lib/
129
		// All on separate lines to make diffs easy to read + make it apparent how much
130
		// we're actually loading on every page (Hint: it's too much).
131
		$lib_files = array(
132
			// Needs to be loaded first to correctly bootstrap
133
			'autoloader.php',
134
			'elgglib.php',
135
136
			// The order of these doesn't matter, so keep them alphabetical
137
			'access.php',
138
			'actions.php',
139
			'admin.php',
140
			'annotations.php',
141
			'cache.php',
142
			'comments.php',
143
			'configuration.php',
144
			'cron.php',
145
			'database.php',
146
			'entities.php',
147
			'extender.php',
148
			'filestore.php',
149
			'friends.php',
150
			'group.php',
151
			'input.php',
152
			'languages.php',
153
			'mb_wrapper.php',
154
			'memcache.php',
155
			'metadata.php',
156
			'metastrings.php',
157
			'navigation.php',
158
			'notification.php',
159
			'objects.php',
160
			'output.php',
161
			'pagehandler.php',
162
			'pageowner.php',
163
			'pam.php',
164
			'plugins.php',
165
			'private_settings.php',
166
			'relationships.php',
167
			'river.php',
168
			'sessions.php',
169
			'sites.php',
170
			'statistics.php',
171
			'system_log.php',
172
			'tags.php',
173
			'user_settings.php',
174
			'users.php',
175
			'upgrade.php',
176
			'views.php',
177
			'widgets.php',
178
179
			// backward compatibility
180
			'deprecated-1.9.php',
181
			'deprecated-1.10.php',
182
			'deprecated-1.11.php',
183
			'deprecated-1.12.php',
184
			'deprecated-2.1.php',
185
		);
186
187
		// isolate global scope
188
		call_user_func(function () use ($lib_dir, $lib_files) {
189
190
			$setups = array();
191
192
			// include library files, capturing setup functions
193
			foreach ($lib_files as $file) {
194
				$setup = (require_once $lib_dir->getPath($file));
195
196
				if ($setup instanceof \Closure) {
197
					$setups[$file] = $setup;
198
				}
199
			}
200
201
			// store instance to be returned by elgg()
202
			self::$_instance = $this;
203
204
			// set up autoloading and DIC
205
			_elgg_services($this->services);
0 ignored issues
show
Unused Code introduced by
The call to the function _elgg_services() seems unnecessary as the function has no side-effects.
Loading history...
206
207
			$events = $this->services->events;
208
			$hooks = $this->services->hooks;
209
210
			// run setups
211
			foreach ($setups as $func) {
212
				$func($events, $hooks);
213
			}
214
		});
215
	}
216
217
	/**
218
	 * Replacement for loading engine/start.php
219
	 *
220
	 * @return self
221
	 */
222
	public static function start() {
223
		$app = self::create();
224
		$app->bootCore();
225
		return $app;
226
	}
227
228
	/**
229
	 * Bootstrap the Elgg engine, loads plugins, and calls initial system events
230
	 *
231
	 * This method loads the full Elgg engine, checks the installation
232
	 * state, and triggers a series of events to finish booting Elgg:
233
	 * 	- {@elgg_event boot system}
234
	 * 	- {@elgg_event init system}
235
	 * 	- {@elgg_event ready system}
236
	 *
237
	 * If Elgg is not fully installed, the browser will be redirected to an installation page.
238
	 *
239
	 * @return void
240
	 */
241
	public function bootCore() {
242
243
		$config = $this->services->config;
244
245
		if ($this->isTestingApplication()) {
246
			throw new \RuntimeException('Unit tests should not call ' . __METHOD__);
247
		}
248
249
		if ($config->getVolatile('boot_complete')) {
250
			return;
251
		}
252
253
		$this->loadSettings();
254
255
		$config->set('boot_complete', false);
256
257
		// This will be overridden by the DB value but may be needed before the upgrade script can be run.
258
		$config->set('default_limit', 10);
259
260
		// in case not loaded already
261
		$this->loadCore();
262
263
		$events = $this->services->events;
264
265
		// Connect to database, load language files, load configuration, init session
266
		// Plugins can't use this event because they haven't been loaded yet.
267
		$events->trigger('boot', 'system');
268
269
		// Load the plugins that are active
270
		$this->services->plugins->load();
271
272
		$root = Directory\Local::root();
273
		if ($root->getPath() != self::elggDir()->getPath()) {
274
			// Elgg is installed as a composer dep, so try to treat the root directory
275
			// as a custom plugin that is always loaded last and can't be disabled...
276
			if (!elgg_get_config('system_cache_loaded')) {
277
				// configure view locations for the custom plugin (not Elgg core)
278
				$viewsFile = $root->getFile('views.php');
279
				if ($viewsFile->exists()) {
280
					$viewsSpec = $viewsFile->includeFile();
281
					if (is_array($viewsSpec)) {
282
						_elgg_services()->views->mergeViewsSpec($viewsSpec);
283
					}
284
				}
285
286
				// find views for the custom plugin (not Elgg core)
287
				_elgg_services()->views->registerPluginViews($root->getPath());
288
			}
289
290
			if (!elgg_get_config('i18n_loaded_from_cache')) {
291
				_elgg_services()->translator->registerPluginTranslations($root->getPath());
292
			}
293
294
			// This is root directory start.php, not elgg/engine/start.php
295
			$root_start = $root->getPath("start.php");
296
			if (is_file($root_start)) {
297
				require $root_start;
298
			}
299
		}
300
301
302
		// @todo move loading plugins into a single boot function that replaces 'boot', 'system' event
303
		// and then move this code in there.
304
		// This validates the view type - first opportunity to do it is after plugins load.
305
		$viewtype = elgg_get_viewtype();
306
		if (!elgg_is_registered_viewtype($viewtype)) {
307
			elgg_set_viewtype('default');
308
		}
309
310
		$this->allowPathRewrite();
311
312
		// Allows registering handlers strictly before all init, system handlers
313
		$events->trigger('plugins_boot', 'system');
314
315
		// Complete the boot process for both engine and plugins
316
		$events->trigger('init', 'system');
317
318
		$config->set('boot_complete', true);
319
320
		// System loaded and ready
321
		$events->trigger('ready', 'system');
322
	}
323
324
	/**
325
	 * Get a Database wrapper for performing queries without booting Elgg
326
	 *
327
	 * If settings.php has not been loaded, it will be loaded to configure the DB connection.
328
	 *
329
	 * @note Do not type hint on \Elgg\Database, as this will fail in 3.0. If you must type hint,
330
	 *       expect an \Elgg\Application\Database.
331
	 *
332
	 * @note Before boot, the Database instance will not yet be bound to a Logger.
333
	 *
334
	 * @return \Elgg\Application\Database
335
	 */
336
	public function getDb() {
337
		$this->loadSettings();
338
		return $this->services->publicDb;
339
	}
340
341
	/**
342
	 * Get an undefined property
343
	 *
344
	 * @param string $name The property name accessed
345
	 *
346
	 * @return mixed
347
	 */
348
	public function __get($name) {
349
		if (isset(self::$public_services[$name])) {
350
			return $this->services->{$name};
351
		}
352
		trigger_error("Undefined property: " . __CLASS__ . ":\${$name}");
353
	}
354
355
	/**
356
	 * Creates a new, trivial instance of Elgg\Application and set it as the singleton instance.
357
	 * If the singleton is already set, it's returned.
358
	 *
359
	 * @return self
360
	 */
361
	private static function create() {
362
		if (self::$_instance === null) {
363
			// we need to register for shutdown before Symfony registers the
364
			// session_write_close() function. https://github.com/Elgg/Elgg/issues/9243
365
			register_shutdown_function(function () {
366
				// There are cases where we may exit before this function is defined
367
				if (function_exists('_elgg_shutdown_hook')) {
368
					_elgg_shutdown_hook();
369
				}
370
			});
371
372
			self::$_instance = new self(new Di\ServiceProvider(new Config()));
373
		}
374
375
		return self::$_instance;
376
	}
377
378
	/**
379
	 * Elgg's front controller. Handles basically all incoming URL requests.
380
	 *
381
	 * @return bool True if Elgg will handle the request, false if the server should (PHP-CLI server)
382
	 */
383
	public static function index() {
384
		return self::create()->run();
385
	}
386
387
	/**
388
	 * Routes the request, booting core if not yet booted
389
	 *
390
	 * @return bool False if Elgg wants the PHP CLI server to handle the request
391
	 */
392
	public function run() {
0 ignored issues
show
Coding Style introduced by
run uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
run uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
393
		$path = $this->setupPath();
394
395
		// allow testing from the upgrade page before the site is upgraded.
396
		if (isset($_GET[self::REWRITE_TEST_TOKEN])) {
397
			if (false !== strpos($path, self::REWRITE_TEST_TOKEN)) {
398
				echo self::REWRITE_TEST_OUTPUT;
399
			}
400
			return true;
401
		}
402
403
		if (php_sapi_name() === 'cli-server') {
404
			$www_root = "http://{$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']}/";
405
			$this->services->config->set('wwwroot', $www_root);
406
		}
407
408
		if (0 === strpos($path, '/cache/')) {
409
			(new Application\CacheHandler($this, $this->services->config, $_SERVER))->handleRequest($path);
0 ignored issues
show
Documentation introduced by
$path is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
410
			return true;
411
		}
412
413
		if (0 === strpos($path, '/serve-file/')) {
414
			$this->services->serveFileHandler->getResponse($this->services->request)->send();
415
			return true;
416
		}
417
418
		if ($path === '/rewrite.php') {
419
			require Directory\Local::root()->getPath("install.php");
420
			return true;
421
		}
422
423
		if (php_sapi_name() === 'cli-server') {
424
			// The CLI server routes ALL requests here (even existing files), so we have to check for these.
425
			if ($path !== '/' && Directory\Local::root()->isFile($path)) {
426
				// serve the requested resource as-is.
427
				return false;
428
			}
429
		}
430
431
		$this->bootCore();
432
433
		// TODO use formal Response object instead
434
		header("Content-Type: text/html;charset=utf-8");
435
436
		if (!$this->services->router->route($this->services->request)) {
437
			forward('', '404');
438
		}
439
	}
440
441
	/**
442
	 * Determine the Elgg data directory with trailing slash, save it to config, and return it
443
	 *
444
	 * @todo Consider a better place for this logic? We need it before boot
445
	 *
446
	 * @return string
447
	 * @throws \InstallationException
448
	 */
449
	public static function getDataPath() {
0 ignored issues
show
Coding Style introduced by
getDataPath uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
450
		$app = self::create();
451
		$app->services->config->loadSettingsFile();
452
453
		if ($GLOBALS['_ELGG']->dataroot_in_settings) {
454
			return $app->services->config->getVolatile('dataroot');
455
		}
456
457
		$dataroot = $app->services->datalist->get('dataroot');
458
		if (!$dataroot) {
459
			throw new \InstallationException('The datalists table lacks a value for "dataroot".');
460
		}
461
		$dataroot = rtrim($dataroot, '/\\') . DIRECTORY_SEPARATOR;
462
		$app->services->config->set('dataroot', $dataroot);
463
		return $dataroot;
464
	}
465
466
	/**
467
	 * Returns a directory that points to the root of Elgg, but not necessarily
468
	 * the install root. See `self::root()` for that.
469
	 *
470
	 * @return Directory
471
	 */
472
	public static function elggDir() /*: Directory*/ {
473
		return Directory\Local::fromPath(realpath(__DIR__ . '/../../..'));
474
	}
475
476
	/**
477
	 * Renders a web UI for installing Elgg.
478
	 *
479
	 * @return void
480
	 */
481
	public static function install() {
482
		ini_set('display_errors', 1);
483
		$installer = new \ElggInstaller();
484
		$step = get_input('step', 'welcome');
485
		$installer->run($step);
486
	}
487
488
	/**
489
	 * Elgg upgrade script.
490
	 *
491
	 * This script triggers any necessary upgrades. If the site has been upgraded
492
	 * to the most recent version of the code, no upgrades are run but the caches
493
	 * are flushed.
494
	 *
495
	 * Upgrades use a table {db_prefix}upgrade_lock as a mutex to prevent concurrent upgrades.
496
	 *
497
	 * The URL to forward to after upgrades are complete can be specified by setting $_GET['forward']
498
	 * to a relative URL.
499
	 *
500
	 * @return void
501
	 */
502
	public static function upgrade() {
503
		// we want to know if an error occurs
504
		ini_set('display_errors', 1);
505
506
		define('UPGRADING', 'upgrading');
507
508
		self::start();
509
510
		$site_url = elgg_get_config('url');
511
		$site_host = parse_url($site_url, PHP_URL_HOST) . '/';
512
513
		// turn any full in-site URLs into absolute paths
514
		$forward_url = get_input('forward', '/admin', false);
515
		$forward_url = str_replace(array($site_url, $site_host), '/', $forward_url);
516
517
		if (strpos($forward_url, '/') !== 0) {
518
			$forward_url = '/' . $forward_url;
519
		}
520
521
		if (get_input('upgrade') == 'upgrade') {
522
523
			$upgrader = _elgg_services()->upgrades;
524
			$result = $upgrader->run();
525
			if ($result['failure'] == true) {
526
				register_error($result['reason']);
527
				forward($forward_url);
528
			}
529
		} else {
530
			$rewriteTester = new \ElggRewriteTester();
531
			$url = elgg_get_site_url() . "__testing_rewrite?__testing_rewrite=1";
532
			if (!$rewriteTester->runRewriteTest($url)) {
533
				// see if there is a problem accessing the site at all
534
				// due to ip restrictions for example
535
				if (!$rewriteTester->runLocalhostAccessTest()) {
536
					// note: translation may not be available until after upgrade
537
					$msg = elgg_echo("installation:htaccess:localhost:connectionfailed");
538
					if ($msg === "installation:htaccess:localhost:connectionfailed") {
539
						$msg = "Elgg cannot connect to itself to test rewrite rules properly. Check "
540
								. "that curl is working and there are no IP restrictions preventing "
541
								. "localhost connections.";
542
					}
543
					echo $msg;
544
					exit;
545
				}
546
547
				// note: translation may not be available until after upgrade
548
				$msg = elgg_echo("installation:htaccess:needs_upgrade");
549
				if ($msg === "installation:htaccess:needs_upgrade") {
550
					$msg = "You must update your .htaccess file so that the path is injected "
551
						. "into the GET parameter __elgg_uri (you can use install/config/htaccess.dist as a guide).";
552
				}
553
				echo $msg;
554
				exit;
555
			}
556
557
			$vars = array(
558
				'forward' => $forward_url
559
			);
560
561
			// reset cache to have latest translations available during upgrade
562
			elgg_reset_system_cache();
563
564
			echo elgg_view_page(elgg_echo('upgrading'), '', 'upgrade', $vars);
565
			exit;
566
		}
567
568
		forward($forward_url);
569
	}
570
571
	/**
572
	 * Get the request URI and store it in $_GET['__elgg_uri']
573
	 *
574
	 * @return string e.g. "cache/123..."
575
	 */
576
	private function setupPath() {
0 ignored issues
show
Coding Style introduced by
setupPath uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
setupPath uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
577
		if (!isset($_GET[self::GET_PATH_KEY]) || is_array($_GET[self::GET_PATH_KEY])) {
578
			if (php_sapi_name() === 'cli-server') {
579
				$_GET[self::GET_PATH_KEY] = (string)parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
580
			} else {
581
				$_GET[self::GET_PATH_KEY] = '/';
582
			}
583
		}
584
585
		// normalize
586
		$_GET[self::GET_PATH_KEY] = '/' . trim($_GET[self::GET_PATH_KEY], '/');
587
588
		return $_GET[self::GET_PATH_KEY];
589
	}
590
591
	/**
592
	 * Allow plugins to rewrite the path.
593
	 *
594
	 * @return void
595
	 */
596
	private function allowPathRewrite() {
597
		$request = $this->services->request;
598
		$new = $this->services->router->allowRewrite($request);
599
		if ($new === $request) {
600
			return;
601
		}
602
603
		$this->services->setValue('request', $new);
604
		_elgg_set_initial_context($new);
605
	}
606
607
	/**
608
	 * Flag this application as running for testing (PHPUnit)
609
	 * 
610
	 * @param bool $testing Is testing application
611
	 * @return void
612
	 */
613 180
	public static function setTestingApplication($testing = true) {
614 180
		self::$testing_app = $testing;
615 180
	}
616
617
	/**
618
	 * Checks if the application is running in PHPUnit
619
	 * @return bool
620
	 */
621 1
	public static function isTestingApplication() {
622 1
		return (bool) self::$testing_app;
623
	}
624
}
625