MapRepository   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 1037
Duplicated Lines 0 %

Test Coverage

Coverage 32.61%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 773
dl 0
loc 1037
ccs 165
cts 506
cp 0.3261
rs 9.0269
c 2
b 1
f 0
wmc 40

32 Methods

Rating   Name   Duplication   Size   Complexity  
A getAllWithoutSystem() 0 19 1
A getAllOrdered() 0 19 1
A getByCoordinates() 0 11 2
A getAllWithSystem() 0 19 1
A getByBoundaries() 0 9 1
A save() 0 6 1
A getAmountByLayer() 0 5 1
A getRegionBorderData() 0 42 1
A getNormalBorderData() 0 22 1
A getUniqueInfluenceAreaIds() 0 21 1
A isAdminRegionUserRegion() 0 24 1
A getUserSpacecraftCountLayerData() 0 34 1
A getRandomPassableUnoccupiedWithoutDamage() 0 45 3
A getAllianceSpacecraftCountLayerData() 0 36 1
A getAnomalyData() 0 23 1
A getMapLayerData() 0 22 1
A getLssBlockadeLocations() 0 32 1
A getDynamicQueryConditions() 0 19 3
A getSpacecraftCountLayerDataForSpacecraft() 0 34 1
A getExplored() 0 50 1
B getShipSubspaceLayerData() 0 72 3
A getWithEmptySystem() 0 20 1
A getMapFieldsByRegion() 0 19 1
A getByCoordinateRange() 0 35 2
A getCartographingData() 0 31 1
A getSubspaceLayerData() 0 34 1
A getSpacecraftCountLayerData() 0 47 1
A getAllianceSubspaceLayerData() 0 44 1
A getIgnoringSubspaceLayerData() 0 52 1
A getUserSubspaceLayerData() 0 40 1
A getImpassableBorderData() 0 42 1
A getRandomMapIdsForAstroMeasurement() 0 39 1

How to fix   Complexity   

Complex Class

Complex classes like MapRepository 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 MapRepository, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Orm\Repository;
6
7
use Doctrine\ORM\EntityRepository;
8
use Doctrine\ORM\Query\ResultSetMapping;
9
use RuntimeException;
10
use Stu\Component\Ship\FlightSignatureVisibilityEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\FlightSignatureVisibilityEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
12
use Stu\Lib\Map\VisualPanel\PanelBoundaries;
13
use Stu\Module\PlayerSetting\Lib\UserSettingEnum;
14
use Stu\Module\Starmap\Lib\ExploreableStarMap;
15
use Stu\Orm\Entity\Layer;
16
use Stu\Orm\Entity\Location;
17
use Stu\Orm\Entity\Map;
18
use Stu\Orm\Entity\MapRegionSettlement;
19
use Stu\Orm\Entity\StarSystemMap;
20
use Stu\Orm\Entity\User;
21
22
/**
23
 * @extends EntityRepository<Map>
24
 */
