Passed
Push — develop ( e920eb...9cd2fd )
by BENARD
05:00
created

PlayerChartRankingProvider::getRankingBaseQuery()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 38
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 38
rs 9.456
c 0
b 0
f 0
cc 4
nc 6
nop 2
1
<?php
2
3
namespace VideoGamesRecords\CoreBundle\Ranking\Provider\Player;
4
5
use Doctrine\ORM\Exception\ORMException;
6
use Doctrine\ORM\NonUniqueResultException;
7
use Doctrine\ORM\NoResultException;
8
use Doctrine\ORM\QueryBuilder;
9
use VideoGamesRecords\CoreBundle\Entity\Chart;
10
use VideoGamesRecords\CoreBundle\Entity\Player;
11
use VideoGamesRecords\CoreBundle\Ranking\Provider\AbstractRankingProvider;
12
13
14
class PlayerChartRankingProvider extends AbstractRankingProvider
15
{
16
    const ORDER_BY_RANK = 'RANK';
17
    const ORDER_BY_SCORE = 'SCORE';
18
19
    /**
20
     * @throws ORMException
21
     */
22
    public function getRankingPoints(int $id = null, array $options = []): array
23
    {
24
        $chart = $this->em->getRepository('VideoGamesRecords\CoreBundle\Entity\Chart')->find($id);
25
        if (null === $chart) {
26
            return [];
27
        }
28
29
        $maxRank = $options['maxRank'] ?? null;
30
        $player = $this->getPlayer();
31
        $team = !empty($options['idTeam']) ? $this->em->getReference('VideoGamesRecords\CoreBundle\Entity\Team', $options['idTeam']) : null;
32
33
        $query = $this->em->createQueryBuilder()
34
            ->select('pc')
35
            ->from('VideoGamesRecords\CoreBundle\Entity\PlayerChart', 'pc')
36
            ->join('pc.player', 'p')
37
            ->addSelect('p')
38
            ->orderBy('pc.rank');
39
40
        $query->where('pc.chart = :chart')
41
            ->setParameter('chart', $chart);
42
43
        if ($team != null) {
44
            $query->andWhere('(p.team = :team)')
45
                ->setParameter('team', $team);
46
        } elseif (($maxRank !== null) && ($player !== null)) {
47
            $query->andWhere('(pg.rankPointChart <= :maxRank OR pc.player= :player)')
48
                ->setParameter('maxRank', $maxRank)
49
                ->setParameter('player', $player);
50
        } elseif ($maxRank !== null) {
51
            $query->andWhere('pc.rank <= :maxRank')
52
                ->setParameter('maxRank', $maxRank);
53
        } else {
54
            $query->setMaxResults(100);
55
        }
56
57
        return $query->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
58
    }
59
60
    public function getRankingMedals(int $id = null, array $options = []): array
61
    {
62
        return [];
63
    }
64
65
    /**
66
     * @param Chart $chart
67
     * @param array $options
68
     * @return array
69
     * @throws ORMException
70
     */
71
    public function getRanking(Chart $chart, array $options = []): array
72
    {
73
        $maxRank = $options['maxRank'] ?? null;
74
        $player = $this->getPlayer();
75
76
        $orderBy = $chart->getStatusPlayer()->isNormal() ? self::ORDER_BY_RANK : self::ORDER_BY_SCORE;
77
        $queryBuilder = $this->getRankingBaseQuery($chart, $orderBy);
78
        $queryBuilder->andWhere('status.boolRanking = 1');
79
80
        if (null !== $maxRank && null !== $player) {
81
            $rank = $this->getRank($player, $chart);
82
            if ($rank) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rank of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
83
                $queryBuilder
84
                    ->andWhere(
85
                        $queryBuilder->expr()->orX(
86
                            '(pc.rank <= :maxRank)',
87
                            '(pc.rank IS NULL)',
88
                            '(:min <= pc.rank) AND (pc.rank <= :max)',
89
                            '(pc.player = :player)'
90
                        )
91
                    )
92
                    ->setParameter('maxRank', $maxRank)
93
                    ->setParameter('player', $player)
94
                    ->setParameter(':min', $rank - 5)
95
                    ->setParameter(':max', $rank + 5);
96
            } else {
97
                $queryBuilder
98
                    ->andWhere(
99
                        $queryBuilder->expr()->orX('(pc.rank <= :maxRank)', '(pc.rank IS NULL)', 'pc.player = :player')
100
                    )
101
                    ->setParameter('maxRank', $maxRank)
102
                    ->setParameter('player', $player);
103
            }
104
        } elseif (null !== $maxRank) {
105
            $queryBuilder
106
                ->andWhere('pc.rank <= :maxRank')
107
                ->setParameter('maxRank', $maxRank);
108
        }
109
110
        return $queryBuilder->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $queryBuilder->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
111
    }
