Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — master (#959)
by Dan
03:44
created

AbstractSmrLocation   F

Complexity

Total Complexity 109

Size/Duplication

Total Lines 447
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 256
dl 0
loc 447
rs 2
c 1
b 0
f 1
wmc 109

42 Methods

Rating   Name   Duplication   Size   Complexity  
A getGalaxyLocations() 0 16 3
A clearCache() 0 4 1
A getSectorLocations() 0 12 4
A getAllLocations() 0 12 4
C hasX() 0 42 17
A getEditHREF() 0 5 1
A setName() 0 7 2
A isWeaponSold() 0 6 2
A isUG() 0 6 2
A addWeaponSold() 0 7 2
A removeHardwareSold() 0 6 2
A getLocation() 0 5 3
A hasAction() 0 2 1
A setUG() 0 10 3
A addSectorLocation() 0 6 1
A removeWeaponSold() 0 6 2
A getLinkedLocations() 0 14 3
A getName() 0 2 1
A isHQ() 0 6 2
A __construct() 0 19 3
A setHQ() 0 10 3
A removeShipSold() 0 6 2
A getWeaponsSold() 0 10 3
A setBar() 0 10 3
A equals() 0 2 1
A setBank() 0 10 3
A setFed() 0 10 3
A addShipSold() 0 10 3
A isShipSold() 0 6 2
A removeSectorLocations() 0 4 1
A getAction() 0 2 1
A isBar() 0 6 2
A isBank() 0 6 2
A getHardwareSold() 0 9 3
A isHardwareSold() 0 6 2
A getRaceID() 0 8 5
A getTypeID() 0 2 1
A getImage() 0 2 1
A addHardwareSold() 0 10 3
A getShipsSold() 0 9 3
A getExamineHREF() 0 4 1
A isFed() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like AbstractSmrLocation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractSmrLocation, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
class AbstractSmrLocation {
3
	protected static $CACHE_ALL_LOCATIONS;
4
	protected static $CACHE_LOCATIONS = array();
5
	protected static $CACHE_SECTOR_LOCATIONS = array();
6
7
	protected MySqlDatabase $db;
8
	protected string $SQL;
9
10
	protected int $typeID;
11
	protected string $name;
12
	protected ?string $processor;
13
	protected string $image;
14
15
	protected bool $fed;
16
	protected bool $bank;
17
	protected bool $bar;
18
	protected bool $HQ;
19
	protected bool $UG;
20
21
	protected array $hardwareSold;
22
	protected array $shipsSold;
23
	protected array $weaponsSold;
24
25
	public static function clearCache() : void {
26
		self::$CACHE_ALL_LOCATIONS = [];
27
		self::$CACHE_LOCATIONS = [];
28
		self::$CACHE_SECTOR_LOCATIONS = [];
29
	}
30
31
	public static function getAllLocations(bool $forceUpdate = false) : array {
32
		if ($forceUpdate || !isset(self::$CACHE_ALL_LOCATIONS)) {
33
			$db = MySqlDatabase::getInstance();
34
			$db->query('SELECT * FROM location_type ORDER BY location_type_id');
35
			$locations = array();
36
			while ($db->nextRecord()) {
37
				$locationTypeID = $db->getInt('location_type_id');
38
				$locations[$locationTypeID] = SmrLocation::getLocation($locationTypeID, $forceUpdate, $db);
39
			}
40
			self::$CACHE_ALL_LOCATIONS = $locations;
41
		}
42
		return self::$CACHE_ALL_LOCATIONS;
43
	}
44
45
	public static function getGalaxyLocations(int $gameID, int $galaxyID, bool $forceUpdate = false) : array {
46
		$db = MySqlDatabase::getInstance();
47
		$db->query('SELECT location_type.*, sector_id FROM sector LEFT JOIN location USING(game_id, sector_id) LEFT JOIN location_type USING (location_type_id) WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND galaxy_id = ' . $db->escapeNumber($galaxyID));
48
		$galaxyLocations = [];
49
		while ($db->nextRecord()) {
50
			$sectorID = $db->getInt('sector_id');
51
			if (!$db->hasField('location_type_id')) {
52
				self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID] = [];
53
			} else {
54
				$locationTypeID = $db->getInt('location_type_id');
55
				$location = self::getLocation($locationTypeID, $forceUpdate, $db);
56
				self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID][$locationTypeID] = $location;
57
				$galaxyLocations[$sectorID][$locationTypeID] = $location;
58
			}
59
		}
60
		return $galaxyLocations;
61
	}