25
final class MapRepository extends EntityRepository implements MapRepositoryInterface
26
{
27 1
    #[\Override]
28
    public function getAmountByLayer(Layer $layer): int
29
    {
30 1
        return $this->count([
31 1
            'layer' => $layer
32 1
        ]);
33
    }
34
35
    #[\Override]
36
    public function getAllOrdered(Layer $layer): array
37
    {
38
        return $this->getEntityManager()
39
            ->createQuery(
40
                sprintf(
41
                    'SELECT m FROM %s m
42
                    JOIN %s l
43
                    WITH m.id = l.id
44
                    WHERE l.layer = :layer
45
                    ORDER BY l.cy, l.cx',
46
                    Map::class,
47
                    Location::class
48
                )
49
            )
50
            ->setParameters([
51
                'layer' => $layer
52
            ])
53
            ->getResult();
54
    }
55
56
    #[\Override]
57
    public function getAllWithSystem(Layer $layer): array
58
    {
59
        return $this->getEntityManager()
60
            ->createQuery(
61
                sprintf(
62
                    'SELECT m FROM %s m INDEX BY m.id
63
                    JOIN %s l
64
                    WITH m.id = l.id
65
                    WHERE l.layer = :layer
66
                    AND m.systems_id IS NOT null',
67
                    Map::class,
68
                    Location::class
69
                )
70
            )
71
            ->setParameters([
72
                'layer' => $layer
73
            ])
74
            ->getResult();
75
    }
76
77
    #[\Override]
78
    public function getAllWithoutSystem(Layer $layer): array
79
    {
80
        return $this->getEntityManager()
81
            ->createQuery(
82
                sprintf(
83
                    'SELECT m FROM %s m INDEX BY m.id
84
                    JOIN %s l
85
                    WITH m.id = l.id
86
                    WHERE l.layer = :layer
87
                    AND m.systems_id IS null',
88
                    Map::class,
89
                    Location::class
90
                )
91
            )
92
            ->setParameters([
93
                'layer' => $layer
94
            ])
95
            ->getResult();
96
    }
97
98 6
    #[\Override]
99
    public function getByCoordinates(?Layer $layer, int $cx, int $cy): ?Map
100
    {
101 6
        if ($layer === null) {
102
            return null;
103
        }
104
105 6
        return $this->findOneBy([
106 6
            'layer' => $layer,
107 6
            'cx' => $cx,
108 6
            'cy' => $cy
109 6
        ]);
110
    }
111
112
    #[\Override]
113
    public function getByBoundaries(PanelBoundaries $boundaries): array
114
    {
115
        return $this->getByCoordinateRange(
116
            $boundaries->getParentId(),
117
            $boundaries->getMinX(),
118
            $boundaries->getMaxX(),
119
            $boundaries->getMinY(),
120
            $boundaries->getMaxY()
121
        );
122
    }
123
124 3
    #[\Override]
125
    public function getByCoordinateRange(
126
        int $layerId,
127
        int $startCx,
128
        int $endCx,
129
        int $startCy,
130
        int $endCy,
131
        bool $sortAscending = true
132
    ): array {
133 3
        return $this->getEntityManager()
134 3
            ->createQuery(
135 3
                sprintf(
136 3
                    'SELECT m FROM %s m
137
                    JOIN %s l
138
                    WITH m.id = l.id
139
                    JOIN %s ly
140
                    WITH l.layer = ly
141
                    WHERE l.cx BETWEEN :startCx AND :endCx
142
                    AND l.cy BETWEEN :startCy AND :endCy
143
                    AND ly.id = :layerId
144 3
                    ORDER BY l.cy %4$s, l.cx %4$s',
145 3
                    Map::class,
146 3
                    Location::class,
147 3
                    Layer::class,
148 3
                    $sortAscending ? 'ASC' : 'DESC'
149 3
                )
150 3
            )
151 3
            ->setParameters([
152 3
                'layerId' => $layerId,
153 3
                'startCx' => $startCx,
154 3
                'endCx' => $endCx,
155 3
                'startCy' => $startCy,
156 3
                'endCy' => $endCy
157 3
            ])
158 3
            ->getResult();
159
    }
160
161
    #[\Override]
162
    public function save(Map $map): void
163
    {
164
        $em = $this->getEntityManager();
165
166
        $em->persist($map);
167
    }
168
169 1
    #[\Override]
170
    public function getNormalBorderData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
171
    {
172 1
        return $this->getEntityManager()
173 1
            ->createNativeQuery(
174 1
                'SELECT l.cx AS x, l.cy AS y
175
            FROM stu_map m
176
            JOIN stu_location l
177
            ON m.id = l.id
178
            WHERE l.cx BETWEEN :xStart AND :xEnd
179
            AND l.cy BETWEEN :yStart AND :yEnd
180 1
            AND l.layer_id = :layerId',
181 1
                $rsm
182 1
            )
183 1
            ->setParameters([
184 1
                'xStart' => $boundaries->getMinX(),
185 1
                'xEnd' => $boundaries->getMaxX(),
186 1
                'yStart' => $boundaries->getMinY(),
187 1
                'yEnd' => $boundaries->getMaxY(),
188 1
                'layerId' => $boundaries->getParentId()
189 1
            ])
190 1
            ->getResult();
191
    }
192
193
    #[\Override]
194
    public function getCartographingData(
195
        PanelBoundaries $boundaries,
196
        ResultSetMapping $rsm,
197
        array $locations
198
    ): array {
199
        return $this->getEntityManager()
200
            ->createNativeQuery(
201
            'SELECT DISTINCT
202
                    l.cx AS x,
203
                    l.cy AS y,
204
                    CASE
205
                        WHEN l.id IN (:fieldIds) THEN TRUE ELSE FALSE
206
                    END AS cartographing,
207
                    (SELECT mft.complementary_color FROM stu_map_ftypes mft where mft.id = l.field_id) AS complementary_color
208
                FROM stu_location l
209
                WHERE l.cx BETWEEN :xStart AND :xEnd
210
                AND l.cy BETWEEN :yStart AND :yEnd
211
                AND l.layer_id = :layerId
212
                ORDER BY cartographing DESC',
213
                $rsm
214
            )
215
            ->setParameters([
216
                'xStart' => $boundaries->getMinX(),
217
                'xEnd' => $boundaries->getMaxX(),
218
                'yStart' => $boundaries->getMinY(),
219
                'yEnd' => $boundaries->getMaxY(),
220
                'layerId' => $boundaries->getParentId(),
221
                'fieldIds' => $locations
222
            ])
223
            ->getResult();
224
    }
225
226
    #[\Override]
227
    public function getRegionBorderData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
228
    {
229
        return $this->getEntityManager()
230
            ->createNativeQuery(
231
                'SELECT l.cx AS x, l.cy AS y,
232
                (SELECT al.rgb_code FROM stu_alliances al
233
                    JOIN stu_user u ON al.id = u.allys_id
234
                    JOIN stu_spacecraft sc ON u.id = sc.user_id
235
                    JOIN stu_station s ON sc.id = s.id
236
                    JOIN stu_map ma ON ma.influence_area_id = s.influence_area_id
237
                    WHERE ma.id = m.id AND ma.bordertype_id IS NULL AND ma.admin_region_id IS NULL)
238
                            AS allycolor,
239
                (SELECT COALESCE(us.value, \'\') FROM stu_user u
240
                    LEFT JOIN stu_user_setting us ON u.id = us.user_id
241
                    JOIN stu_spacecraft sc ON u.id = sc.user_id
242
                    JOIN stu_station s ON sc.id = s.id
243
                    JOIN stu_map mu ON mu.influence_area_id = s.influence_area_id
244
                    WHERE us.setting = :rgbCodeSetting
245
                    AND mu.id = m.id AND mu.bordertype_id IS NULL AND mu.admin_region_id IS NULL)
246
                        as usercolor,
247
                (SELECT mbt.color FROM stu_map_bordertypes mbt
248
                    JOIN stu_map mb ON mb.bordertype_id = mbt.id
249
                    WHERE mb.id = m.id AND mb.bordertype_id IS NOT NULL)
250
                        AS factioncolor
251
            FROM stu_map m
252
            JOIN stu_location l
253
            ON m.id = l.id
254
            WHERE l.cx BETWEEN :xStart AND :xEnd
255
            AND l.cy BETWEEN :yStart AND :yEnd
256
            AND l.layer_id = :layerId',
257
                $rsm
258
            )
259
            ->setParameters([
260
                'xStart' => $boundaries->getMinX(),
261
                'xEnd' => $boundaries->getMaxX(),
262
                'yStart' => $boundaries->getMinY(),
263
                'yEnd' => $boundaries->getMaxY(),
264
                'layerId' => $boundaries->getParentId(),
265
                'rgbCodeSetting' => UserSettingEnum::RGB_CODE->value
266
            ])
267
            ->getResult();
268
    }
269
270
    #[\Override]
271
    public function getImpassableBorderData(
272
        PanelBoundaries $boundaries,
273
        User $user,
274
        ResultSetMapping $rsm
275
    ): array {
276
        return $this->getEntityManager()
277
            ->createNativeQuery(
278
            'SELECT DISTINCT
279
                l.cx AS x,
280
                l.cy AS y,
281
                CASE
282
                    WHEN mf.passable = FALSE
283
                         AND EXISTS (
284
                            SELECT 1
285
                            FROM stu_database_user du
286
                            JOIN stu_database_entrys de ON du.database_id = de.id
287
                            WHERE du.user_id = :userId
288
                            AND de.id = r.database_id
289
                         )
290
                    THEN FALSE
291
                    ELSE TRUE
292
                END AS impassable,
293
                    (SELECT mft.complementary_color FROM stu_map_ftypes mft where mft.id = l.field_id) AS complementary_color
294
            FROM stu_location l
295
            LEFT JOIN stu_map_ftypes mf ON l.field_id = mf.id
296
            LEFT JOIN stu_map m ON l.id = m.id
297
            LEFT JOIN stu_map_regions r ON m.region_id = r.id
298
            WHERE l.cx BETWEEN :xStart AND :xEnd
299
              AND l.cy BETWEEN :yStart AND :yEnd
300
              AND l.layer_id = :layerId',
301
                $rsm
302
            )
303
            ->setParameters([
304
                'xStart' => $boundaries->getMinX(),
305
                'xEnd' => $boundaries->getMaxX(),
306
                'yStart' => $boundaries->getMinY(),
307
                'yEnd' => $boundaries->getMaxY(),
308
                'layerId' => $boundaries->getParentId(),
309
                'userId' => $user->getId()
310
            ])
311
            ->getResult();
312
    }
313
314
    #[\Override]
315
    public function getAnomalyData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
316
    {
317
        return $this->getEntityManager()
318
            ->createNativeQuery(
319
                'SELECT l.cx AS x, l.cy AS y,
320
                (SELECT array_to_string(array(SELECT a.anomaly_type_id FROM stu_anomaly a WHERE a.location_id = m.id), \',\')) as anomalytypes
321
            FROM stu_map m
322
            JOIN stu_location l
323
            ON m.id = l.id
324
            WHERE l.cx BETWEEN :xStart AND :xEnd
325
            AND l.cy BETWEEN :yStart AND :yEnd
326
            AND l.layer_id = :layerId',
327
                $rsm
328
            )
329
            ->setParameters([
330
                'xStart' => $boundaries->getMinX(),
331
                'xEnd' => $boundaries->getMaxX(),
332
                'yStart' => $boundaries->getMinY(),
333
                'yEnd' => $boundaries->getMaxY(),
334
                'layerId' => $boundaries->getParentId()
335
            ])
336
            ->getResult();
337
    }
338
339 1
    #[\Override]
340
    public function getLssBlockadeLocations(PanelBoundaries $boundaries): array
341
    {
342 1
        $rsm = new ResultSetMapping();
343 1
        $rsm->addScalarResult('cx', 'x', 'integer');
344 1
        $rsm->addScalarResult('cy', 'y', 'integer');
345 1
        $rsm->addScalarResult('effects', 'effects', 'string');
346
347 1
        return $this->getEntityManager()
348 1
            ->createNativeQuery(
349 1
                'WITH bbox AS (
350
                SELECT id, field_id, cx, cy
351
                FROM stu_location
352
                WHERE layer_id = :layerId
353
                AND  cx BETWEEN :xStart AND :xEnd
354
                AND  cy BETWEEN :yStart AND :yEnd
355
                and discr = \'map\'
356
            )
357
            SELECT  l.cx, l.cy, mft.effects
358
            FROM bbox l
359
            JOIN stu_map_ftypes mft ON mft.id = l.field_id
360 1
            JOIN stu_map m ON m.id = l.id',
361 1
                $rsm
362 1
            )
363 1
            ->setParameters([
364 1
                'xStart' => $boundaries->getMinX(),
365 1
                'xEnd' => $boundaries->getMaxX(),
366 1
                'yStart' => $boundaries->getMinY(),
367 1
                'yEnd' => $boundaries->getMaxY(),
368 1
                'layerId' => $boundaries->getParentId()
369 1
            ])
370 1
            ->getResult();
371
    }
372
373 1
    #[\Override]
374
    public function getSpacecraftCountLayerData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
375
    {
376 1
        return $this->getEntityManager()
377 1
            ->createNativeQuery(
378 1
            'SELECT l.cx as x, l.cy AS y, mft.effects as effects,
379
                (SELECT count(DISTINCT b.id) FROM stu_spacecraft b
380
                    JOIN stu_location l2
381
                    ON b.location_id = l2.id
382
                    WHERE l2.layer_id = l.layer_id
383
                    AND l2.cx = l.cx
384
                    AND l2.cy = l.cy
385
                    AND NOT EXISTS (SELECT ss.id
386
                                        FROM stu_spacecraft_system ss
387
                                        WHERE b.id = ss.spacecraft_id
388
                                        AND ss.system_type = :cloakSystemId
389
                                        AND ss.mode > 1)) AS spacecraftcount,
390
                (SELECT count(DISTINCT c.id) FROM stu_spacecraft c
391
                    JOIN stu_location l2
392
                    ON c.location_id = l2.id
393
                    WHERE l2.layer_id = l.layer_id
394
                    AND l2.cx = l.cx
395
                    AND l2.cy = l.cy
396
                    AND EXISTS (SELECT ss2.id
397
                                        FROM stu_spacecraft_system ss2
398
                                        WHERE c.id = ss2.spacecraft_id
399
                                        AND ss2.system_type = :cloakSystemId
400
                                        AND ss2.mode > 1)) AS cloakcount
401
            FROM stu_map m
402
            JOIN stu_location l
403
            ON m.id = l.id
404
            JOIN stu_map_ftypes mft
405
            ON l.field_id = mft.id
406
            WHERE l.cx BETWEEN :xStart AND :xEnd
407
            AND l.cy BETWEEN :yStart AND :yEnd
408 1
            AND l.layer_id = :layerId',
409 1
                $rsm
410 1
            )
411 1
            ->setParameters([
412 1
                'xStart' => $boundaries->getMinX(),
413 1
                'xEnd' => $boundaries->getMaxX(),
414 1
                'yStart' => $boundaries->getMinY(),
415 1
                'yEnd' => $boundaries->getMaxY(),
416 1
                'layerId' => $boundaries->getParentId(),
417 1
                'cloakSystemId' => SpacecraftSystemTypeEnum::CLOAK->value
418 1
            ])
419 1
            ->getResult();
420
    }
421
422 1
    #[\Override]
423
    public function getMapLayerData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
424
    {
425 1
        return $this->getEntityManager()
426 1
            ->createNativeQuery(
427 1
                'SELECT l.cx as x, l.cy AS y, ft.type
428
                FROM stu_map m
429
                JOIN stu_location l
430
                ON m.id = l.id
431
                JOIN stu_map_ftypes ft ON ft.id = l.field_id
432
                WHERE l.cx BETWEEN :xStart AND :xEnd AND l.cy BETWEEN :yStart AND :yEnd
433 1
                AND l.layer_id = :layerId',
434 1
                $rsm
435 1
            )
436 1
            ->setParameters([
437 1
                'xStart' => $boundaries->getMinX(),
438 1
                'xEnd' => $boundaries->getMaxX(),
439 1
                'yStart' => $boundaries->getMinY(),
440 1
                'yEnd' => $boundaries->getMaxY(),
441 1
                'layerId' => $boundaries->getParentId()
442 1
            ])
443 1
            ->getResult();
444
    }
445
446
    #[\Override]
447
    public function getUserSpacecraftCountLayerData(
448
        PanelBoundaries $boundaries,
449
        int $userId,
450
        ResultSetMapping $rsm
451
    ): array {
452
        return $this->getEntityManager()
453
            ->createNativeQuery(
454
                'SELECT l.cx as x, l.cy as y,
455
            (SELECT count(distinct s.id)
456
                FROM stu_spacecraft s
457
                JOIN stu_location spl
458
                ON s.location_id = spl.id
459
                WHERE spl.cx = l.cx
460
                AND spl.cy = l.cy
461
                AND spl.layer_id = l.layer_id
462
                AND s.user_id = :userId) as spacecraftcount
463
            FROM stu_map m
464
            JOIN stu_location l
465
            ON m.id = l.id
466
            WHERE l.cx BETWEEN :xStart AND :xEnd
467
            AND l.cy BETWEEN :yStart AND :yEnd
468
            AND l.layer_id = :layerId',
469
                $rsm
470
            )
471
            ->setParameters([
472
                'xStart' => $boundaries->getMinX(),
473
                'xEnd' => $boundaries->getMaxX(),
474
                'yStart' => $boundaries->getMinY(),
475
                'yEnd' => $boundaries->getMaxY(),
476
                'layerId' => $boundaries->getParentId(),
477
                'userId' => $userId
478
            ])
479
            ->getResult();
480
    }
481
482
    #[\Override]
483
    public function getAllianceSpacecraftCountLayerData(
484
        PanelBoundaries $boundaries,
485
        int $allianceId,
486
        ResultSetMapping $rsm
487
    ): array {
488
        return $this->getEntityManager()
489
            ->createNativeQuery(
490
                'SELECT l.cx as x, l.cy as y,
491
             (SELECT count(distinct s.id)
492
                    FROM stu_spacecraft s
493
                    JOIN stu_location spl
494
                    ON s.location_id = spl.id
495
                    JOIN stu_user u
496
                    ON s.user_id = u.id
497
                    WHERE spl.cx = l.cx
498
                    AND spl.cy = l.cy
499
                    AND spl.layer_id = l.layer_id
500
                    AND u.allys_id = :allyId) as spacecraftcount
501
            FROM stu_map m
502
            JOIN stu_location l
503
            ON m.id = l.id
504
            WHERE l.cx BETWEEN :xStart AND :xEnd
505
            AND l.cy BETWEEN :yStart AND :yEnd
506
            AND l.layer_id = :layerId',
507
                $rsm
508
            )
509
            ->setParameters([
510
                'xStart' => $boundaries->getMinX(),
511
                'xEnd' => $boundaries->getMaxX(),
512
                'yStart' => $boundaries->getMinY(),
513
                'yEnd' => $boundaries->getMaxY(),
514
                'layerId' => $boundaries->getParentId(),
515
                'allyId' => $allianceId
516
            ])
517
            ->getResult();
518
    }
519
520
    #[\Override]
521
    public function getSpacecraftCountLayerDataForSpacecraft(
522
        PanelBoundaries $boundaries,
523
        int $spacecraftId,
524
        ResultSetMapping $rsm
525
    ): array {
526
        return $this->getEntityManager()
527
            ->createNativeQuery(
528
                'SELECT l.cx as x, l.cy as y,
529
            (SELECT count(distinct s.id)
530
                FROM stu_spacecraft s
531
                JOIN stu_location spl
532
                ON s.location_id = spl.id
533
                WHERE spl.cx = l.cx
534
                AND spl.cy = l.cy
535
                AND spl.layer_id = l.layer_id
536
                AND s.id = :spacecraftId) as spacecraftcount
537
            FROM stu_map m
538
            JOIN stu_location l
539
            ON m.id = l.id
540
            WHERE l.cx BETWEEN :xStart AND :xEnd
541
            AND l.cy BETWEEN :yStart AND :yEnd
542
            AND l.layer_id = :layerId',
543
                $rsm
544
            )
545
            ->setParameters([
546
                'xStart' => $boundaries->getMinX(),
547
                'xEnd' => $boundaries->getMaxX(),
548
                'yStart' => $boundaries->getMinY(),
549
                'yEnd' => $boundaries->getMaxY(),
550
                'layerId' => $boundaries->getParentId(),
551
                'spacecraftId' => $spacecraftId
552
            ])
553
            ->getResult();
554
    }
555
556 3
    #[\Override]
557
    public function getExplored(int $userId, int $layerId, int $startX, int $endX, int $cy): array
558
    {
559 3
        $rsm = new ResultSetMapping();
560 3
        $rsm->addEntityResult(ExploreableStarMap::class, 'm');
561 3
        $rsm->addFieldResult('m', 'id', 'id');
562 3
        $rsm->addFieldResult('m', 'cx', 'cx');
563 3
        $rsm->addFieldResult('m', 'cy', 'cy');
564 3
        $rsm->addFieldResult('m', 'field_id', 'field_id');
565 3
        $rsm->addFieldResult('m', 'bordertype_id', 'bordertype_id');
566 3
        $rsm->addFieldResult('m', 'user_id', 'user_id');
567 3
        $rsm->addFieldResult('m', 'mapped', 'mapped');
568 3
        $rsm->addFieldResult('m', 'system_name', 'system_name');
569 3
        $rsm->addFieldResult('m', 'influence_area_id', 'influence_area_id');
570 3
        $rsm->addFieldResult('m', 'region_id', 'region_id');
571 3
        $rsm->addFieldResult('m', 'tradepost_id', 'tradepost_id');
572 3
        $rsm->addFieldResult('m', 'region_description', 'region_description');
573 3
        $rsm->addFieldResult('m', 'layer_id', 'layer_id');
574
575 3
        return $this->getEntityManager()
576 3
            ->createNativeQuery(
577 3
                'SELECT m.id, l.cx, l.cy, l.field_id, m.systems_id, m.bordertype_id, um.user_id,
578
                    dbu.database_id as mapped, m.influence_area_id as influence_area_id, m.admin_region_id as region_id,
579
                    sys.name as system_name, l.layer_id,
580
                    (SELECT tp.id FROM stu_spacecraft s JOIN stu_trade_posts tp ON s.id = tp.station_id WHERE s.location_id = m.id) as tradepost_id,
581
                    (SELECT mr.description FROM stu_map_regions mr JOIN stu_database_user dbu on dbu.user_id = :userId and mr.database_id = dbu.database_id WHERE m.region_id = mr.id) as region_description
582
                FROM stu_map m
583
                JOIN stu_location l
584
                ON m.id = l.id
585
                LEFT JOIN stu_user_map um
586
                    ON um.cx = l.cx AND um.cy = l.cy AND um.user_id = :userId AND um.layer_id = l.layer_id
587
                LEFT JOIN stu_systems sys
588
                    ON m.systems_id = sys.id
589
                LEFT JOIN stu_database_user dbu
590
                    ON dbu.user_id = :userId
591
                    AND sys.database_id = dbu.database_id
592
                WHERE l.cx BETWEEN :startX AND :endX
593
                AND l.cy = :cy
594
                AND l.layer_id = :layerId
595 3
                ORDER BY l.cx ASC',
596 3
                $rsm
597 3
            )
598 3
            ->setParameters([
599 3
                'layerId' => $layerId,
600 3
                'userId' => $userId,
601 3
                'startX' => $startX,
602 3
                'endX' => $endX,
603 3
                'cy' => $cy
604 3
            ])
605 3
            ->getResult();
606
    }
607
608
    #[\Override]
609
    public function getWithEmptySystem(Layer $layer): array
610
    {
611
        return $this->getEntityManager()
612
            ->createQuery(
613
                sprintf(
614
                    'SELECT m from %s m
615
                    JOIN %s l
616
                    WITH m.id = l.id
617
                    WHERE m.system_type_id IS NOT NULL
618
                    AND m.systems_id IS NULL
619
                    AND l.layer = :layer',
620
                    Map::class,
621
                    Location::class
622
                )
623
            )
624
            ->setParameters([
625
                'layer' => $layer
626
            ])
627
            ->getResult();
628
    }
629
630
    #[\Override]
631
    public function getRandomMapIdsForAstroMeasurement(
632
        int $regionId,
633
        int $maxPercentage,
634
        int $location
635
    ): array {
636
        $rsm = new ResultSetMapping();
637
        $rsm->addScalarResult('id', 'id', 'integer');
638
639
        $mapIdResultSet = $this->getEntityManager()
640
            ->createNativeQuery(
641
                "SELECT m.id
642
                FROM stu_map m
643
                JOIN stu_location l ON m.id = l.id
644
                JOIN stu_map_ftypes mf ON l.field_id = mf.id
645
                WHERE m.region_id = :regionId
646
                AND
647
                    mf.passable = :true
648
                    AND NOT EXISTS (
649
                        SELECT 1
650
                        FROM jsonb_array_elements_text(mf.effects::jsonb) AS elem
651
                        WHERE elem = 'NO_MEASUREPOINT'
652
                    
653
                )
654
                AND m.id != :loc
655
                ORDER BY RANDOM()",
656
                $rsm
657
            )
658
            ->setParameters([
659
                'regionId' => $regionId,
660
                'loc' => $location,
661
                'true' => true
662
            ])
663
            ->getResult();
664
665
        $amount = (int) ceil((count($mapIdResultSet) * $maxPercentage) / 100);
666
        $subset = array_slice($mapIdResultSet, 0, $amount);
667
668
        return array_map(fn(array $data) => $data['id'], $subset);
669
    }
670
671 3
    #[\Override]
672
    public function getRandomPassableUnoccupiedWithoutDamage(Layer $layer, bool $isAtBorder = false): Map
673
    {
674 3
        $rsm = new ResultSetMapping();
675 3
        $rsm->addScalarResult('id', 'id', 'integer');
676
677 3
        $borderCriteria = $isAtBorder
678 3
            ? sprintf(
679 3
                'AND (l.cx in (1, %d) OR l.cy in (1, %d))',
680 3
                $layer->getWidth(),
681 3
                $layer->getHeight()
682 3
            ) : '';
683
684 3
        $randomMapId = (int) $this->getEntityManager()
685 3
            ->createNativeQuery(
686 3
                sprintf(
687 3
                    'SELECT m.id
688
                    FROM stu_map m
689
                    JOIN stu_location l
690
                    ON m.id = l.id
691
                    JOIN stu_map_ftypes mft
692
                    ON l.field_id = mft.id
693
                    WHERE NOT EXISTS (SELECT s.id FROM stu_spacecraft s WHERE s.location_id = m.id)
694
                    AND l.layer_id = :layerId
695
                    AND mft.x_damage = 0
696
                    AND mft.passable = :true
697
                    %s
698
                    ORDER BY RANDOM()
699 3
                    LIMIT 1',
700 3
                    $borderCriteria
701 3
                ),
702 3
                $rsm
703 3
            )
704 3
            ->setParameters([
705 3
                'layerId' => $layer->getId(),
706 3
                'true' => true
707 3
            ])
708 3
            ->getSingleScalarResult();
709
710 3
        $map = $this->find($randomMapId);
711 3
        if ($map === null) {
712
            throw new RuntimeException('this should not happen');
713
        }
714
715 3
        return $map;
716
    }
717
718
    #[\Override]
719
    public function getIgnoringSubspaceLayerData(
720
        PanelBoundaries $boundaries,
721
        int $ignoreUserId,
722
        int $time,
723
        ResultSetMapping $rsm
724
    ): array {
725
        $maxAge = $time - FlightSignatureVisibilityEnum::SIG_VISIBILITY_UNCLOAKED;
726
727
        return $this->getEntityManager()
728
            ->createNativeQuery(
729
            'SELECT l.cx AS x, l.cy AS y, mft.effects as effects,
730
                (SELECT count(distinct fs1.ship_id) from stu_flight_sig fs1
731
                WHERE fs1.location_id = l.id
732
                AND fs1.user_id != :ignoreUserId
733
                AND (fs1.from_direction = 1 OR fs1.to_direction = 1)
734
                AND fs1.time > :timeThreshold) as d1c,
735
                (SELECT count(distinct fs2.ship_id) from stu_flight_sig fs2
736
                WHERE fs2.location_id = l.id
737
                AND fs2.user_id !=:ignoreUserId
738
                AND (fs2.from_direction = 2 OR fs2.to_direction = 2)
739
                AND fs2.time > :timeThreshold) as d2c,
740
                (SELECT count(distinct fs3.ship_id) from stu_flight_sig fs3
741
                WHERE fs3.location_id = l.id
742
                AND fs3.user_id != :ignoreUserId
743
                AND (fs3.from_direction = 3 OR fs3.to_direction = 3)
744
                AND fs3.time > :timeThreshold) as d3c,
745
                (SELECT count(distinct fs4.ship_id) from stu_flight_sig fs4
746
                WHERE fs4.location_id = l.id
747
                AND fs4.user_id != :ignoreUserId
748
                AND (fs4.from_direction = 4 OR fs4.to_direction = 4)
749
                AND fs4.time > :timeThreshold) as d4c
750
                FROM stu_location l
751
                JOIN stu_map m
752
                ON l.id = m.id
753
                JOIN stu_map_ftypes mft
754
                ON l.field_id = mft.id
755
                WHERE l.cx BETWEEN :xStart AND :xEnd
756
                AND l.cy BETWEEN :yStart AND :yEnd
757
                AND l.layer_id = :layerId',
758
                $rsm
759
            )
760
            ->setParameters([
761
                'xStart' => $boundaries->getMinX(),
762
                'xEnd' => $boundaries->getMaxX(),
763
                'yStart' => $boundaries->getMinY(),
764
                'yEnd' => $boundaries->getMaxY(),
765
                'layerId' => $boundaries->getParentId(),
766
                'ignoreUserId' => $ignoreUserId,
767
                'timeThreshold' => $maxAge
768
            ])
769
            ->getResult();
770
    }
771
772
    #[\Override]
773
    public function getSubspaceLayerData(PanelBoundaries $boundaries, ResultSetMapping $rsm): array
774
    {
775
        return $this->getEntityManager()
776
            ->createNativeQuery(
777
            'SELECT l.cx as x, l.cy as y, mft.effects as effects,
778
            (SELECT count(distinct fs1.ship_id) from stu_flight_sig fs1
779
                WHERE fs1.location_id = l.id
780
                AND (fs1.from_direction = 1 OR fs1.to_direction = 1)) as d1c,
781
            (SELECT count(distinct fs2.ship_id) from stu_flight_sig fs2
782
                WHERE fs2.location_id = l.id
783
                AND (fs2.from_direction = 2 OR fs2.to_direction = 2)) as d2c,
784
            (SELECT count(distinct fs3.ship_id) from stu_flight_sig fs3
785
                WHERE fs3.location_id = l.id
786
                AND (fs3.from_direction = 3 OR fs3.to_direction = 3)) as d3c,
787
            (SELECT count(distinct fs4.ship_id) from stu_flight_sig fs4
788
                WHERE fs4.location_id = l.id
789
                AND (fs4.from_direction = 4 OR fs4.to_direction = 4)) as d4c
790
            FROM stu_location l
791
            JOIN stu_map_ftypes mft
792
            ON l.field_id = mft.id
793
            WHERE l.cx BETWEEN :xStart AND :xEnd
794
            AND l.cy BETWEEN :yStart AND :yEnd
795
            AND l.layer_id = :layerId',
796
                $rsm
797
            )
798
            ->setParameters([
799
                'xStart' => $boundaries->getMinX(),
800
                'xEnd' => $boundaries->getMaxX(),
801
                'yStart' => $boundaries->getMinY(),
802
                'yEnd' => $boundaries->getMaxY(),
803
                'layerId' => $boundaries->getParentId()
804
            ])
805
            ->getResult();
806
    }
807
808
    #[\Override]
809
    public function getUserSubspaceLayerData(
810
        PanelBoundaries $boundaries,
811
        int $userId,
812
        ResultSetMapping $rsm
813
    ): array {
814
        return $this->getEntityManager()
815
            ->createNativeQuery(
816
            'SELECT l.cx as x, l.cy as y,
817
            (SELECT count(distinct fs1.ship_id) from stu_flight_sig fs1
818
                WHERE fs1.location_id = l.id
819
                AND fs1.user_id = :userId
820
                AND (fs1.from_direction = 1 OR fs1.to_direction = 1)) as d1c,
821
            (SELECT count(distinct fs2.ship_id) from stu_flight_sig fs2
822
                WHERE fs2.location_id = l.id
823
                AND fs2.user_id = :userId
824
                AND (fs2.from_direction = 2 OR fs2.to_direction = 2)) as d2c,
825
            (SELECT count(distinct fs3.ship_id) from stu_flight_sig fs3
826
                WHERE fs3.location_id = l.id
827
                AND fs3.user_id = :userId
828
                AND (fs3.from_direction = 3 OR fs3.to_direction = 3)) as d3c,
829
            (SELECT count(distinct fs4.ship_id) from stu_flight_sig fs4
830
                WHERE fs4.location_id = l.id
831
                AND fs4.user_id = :userId
832
                AND (fs4.from_direction = 4 OR fs4.to_direction = 4)) as d4c
833
            FROM stu_location l
834
            WHERE l.cx BETWEEN :xStart AND :xEnd
835
            AND l.cy BETWEEN :yStart AND :yEnd
836
            AND l.layer_id = :layerId',
837
                $rsm
838
            )
839
            ->setParameters([
840
                'xStart' => $boundaries->getMinX(),
841
                'xEnd' => $boundaries->getMaxX(),
842
                'yStart' => $boundaries->getMinY(),
843
                'yEnd' => $boundaries->getMaxY(),
844
                'layerId' => $boundaries->getParentId(),
845
                'userId' => $userId
846
            ])
847
            ->getResult();
848
    }
849
850
    /**
851
     * @return array<int, string>
852
     */
853
    private function getDynamicQueryConditions(bool $cloaked_check, ?int $rumpId): array
854
    {
855
        $conditions = ['', '', '', ''];
856
857
        if ($cloaked_check) {
858
            $conditions[0] = 'AND fs1.is_cloaked = :false';
859
            $conditions[1] = 'AND fs2.is_cloaked = :false';
860
            $conditions[2] = 'AND fs3.is_cloaked = :false';
861
            $conditions[3] = 'AND fs4.is_cloaked = :false';
862
        }
863
864
        if ($rumpId !== null) {
865
            $conditions[0] .= ' AND fs1.rump_id = :rumpId';
866
            $conditions[1] .= ' AND fs2.rump_id = :rumpId';
867
            $conditions[2] .= ' AND fs3.rump_id = :rumpId';
868
            $conditions[3] .= ' AND fs4.rump_id = :rumpId';
869
        }
870
871
        return $conditions;
872
    }
873
874
    #[\Override]
875
    public function getShipSubspaceLayerData(
876
        PanelBoundaries $boundaries,
877
        int $shipId,
878
        int $time,
879
        ResultSetMapping $rsm,
880
        bool $cloaked_check = false,
881
        ?int $rumpId = null
882
    ): array {
883
        $maxAge = $time - FlightSignatureVisibilityEnum::SIG_VISIBILITY_UNCLOAKED;
884
        $conditions = $this->getDynamicQueryConditions($cloaked_check, $rumpId);
885
886
        $query = $this->getEntityManager()->createNativeQuery(
887
            'SELECT l.cx as x, l.cy as y,
888
                (SELECT count(distinct fs1.ship_id) from stu_flight_sig fs1
889
                    WHERE fs1.location_id = l.id
890
                    AND fs1.ship_id = :shipId
891
                    AND fs1.time > :timeThreshold
892
                    '
893
            . $conditions[0]
894
            . '
895
                    AND (fs1.from_direction = 1 OR fs1.to_direction = 1)) as d1c,
896
                (SELECT count(distinct fs2.ship_id) from stu_flight_sig fs2
897
                    WHERE fs2.location_id = l.id
898
                    AND fs2.ship_id = :shipId
899
                    AND fs2.time > :timeThreshold
900
                    '
901
            . $conditions[1]
902
            . '
903
                    AND (fs2.from_direction = 2 OR fs2.to_direction = 2)) as d2c,
904
                (SELECT count(distinct fs3.ship_id) from stu_flight_sig fs3
905
                    WHERE fs3.location_id = l.id
906
                    AND fs3.ship_id = :shipId
907
                    AND fs3.time > :timeThreshold
908
                    '
909
            . $conditions[2]
910
            . '
911
                    AND (fs3.from_direction = 3 OR fs3.to_direction = 3)) as d3c,
912
                (SELECT count(distinct fs4.ship_id) from stu_flight_sig fs4
913
                    WHERE fs4.location_id = l.id
914
                    AND fs4.ship_id = :shipId
915
                    AND fs4.time > :timeThreshold
916
                    '
917
            . $conditions[3]
918
            . '
919
                    AND (fs4.from_direction = 4 OR fs4.to_direction = 4)) as d4c
920
                FROM stu_location l
921
                WHERE l.cx BETWEEN :xStart AND :xEnd
922
                AND l.cy BETWEEN :yStart AND :yEnd
923
                AND l.layer_id = :layerId',
924
            $rsm
925
        );
926
927
        $parameters = [
928
            'xStart' => $boundaries->getMinX(),
929
            'xEnd' => $boundaries->getMaxX(),
930
            'yStart' => $boundaries->getMinY(),
931
            'yEnd' => $boundaries->getMaxY(),
932
            'layerId' => $boundaries->getParentId(),
933
            'shipId' => $shipId,
934
            'timeThreshold' => $maxAge
935
        ];
936
937
        if ($cloaked_check) {
938
            $parameters['false'] = false;
939
        }
940
941
        if ($rumpId !== null) {
942
            $parameters['rumpId'] = $rumpId;
943
        }
944
945
        return $query->setParameters($parameters)->getResult();
946
    }
947
948
    #[\Override]
949
    public function getAllianceSubspaceLayerData(
950
        PanelBoundaries $boundaries,
951
        int $allianceId,
952
        ResultSetMapping $rsm
953
    ): array {
954
        return $this->getEntityManager()
955
            ->createNativeQuery(
956
            'SELECT l.id, l.cx as x, l.cy as y,
957
            (SELECT count(distinct fs1.ship_id) from stu_flight_sig fs1
958
                JOIN stu_user u1 ON fs1.user_id = u1.id
959
                WHERE fs1.location_id = l.id
960
                AND u1.allys_id = :allyId
961
                AND (fs1.from_direction = 1 OR fs1.to_direction = 1)) as d1c,
962
            (SELECT count(distinct fs2.ship_id) from stu_flight_sig fs2
963
                JOIN stu_user u2 ON fs2.user_id = u2.id
964
                WHERE fs2.location_id = l.id
965
                AND u2.allys_id = :allyId
966
                AND (fs2.from_direction = 2 OR fs2.to_direction = 2)) as d2c,
967
            (SELECT count(distinct fs3.ship_id) from stu_flight_sig fs3
968
                JOIN stu_user u3 ON fs3.user_id = u3.id
969
                WHERE fs3.location_id = l.id
970
                AND u3.allys_id = :allyId
971
                AND (fs3.from_direction = 3 OR fs3.to_direction = 3)) as d3c,
972
            (SELECT count(distinct fs4.ship_id) from stu_flight_sig fs4
973
                JOIN stu_user u4 ON fs4.user_id = u4.id
974
                WHERE fs4.location_id = l.id
975
                AND u4.allys_id = :allyId
976
                AND (fs4.from_direction = 4 OR fs4.to_direction = 4)) as d4c
977
            FROM stu_location l
978
            WHERE l.cx BETWEEN :xStart AND :xEnd
979
            AND l.cy BETWEEN :yStart AND :yEnd
980
            AND l.layer_id = :layerId',
981
                $rsm
982
            )
983
            ->setParameters([
984
                'xStart' => $boundaries->getMinX(),
985
                'xEnd' => $boundaries->getMaxX(),
986
                'yStart' => $boundaries->getMinY(),
987
                'yEnd' => $boundaries->getMaxY(),
988
                'layerId' => $boundaries->getParentId(),
989
                'allyId' => $allianceId
990
            ])
991
            ->getResult();
992
    }
993
994 1
    #[\Override]
995
    public function getUniqueInfluenceAreaIds(int $layerId): array
996
    {
997 1
        $rsm = new ResultSetMapping();
998 1
        $rsm->addScalarResult('influence_area_id', 'influence_area_id', 'integer');
999
1000 1
        $query = $this->getEntityManager()
1001 1
            ->createNativeQuery(
1002 1
                'SELECT DISTINCT m.influence_area_id
1003
            FROM stu_map m
1004
            JOIN stu_location l ON m.id = l.id
1005
            WHERE m.influence_area_id IS NOT NULL
1006
            AND l.layer_id = :layerId
1007 1
            ORDER BY m.influence_area_id ASC',
1008 1
                $rsm
1009 1
            )
1010 1
            ->setParameters([
1011 1
                'layerId' => $layerId
1012 1
            ]);
1013
1014 1
        return array_map('intval', array_column($query->getResult(), 'influence_area_id'));
1015
    }
1016
1017
    #[\Override]
1018
    public function isAdminRegionUserRegion(int $locationId, int $factionId): bool
1019
    {
1020
        $result = $this->getEntityManager()
1021
            ->createQuery(
1022
                sprintf(
1023
                    'SELECT COUNT(mrs.id) FROM %s m
1024
            JOIN %s ssm WITH m.systems_id = ssm.systems_id
1025
            JOIN %s mrs WITH m.admin_region_id = mrs.region_id
1026
            WHERE ssm.id = :locationId
1027
            AND mrs.faction_id = :factionId
1028
            AND m.admin_region_id IS NOT NULL',
1029
                    Map::class,
1030
                    StarSystemMap::class,
1031
                    MapRegionSettlement::class
1032
                )
1033
            )
1034
            ->setParameters([
1035
                'locationId' => $locationId,
1036
                'factionId' => $factionId
1037
            ])
1038
            ->getSingleScalarResult();
1039
1040
        return $result > 0;
1041
    }
1042
1043
    #[\Override]
1044
    public function getMapFieldsByRegion(int $regionId): array
1045
    {
1046
        return $this->getEntityManager()
1047
            ->createQuery(
1048
                sprintf(
1049
                    'SELECT m FROM %s m
1050
                    JOIN %s l
1051
                    WITH m.id = l.id
1052
                    WHERE m.region_id = :regionId
1053
                    ORDER BY l.cy ASC, l.cx ASC',
1054
                    Map::class,
1055
                    Location::class
1056
                )
1057
            )
1058
            ->setParameters([
1059
                'regionId' => $regionId
1060
            ])
1061
            ->getResult();
1062
    }
1063
}
1064