112
113
    /**
114
     * @param Chart $chart
115
     * @return array
116
     */
117
    public function getRankingDisabled(Chart $chart): array
118
    {
119
        $queryBuilder = $this->getRankingBaseQuery($chart, self::ORDER_BY_SCORE);
120
        $queryBuilder
121
            ->andWhere('status.boolRanking = 0');
122
123
        return $queryBuilder->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $queryBuilder->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
124
    }
125
126
    /**
127
     * @param Chart  $chart
128
     * @param string $orderBy
129
     * @return QueryBuilder
130
     */
131
    private function getRankingBaseQuery(Chart $chart, string $orderBy = self::ORDER_BY_RANK): QueryBuilder
132
    {
133
        $queryBuilder = $this->em->createQueryBuilder()
134
            ->select('pc')
135
            ->from('VideoGamesRecords\CoreBundle\Entity\PlayerChart', 'pc')
136
            ->innerJoin('pc.player', 'p')
137
            ->addSelect('p')
138
            ->innerJoin('pc.chart', 'c')
139
            ->innerJoin('pc.status', 'status')
140
            ->addSelect('status')
141
            ->where('c.id = :idChart')
142
            ->setParameter('idChart', $chart->getId());
143
144
        if (self::ORDER_BY_RANK === $orderBy) {
145
            $queryBuilder->orderBy('pc.rank', 'ASC')
146
                ->addOrderBy('status.sOrder', 'ASC')
147
                ->addOrderBy('pc.lastUpdate', 'ASC');
148
        }
149
150
        foreach ($chart->getLibs() as $lib) {
151
            $key             = 'value_' . $lib->getIdLibChart();
152
            $alias           = 'pcl_' . $lib->getIdLibChart();
153
            $subQueryBuilder = $this->em->createQueryBuilder()
154
                ->select(sprintf('%s.value', $alias))
155
                ->from('VideoGamesRecords\CoreBundle\Entity\PlayerChartLib', $alias)
156
                ->where(sprintf('%s.libChart = :%s', $alias, $key))
157
                ->andWhere(sprintf('%s.playerChart = pc', $alias))
158
                ->setParameter($key, $lib);
159
160
            $queryBuilder
161
                ->addSelect(sprintf('(%s) as %s', $subQueryBuilder->getQuery()->getDQL(), $key))
162
                ->setParameter($key, $lib);
163
            if (self::ORDER_BY_SCORE === $orderBy) {
164
                $queryBuilder->addOrderBy($key, $lib->getType()->getOrderBy());
165
            }
166
        }
167
168
        return $queryBuilder;
169
    }
170
171
    /**
172
     * @param Player $player
173
     * @param Chart  $chart
174
     * @return int|null
175
     */
176
    private function getRank(Player $player, Chart $chart): ?int
177
    {
178
        $query = $this->em->createQueryBuilder()
179
            ->from('VideoGamesRecords\CoreBundle\Entity\PlayerChart', 'pc')
180
            ->select('pc.rank')
181
            ->where('pc.player = :player')
182
            ->setParameter('player', $player)
183
            ->andWhere('pc.chart = :chart')
184
            ->setParameter('chart', $chart);
185
186
        try {
187
            return $query->getQuery()->getSingleScalarResult();
188
        } catch (NoResultException | NonUniqueResultException $e) {
189
            return null;
190
        }
191
    }
192
}
193