Completed
Branch newinternal (4dede1)
by Simon
03:45
created

WebStart::exceptionHandler()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 62
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 7
Bugs 1 Features 0
Metric Value
c 7
b 1
f 0
dl 0
loc 62
ccs 0
cts 47
cp 0
rs 9.4743
cc 3
eloc 27
nc 4
nop 1
crap 12

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca;
10
11
use Waca\DataObjects\User;
12
use Waca\Exceptions\EnvironmentException;
13
use Waca\Exceptions\ReadableException;
14
use Waca\Helpers\BlacklistHelper;
15
use Waca\Helpers\FakeBlacklistHelper;
16
use Waca\Helpers\TypeAheadHelper;
17
use Waca\Providers\GlobalStateProvider;
18
use Waca\Router\IRequestRouter;
19
use Waca\Security\SecurityManager;
20
use Waca\Security\TokenManager;
21
use Waca\Tasks\ITask;
22
use Waca\Tasks\InternalPageBase;
23
use Waca\Tasks\PageBase;
24
25
/**
26
 * Internal application entry point.
27
 *
28
 * @package Waca
29
 */
30
class WebStart extends ApplicationBase
31
{
32
	/**
33
	 * @var IRequestRouter
34
	 */
35
	private $requestRouter;
36
	/** @var bool */
37
	private $isPublic;
38
39
	/**
40
	 * WebStart constructor.
41
	 *
42
	 * @param SiteConfiguration $configuration The site configuration
43
	 * @param IRequestRouter    $router        The request router to use
44
	 */
45
	public function __construct(SiteConfiguration $configuration, IRequestRouter $router)
46
	{
47
		parent::__construct($configuration);
48
49
		$this->requestRouter = $router;
50
	}
51
52
	/**
53
	 * @param ITask             $page
54
	 * @param SiteConfiguration $siteConfiguration
55
	 * @param PdoDatabase       $database
56
	 * @param PdoDatabase       $notificationsDatabase
57
	 *
58
	 * @return void
59
	 */
60
	protected function setupHelpers(
61
		ITask $page,
62
		SiteConfiguration $siteConfiguration,
63
		PdoDatabase $database,
64
		PdoDatabase $notificationsDatabase
65
	) {
66
		parent::setupHelpers($page, $siteConfiguration, $database, $notificationsDatabase);
67
68
		if ($page instanceof PageBase) {
69
			$page->setTokenManager(new TokenManager());
70
71
			if ($page instanceof InternalPageBase) {
72
				$page->setTypeAheadHelper(new TypeAheadHelper());
73
74
				$identificationVerifier = new IdentificationVerifier($page->getHttpHelper(), $siteConfiguration,
75
					$database);
76
				$page->setIdentificationVerifier($identificationVerifier);
77
78
				$page->setSecurityManager(new SecurityManager($identificationVerifier,
79
					$siteConfiguration->getForceIdentification()));
80
81
				if ($siteConfiguration->getTitleBlacklistEnabled()) {
82
					$page->setBlacklistHelper(new FakeBlacklistHelper());
83
				}
84
				else {
85
					$page->setBlacklistHelper(new BlacklistHelper($page->getHttpHelper(),
86
						$siteConfiguration->getMediawikiWebServiceEndpoint()));
87
				}
88
			}
89
		}
90
	}
91
92
	/**
93
	 * Application entry point.
94
	 *
95
	 * Sets up the environment and runs the application, performing any global cleanup operations when done.
96
	 */
97
	public function run()
98
	{
99
		try {
100
			if ($this->setupEnvironment()) {
101
				$this->main();
102
			}
103
		}
104
		catch (EnvironmentException $ex) {
105
			ob_end_clean();
106
			print Offline::getOfflineMessage(false, $ex->getMessage());
107
		}
108
		catch (ReadableException $ex) {
109
			ob_end_clean();
110
			print $ex->getReadableError();
111
		}
112
		finally {
113
			$this->cleanupEnvironment();
114
		}
115
	}
116
117
	/**
118
	 * Environment setup
119
	 *
120
	 * This method initialises the tool environment. If the tool cannot be initialised correctly, it will return false
121
	 * and shut down prematurely.
122
	 *
123
	 * @return bool
124
	 * @throws EnvironmentException
125
	 */
126
	protected function setupEnvironment()
127
	{
128
		// initialise global exception handler
129
		set_exception_handler(array(ExceptionHandler::class, 'exceptionHandler'));
130
		set_error_handler(array(ExceptionHandler::class, 'errorHandler'), E_RECOVERABLE_ERROR);
131
132
		// start output buffering if necessary
133
		if (ob_get_level() === 0) {
134
			ob_start();
135
		}
136
137
		// initialise super-global providers
138
		WebRequest::setGlobalStateProvider(new GlobalStateProvider());
139
140
		if (Offline::isOffline()) {
141
			print Offline::getOfflineMessage($this->isPublic());
142
			ob_end_flush();
143
144
			return false;
145
		}
146
147
		// Call parent setup
148
		if (!parent::setupEnvironment()) {
149
			return false;
150
		}
151
152
		// Start up sessions
153
		Session::start();
154
155
		// Check the user is allowed to be logged in still. This must be before we call any user-loading functions and
156
		// get the current user cached.
157
		// I'm not sure if this function call being here is particularly a good thing, but it's part of starting up a
158
		// session I suppose.
159
		$this->checkForceLogout();
160
161
		// environment initialised!
162
		return true;
163
	}
164
165
	/**
166
	 * Main application logic
167
	 */
168
	protected function main()
169
	{
170
		// Get the right route for the request
171
		$page = $this->requestRouter->route();
172
173
		$siteConfiguration = $this->getConfiguration();
174
		$database = PdoDatabase::getDatabaseConnection('acc');
175
176
		if ($siteConfiguration->getIrcNotificationsEnabled()) {
177
			$notificationsDatabase = PdoDatabase::getDatabaseConnection('notifications');
178
		}
179
		else {
180
			// @todo federated table here?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
181
			$notificationsDatabase = $database;
182
		}
183
184
		$this->setupHelpers($page, $siteConfiguration, $database, $notificationsDatabase);
185
186
		/* @todo Remove this global statement! It's here for User.php, which does far more than it should. */
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
187
		global $oauthHelper;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
188
		$oauthHelper = $page->getOAuthHelper();
189
190
		/* @todo Remove this global statement! It's here for Request.php, which does far more than it should. */
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
191
		global $globalXffTrustProvider;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
192
		$globalXffTrustProvider = $page->getXffTrustProvider();
193
194
		// run the route code for the request.
195
		$page->execute();
196
	}
197
198
	/**
199
	 * Any cleanup tasks should go here
200
	 *
201
	 * Note that we need to be very careful here, as exceptions may have been thrown and handled.
202
	 * This should *only* be for cleaning up, no logic should go here.
203
	 */
204
	protected function cleanupEnvironment()
205
	{
206
		// Clean up anything we splurged after sending the page.
207
		if (ob_get_level() > 0) {
208
			for ($i = ob_get_level(); $i > 0; $i--) {
209
				ob_end_clean();
210
			}
211
		}
212
	}
213
214
	private function checkForceLogout()
215
	{
216
		$database = PdoDatabase::getDatabaseConnection('acc');
217
218
		$sessionUserId = WebRequest::getSessionUserId();
219
		iF ($sessionUserId === null) {
220
			return;
221
		}
222
223
		// Note, User::getCurrent() caches it's result, which we *really* don't want to trigger.
224
		$currentUser = User::getById($sessionUserId, $database);
225
226
		if ($currentUser === false) {
227
			// Umm... this user has a session cookie with a userId set, but no user exists...
228
			Session::restart();
229
		}
230
231
		if ($currentUser->getForceLogout()) {
232
			Session::restart();
233
234
			$currentUser->setForceLogout(false);
235
			$currentUser->save();
236
		}
237
	}
238
239
	public function isPublic()
240
	{
241
		return $this->isPublic;
242
	}
243
244
	public function setPublic($isPublic)
245
	{
246
		$this->isPublic = $isPublic;
247
	}
248
}
249