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

EditGalaxiesProcessor::build()   F
last analyzed

Complexity

Conditions 39
Paths > 20000

Size

Total Lines 204
Code Lines 110

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 39
eloc 110
nc 5515776
nop 1
dl 0
loc 204
rs 0
c 2
b 0
f 0

How to fix   Long Method    Complexity   

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 declare(strict_types=1);
2
3
namespace Smr\Pages\Admin\UniGen;
4
5
use Exception;
6
use Smr\Database;
7
use Smr\Page\AccountPageProcessor;
8
use Smr\Request;
9
use SmrAccount;
10
use SmrGalaxy;
11
use SmrGame;
12
use SmrLocation;
13
use SmrPlanet;
14
use SmrPort;
15
use SmrSector;
16
17
class EditGalaxiesProcessor extends AccountPageProcessor {
18
19
	public function __construct(
20
		private readonly int $gameID,
21
		private readonly int $galaxyID
22
	) {}
23
24
	public function build(SmrAccount $account): never {
25
		$db = Database::getInstance();
26
27
		$gameID = $this->gameID;
28
		$game = SmrGame::getGame($gameID);
29
		$galaxies = $game->getGalaxies();
30
31
		// Save the original sizes for later processing
32
		$origGals = [];
33
		foreach ($galaxies as $i => $galaxy) {
34
			$origGals[$i] = [
35
				'Width' => $galaxy->getWidth(),
36
				'Height' => $galaxy->getHeight(),
37
			];
38
		}
39
40
		// Modify the galaxy properties
41
		foreach ($galaxies as $i => $galaxy) {
42
			$galaxy->setName(Request::get('gal' . $i));
43
			$galaxy->setGalaxyType(Request::get('type' . $i));
44
			$galaxy->setMaxForceTime(IFloor(Request::getFloat('forces' . $i) * 3600));
0 ignored issues
show
Bug introduced by
The function IFloor was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

44
			$galaxy->setMaxForceTime(/** @scrutinizer ignore-call */ IFloor(Request::getFloat('forces' . $i) * 3600));
Loading history...
45
			if (!$game->isEnabled()) {
46
				$galaxy->setWidth(Request::getInt('width' . $i));
47
				$galaxy->setHeight(Request::getInt('height' . $i));
48
			}
49
		}
50
51
		// Early return if no galaxy dimensions are modified
52
		$galaxySizesUnchanged = true;
53
		foreach ($galaxies as $i => $galaxy) {
54
			if ($galaxy->getWidth() != $origGals[$i]['Width'] || $galaxy->getHeight() != $origGals[$i]['Height']) {
55
				$galaxySizesUnchanged = false;
56
				break;
57
			}
58
		}
59
		if ($galaxySizesUnchanged) {
60
			SmrGalaxy::saveGalaxies();
61
			$message = '<span class="green">SUCCESS: </span>Edited galaxies (sizes unchanged).';
62
			$container = new EditGalaxy($this->gameID, $this->galaxyID, $message);
63
			$container->go();
64
		}
65
66
		// *** BEGIN GALAXY DIMENSION MODIFICATION! ***
67
		// Warning: This changes primary keys for several tables, which needs to be
68
		// done carefully. It also interacts with the caches in unexpected ways.
69
		// *** BEGIN GALAXY DIMENSION MODIFICATION! ***
70
71
		// Efficiently construct the caches before proceeding
72
		// NOTE: these will be associated with the old sector IDs, so the caches
73
		// will need to be cleared afterwards.
74
		foreach ($galaxies as $galaxy) {
75
			$galaxy->getSectors();
76
			$galaxy->getPorts();
77
			$galaxy->getLocations();
78
			$galaxy->getPlanets();
79
		}
80
81
		// Determine the mapping from old to new sector IDs
82
		$newID = 0;
83
		$oldID = 0;
84
		$sectorMap = [];
85
		foreach ($galaxies as $i => $galaxy) {
86
			$maxRows = max($galaxy->getHeight(), $origGals[$i]['Height']);
87
			$maxCols = max($galaxy->getWidth(), $origGals[$i]['Width']);
88
			for ($row = 0; $row < $maxRows; $row++) {
89
				for ($col = 0; $col < $maxCols; $col++) {
90
					$oldExists = ($row < $origGals[$i]['Height'] && $col < $origGals[$i]['Width']);
91
					$newExists = ($row < $galaxy->getHeight() && $col < $galaxy->getWidth());
92
93
					if ($oldExists && $newExists) {
94
						$oldID++;
95
						$newID++;
96
						$sectorMap[$newID] = $oldID;
97
					} elseif ($newExists) {
98
						$newID++;
99
						$sectorMap[$newID] = false;
100
					} elseif ($oldExists) {
101
						$oldID++;
102
						// Remove this sector and everything in it
103
						$delSector = SmrSector::getSector($gameID, $oldID);
104
						$delSector->removeAllFixtures();
105
						$db->write('DELETE FROM sector WHERE ' . $delSector->getSQL());
106
					}
107
				}
108
			}
109
		}
110
111
		// Save remaining old warps to re-add later, then clear all warp data.
112
		// This is necessary because we will be manually modifying sector IDs.
113
		$oldWarps = [];
114
		foreach ($galaxies as $galaxy) {
115
			foreach ($galaxy->getSectors() as $galSector) {
116
				if ($galSector->hasWarp()) {
117
					$oldWarps[$galSector->getSectorID()] = $galSector->getWarp();
118
				}
119
			}
120
		}
121
		$db->write('UPDATE sector SET warp = 0 WHERE game_id = ' . $db->escapeNumber($gameID));
122
123
		// Many sectors will have their IDs shifted up or down, so we need to modify
124
		// the primary keys for the sector table as well as planets, ports, etc.
125
		// We have to do this in a loop to ensure that the new sector ID will not
126
		// collide with an old sector ID that hasn't been shifted yet (because we
127
		// may be both adding and removing sectors).
128
		//
129
		// NOTE: We have already accounted for collisions from removing sectors by
130
		// deleting all fixtures from sectors that will no longer exist.
131
		$needsUpdate = $sectorMap;
132
		while ($needsUpdate) {
133
			foreach ($needsUpdate as $newID => $oldID) {
134
				// If sector is new or has the same ID, then no shifting is necessary
135
				if ($oldID === false || $oldID == $newID) {
136
					unset($needsUpdate[$newID]);
137
					continue;
138
				}
139
140
				// If the oldID still exists, then we have to defer shifting until
141
				// this destination has been vacated.
142
				if (array_search($newID, $needsUpdate)) {
143
					continue;
144
				}
145
146
				// Else we are ready to shift from oldID to newID
147
				$oldSector = SmrSector::getSector($gameID, $oldID);
148
				$SQL = 'SET sector_id = ' . $db->escapeNumber($newID) . ' WHERE ' . $oldSector->getSQL();
149
150
				if ($oldSector->hasPlanet()) {
151
					$db->write('UPDATE planet ' . $SQL);
152
					$db->write('UPDATE planet_has_building ' . $SQL);
153
					$db->write('UPDATE planet_has_cargo ' . $SQL);
154
					$db->write('UPDATE planet_has_weapon ' . $SQL);
155
				}
156
157
				if ($oldSector->hasPort()) {
158
					$db->write('UPDATE port ' . $SQL);
159
					$db->write('UPDATE port_has_goods ' . $SQL);
160
				}
161
162
				if ($oldSector->hasLocation()) {
163
					$db->write('UPDATE location ' . $SQL);
164
				}
165
166
				$db->write('UPDATE sector ' . $SQL);
167
				unset($needsUpdate[$newID]);
168
			}
169
		}
170
171
		// Clear all the caches, since they are associated with the old IDs.
172
		// NOTE: We can't re-initialize the cache here because the sectors
173
		// still have the wrong galaxy ID at this point.
174
		SmrSector::clearCache();
175
		SmrPort::clearCache();
176
		SmrPlanet::clearCache();
177
		SmrLocation::clearCache();
178
179
		// Create any new sectors that need to be made
180
		foreach ($sectorMap as $newID => $oldID) {
181
			if ($oldID === false) {
182
				SmrSector::createSector($gameID, $newID);
183
			}
184
		}
185
186
		// Finally, modify sector properties (galaxy ID, links, and warps)
187
		foreach ($sectorMap as $newID => $oldID) {
188
			$newSector = SmrSector::getSector($gameID, $newID);
189
190
			// Update the galaxy ID
191
			// NOTE: this must be done before SmrGalaxy::getSectors is called
192
			foreach ($galaxies as $galaxy) {
193
				if ($galaxy->contains($newID)) {
194
					$newSector->setGalaxyID($galaxy->getGalaxyID());
195
				}
196
			}
197
198
			// Update the sector connections
199
			foreach (['Up', 'Down', 'Left', 'Right'] as $dir) {
200
				if ($oldID === false) {
201
					// No sector walls for newly added sectors
202
					$newSector->enableLink($dir);
203
				} else {
204
					// Toggle links twice to reset them (since this internally handles
205
					// the calculation of the neighboring sector IDs).
206
					$newSector->toggleLink($dir);
207
					$newSector->toggleLink($dir);
208
				}
209
			}
210
211
			// Update the warp
212
			if ($oldID !== false && isset($oldWarps[$oldID])) {
213
				$oldWarpID = $oldWarps[$oldID];
214
				$newWarpID = array_search($oldWarpID, $sectorMap);
215
				if ($newWarpID === false) {
216
					throw new Exception('Warp sector unexpectedly missing from mapping: ' . $oldWarpID);
217
				}
218
				$newSector->setWarp(SmrSector::getSector($gameID, $newWarpID));
0 ignored issues
show
Bug introduced by
It seems like $newWarpID can also be of type string; however, parameter $sectorID of SmrSector::getSector() 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

218
				$newSector->setWarp(SmrSector::getSector($gameID, /** @scrutinizer ignore-type */ $newWarpID));
Loading history...
219
			}
220
		}
221
222
		SmrGalaxy::saveGalaxies();
223
		SmrSector::saveSectors();
224
225
		$message = '<span class="green">SUCCESS: </span>Edited galaxies (sizes have changed).';
226
		$container = new EditGalaxy($this->gameID, $this->galaxyID, $message);
227
		$container->go();
228
	}
229
230
}
231