62
63
	public static function getSectorLocations(int $gameID, int $sectorID, bool $forceUpdate = false) : array {
64
		if ($forceUpdate || !isset(self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID])) {
65
			$db = MySqlDatabase::getInstance();
66
			$db->query('SELECT * FROM location JOIN location_type USING (location_type_id) WHERE sector_id = ' . $db->escapeNumber($sectorID) . ' AND game_id=' . $db->escapeNumber($gameID));
67
			$locations = array();
68
			while ($db->nextRecord()) {
69
				$locationTypeID = $db->getInt('location_type_id');
70
				$locations[$locationTypeID] = self::getLocation($locationTypeID, $forceUpdate, $db);
71
			}
72
			self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID] = $locations;
73
		}
74
		return self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID];
75
	}
76
77
	public static function addSectorLocation(int $gameID, int $sectorID, SmrLocation $location) : void {
78
		self::getSectorLocations($gameID, $sectorID); // make sure cache is populated
79
		$db = MySqlDatabase::getInstance();
80
		$db->query('INSERT INTO location (game_id, sector_id, location_type_id)
81
						values(' . $db->escapeNumber($gameID) . ',' . $db->escapeNumber($sectorID) . ',' . $db->escapeNumber($location->getTypeID()) . ')');
82
		self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID][$location->getTypeID()] = $location;
83
	}
84
85
	public static function removeSectorLocations(int $gameID, int $sectorID) : void {
86
		$db = MySqlDatabase::getInstance();
87
		$db->query('DELETE FROM location WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND sector_id = ' . $db->escapeNumber($sectorID));
88
		self::$CACHE_SECTOR_LOCATIONS[$gameID][$sectorID] = [];
89
	}
90
91
	public static function getLocation(int $locationTypeID, bool $forceUpdate = false, MySqlDatabase $db = null) : SmrLocation {
92
		if ($forceUpdate || !isset(self::$CACHE_LOCATIONS[$locationTypeID])) {
93
			self::$CACHE_LOCATIONS[$locationTypeID] = new SmrLocation($locationTypeID, $db);
94
		}
95
		return self::$CACHE_LOCATIONS[$locationTypeID];
96
	}
97
98
	protected function __construct(int $locationTypeID, ?MySqlDatabase $db = null) {
99
		$this->db = MySqlDatabase::getInstance();
100
		$this->SQL = 'location_type_id = ' . $this->db->escapeNumber($locationTypeID);
101
102
		if (isset($db)) {
103
			$locationExists = true;
104
		} else {
105
			$db = $this->db;
106
			$db->query('SELECT * FROM location_type WHERE ' . $this->SQL . ' LIMIT 1');
107
			$locationExists = $db->nextRecord();
108
		}
109
110
		if ($locationExists) {
111
			$this->typeID = $db->getInt('location_type_id');
112
			$this->name = $db->getField('location_name');
113
			$this->processor = $db->getField('location_processor');
114
			$this->image = $db->getField('location_image');
115
		} else {
116
			throw new Exception('Cannot find location: ' . $locationTypeID);
117
		}
118
	}
119
120
	public function getTypeID() : int {
121
		return $this->typeID;
122
	}
123
124
	public function getRaceID() : int {
125
		if ($this->isFed() && $this->getTypeID() != LOCATION_TYPE_FEDERAL_BEACON) {
126
			return $this->getTypeID() - LOCATION_GROUP_RACIAL_BEACONS;
127
		}
128
		if ($this->isHQ() && $this->getTypeID() != LOCATION_TYPE_FEDERAL_HQ) {
129
			return $this->getTypeID() - LOCATION_GROUP_RACIAL_HQS;
130
		}
131
		return RACE_NEUTRAL;
132
	}
133
134
	public function getName() : string {
135
		return $this->name;
136
	}
137
138
	public function setName(string $name) : void {
139
		$name = htmlentities($name, ENT_COMPAT, 'utf-8');
140
		if ($this->name === $name) {
141
			return;
142
		}
143
		$this->name = $name;
144
		$this->db->query('UPDATE location_type SET location_name=' . $this->db->escapeString($this->name) . ' WHERE ' . $this->SQL . ' LIMIT 1');
145
	}
146
147
	public function hasAction() : bool {
148
		return $this->processor !== null;
149
	}
150
151
	public function getAction() : ?string {
152
		return $this->processor;
153
	}
154
155
	public function getImage() : string {
156
		return $this->image;
157
	}
158
159
	public function isFed() : bool {
160
		if (!isset($this->fed)) {
161
			$this->db->query('SELECT * FROM location_is_fed WHERE ' . $this->SQL . ' LIMIT 1');
162
			$this->fed = $this->db->nextRecord();
163
		}
164
		return $this->fed;
165
	}
166
167
	public function setFed(bool $bool) : void {
168
		if ($this->fed === $bool) {
169
			return;
170
		}
171
		if ($bool) {
172
			$this->db->query('INSERT IGNORE INTO location_is_fed (location_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ')');
173
		} else {
174
			$this->db->query('DELETE FROM location_is_fed WHERE ' . $this->SQL . ' LIMIT 1');
175
		}
176
		$this->fed = $bool;
177
	}
178
179
	public function isBank() : bool {
180
		if (!isset($this->bank)) {
181
			$this->db->query('SELECT * FROM location_is_bank WHERE ' . $this->SQL . ' LIMIT 1');
182
			$this->bank = $this->db->nextRecord();
183
		}
184
		return $this->bank;
185
	}
186
187
	public function setBank(bool $bool) : void {
188
		if ($this->bank === $bool) {
189
			return;
190
		}
191
		if ($bool) {
192
			$this->db->query('INSERT INTO location_is_bank (location_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ')');
193
		} else {
194
			$this->db->query('DELETE FROM location_is_bank WHERE ' . $this->SQL . ' LIMIT 1');
195
		}
196
		$this->bank = $bool;
197
	}
198
199
	public function isBar() : bool {
200
		if (!isset($this->bar)) {
201
			$this->db->query('SELECT * FROM location_is_bar WHERE ' . $this->SQL . ' LIMIT 1');
202
			$this->bar = $this->db->nextRecord();
203
		}
204
		return $this->bar;
205
	}
206
207
	public function setBar(bool $bool) : void {
208
		if ($this->bar === $bool) {
209
			return;
210
		}
211
		if ($bool) {
212
			$this->db->query('INSERT IGNORE INTO location_is_bar (location_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ')');
213
		} else {
214
			$this->db->query('DELETE FROM location_is_bar WHERE ' . $this->SQL . ' LIMIT 1');
215
		}
216
		$this->bar = $bool;
217
	}
218
219
	public function isHQ() : bool {
220
		if (!isset($this->HQ)) {
221
			$this->db->query('SELECT * FROM location_is_hq WHERE ' . $this->SQL . ' LIMIT 1');
222
			$this->HQ = $this->db->nextRecord();
223
		}
224
		return $this->HQ;
225
	}
226
227
	public function setHQ(bool $bool) : void {
228
		if ($this->HQ === $bool) {
229
			return;
230
		}
231
		if ($bool) {
232
			$this->db->query('INSERT IGNORE INTO location_is_hq (location_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ')');
233
		} else {
234
			$this->db->query('DELETE FROM location_is_hq WHERE ' . $this->SQL . ' LIMIT 1');
235
		}
236
		$this->HQ = $bool;
237
	}
238
239
	public function isUG() : bool {
240
		if (!isset($this->UG)) {
241
			$this->db->query('SELECT * FROM location_is_ug WHERE ' . $this->SQL . ' LIMIT 1');
242
			$this->UG = $this->db->nextRecord();
243
		}
244
		return $this->UG;
245
	}
246
247
	public function setUG(bool $bool) : void {
248
		if ($this->UG === $bool) {
249
			return;
250
		}
251
		if ($bool) {
252
			$this->db->query('INSERT INTO location_is_ug (location_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ')');
253
		} else {
254
			$this->db->query('DELETE FROM location_is_ug WHERE ' . $this->SQL . ' LIMIT 1');
255
		}
256
		$this->UG = $bool;
257
	}
258
259
	public function getHardwareSold() : array {
260
		if (!isset($this->hardwareSold)) {
261
			$this->hardwareSold = array();
262
			$this->db->query('SELECT hardware_type_id FROM location_sells_hardware WHERE ' . $this->SQL);
263
			while ($this->db->nextRecord()) {
264
				$this->hardwareSold[$this->db->getInt('hardware_type_id')] = Globals::getHardwareTypes($this->db->getInt('hardware_type_id'));
265
			}
266
		}
267
		return $this->hardwareSold;
268
	}
269
270
	public function isHardwareSold(int $hardwareTypeID = null) : bool {
271
		$hardware = $this->getHardwareSold();
272
		if ($hardwareTypeID === null) {
273
			return count($hardware) != 0;
274
		}
275
		return isset($hardware[$hardwareTypeID]);
276
	}
277
278
	public function addHardwareSold(int $hardwareTypeID) : void {
279
		if ($this->isHardwareSold($hardwareTypeID)) {
280
			return;
281
		}
282
		$this->db->query('SELECT * FROM hardware_type WHERE hardware_type_id = ' . $this->db->escapeNumber($hardwareTypeID) . ' LIMIT 1');
283
		if (!$this->db->nextRecord()) {
284
			throw new Exception('Invalid hardware type id given');
285
		}
286
		$this->db->query('INSERT INTO location_sells_hardware (location_type_id,hardware_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ',' . $this->db->escapeNumber($hardwareTypeID) . ')');
287
		$this->hardwareSold[$hardwareTypeID] = $this->db->getField('hardware_name');
288
	}
289
290
	public function removeHardwareSold(int $hardwareTypeID) : void {
291
		if (!$this->isHardwareSold($hardwareTypeID)) {
292
			return;
293
		}
294
		$this->db->query('DELETE FROM location_sells_hardware WHERE ' . $this->SQL . ' AND hardware_type_id = ' . $this->db->escapeNumber($hardwareTypeID) . ' LIMIT 1');
295
		unset($this->hardwareSold[$hardwareTypeID]);
296
	}
297
298
	public function getShipsSold() : array {
299
		if (!isset($this->shipsSold)) {
300
			$this->shipsSold = array();
301
			$this->db->query('SELECT * FROM location_sells_ships WHERE ' . $this->SQL);
302
			while ($this->db->nextRecord()) {
303
				$this->shipsSold[$this->db->getInt('ship_type_id')] = AbstractSmrShip::getBaseShip(Globals::getGameType(SmrSession::getGameID()), $this->db->getInt('ship_type_id'));
304
			}
305
		}
306
		return $this->shipsSold;
307
	}
308
309
	public function isShipSold(int $shipTypeID = null) : bool {
310
		$ships = $this->getShipsSold();
311
		if ($shipTypeID === null) {
312
			return count($ships) != 0;
313
		}
314
		return isset($ships[$shipTypeID]);
315
	}
316
317
	public function addShipSold(int $shipTypeID) : void {
318
		if ($this->isShipSold($shipTypeID)) {
319
			return;
320
		}
321
		$ship = AbstractSmrShip::getBaseShip(Globals::getGameType(SmrSession::getGameID()), $shipTypeID);
322
		if ($ship === false) {
323
			throw new Exception('Invalid ship type id given');
324
		}
325
		$this->db->query('INSERT INTO location_sells_ships (location_type_id,ship_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ',' . $this->db->escapeNumber($shipTypeID) . ')');
326
		$this->shipsSold[$shipTypeID] = $ship;
327
	}
328
329
	public function removeShipSold(int $shipTypeID) : void {
330
		if (!$this->isShipSold($shipTypeID)) {
331
			return;
332
		}
333
		$this->db->query('DELETE FROM location_sells_ships WHERE ' . $this->SQL . ' AND ship_type_id = ' . $this->db->escapeNumber($shipTypeID) . ' LIMIT 1');
334
		unset($this->shipsSold[$shipTypeID]);
335
	}
336
337
	public function getWeaponsSold() : array {
338
		if (!isset($this->weaponsSold)) {
339
			$this->weaponsSold = array();
340
			$this->db->query('SELECT * FROM location_sells_weapons JOIN weapon_type USING (weapon_type_id) WHERE ' . $this->SQL);
341
			while ($this->db->nextRecord()) {
342
				$weaponTypeID = $this->db->getInt('weapon_type_id');
343
				$this->weaponsSold[$weaponTypeID] = SmrWeapon::getWeapon($weaponTypeID, $this->db);
344
			}
345
		}
346
		return $this->weaponsSold;
347
	}
348
349
	public function isWeaponSold(int $weaponTypeID = null) : bool {
350
		$weapons = $this->getWeaponsSold();
351
		if ($weaponTypeID === null) {
352
			return count($weapons) != 0;
353
		}
354
		return isset($weapons[$weaponTypeID]);
355
	}
356
357
	public function addWeaponSold(int $weaponTypeID) : void {
358
		if ($this->isWeaponSold($weaponTypeID)) {
359
			return;
360
		}
361
		$weapon = SmrWeapon::getWeapon($weaponTypeID);
362
		$this->db->query('INSERT INTO location_sells_weapons (location_type_id,weapon_type_id) values (' . $this->db->escapeNumber($this->getTypeID()) . ',' . $this->db->escapeNumber($weaponTypeID) . ')');
363
		$this->weaponsSold[$weaponTypeID] = $weapon;
364
	}
365
366
	public function removeWeaponSold(int $weaponTypeID) : void {
367
		if (!$this->isWeaponSold($weaponTypeID)) {
368
			return;
369
		}
370
		$this->db->query('DELETE FROM location_sells_weapons WHERE ' . $this->SQL . ' AND weapon_type_id = ' . $this->db->escapeNumber($weaponTypeID) . ' LIMIT 1');
371
		unset($this->weaponsSold[$weaponTypeID]);
372
	}
373
374
	public function getLinkedLocations() : array {
375
		$linkedLocations = array();
376
		if ($this->isHQ()) {
377
			if ($this->getTypeID() == LOCATION_TYPE_FEDERAL_HQ) {
378
				$linkedLocations[] = SmrLocation::getLocation(LOCATION_TYPE_FEDERAL_BEACON);
379
				$linkedLocations[] = SmrLocation::getLocation(LOCATION_TYPE_FEDERAL_MINT);
380
			} else {
381
				$raceID = $this->getRaceID();
382
				$linkedLocations[] = SmrLocation::getLocation(LOCATION_GROUP_RACIAL_BEACONS + $raceID);
383
				$linkedLocations[] = SmrLocation::getLocation(LOCATION_GROUP_RACIAL_SHIPS + $raceID);
384
				$linkedLocations[] = SmrLocation::getLocation(LOCATION_GROUP_RACIAL_SHOPS + $raceID);
385
			}
386
		}
387
		return $linkedLocations;
388
	}
389
390
	public function getExamineHREF() : string {
391
		$container = create_container('skeleton.php', $this->getAction());
392
		$container['LocationID'] = $this->getTypeID();
393
		return SmrSession::getNewHREF($container);
394
	}
395
396
	public function getEditHREF() : string {
397
		$container = create_container('skeleton.php', 'location_edit.php');
398
		$container['game_type_id'] = 0; //TODO add game type id
399
		$container['location_type_id'] = $this->getTypeID();
400
		return SmrSession::getNewHREF($container);
401
	}
402
403
	public function equals(SmrLocation $otherLocation) : bool {
404
		return $this->getTypeID() == $otherLocation->getTypeID();
405
	}
406
407
	public function hasX(/*Object*/ $x, AbstractSmrPlayer $player = null) : bool {
408
		if ($x instanceof SmrWeaponType) {
409
			return $this->isWeaponSold($x->getWeaponTypeID());
410
		}
411
		if (is_array($x)) {
412
			if ($x['Type'] == 'Ship') { // instanceof Ship)
413
				return $this->isShipSold($x['ShipTypeID']);
414
			}
415
			if ($x['Type'] == 'Hardware') { // instanceof ShipEquipment)
416
				return $this->isHardwareSold($x['ID']);
417
			}
418
		}
419
		if (is_string($x)) {
420
			if ($x == 'Bank') {
421
				return $this->isBank();
422
			}
423
			if ($x == 'Bar') {
424
				return $this->isBar();
425
			}
426
			if ($x == 'Fed') {
427
				return $this->isFed();
428
			}
429
			if ($x == 'SafeFed') {
430
				return $player != null && $this->isFed() && $player->canBeProtectedByRace($this->getRaceID());
431
			}
432
			if ($x == 'HQ') {
433
				return $this->isHQ();
434
			}
435
			if ($x == 'UG') {
436
				return $this->isUG();
437
			}
438
			if ($x == 'Hardware') {
439
				return $this->isHardwareSold();
440
			}
441
			if ($x == 'Ship') {
442
				return $this->isShipSold();
443
			}
444
			if ($x == 'Weapon') {
445
				return $this->isWeaponSold();
446
			}
447
		}
448
		return false;
449
	}
450
}
451