Passed
Push — main ( 8ed4a3...deab0e )
by MusikAnimal
04:20
created

GlobalContribs::globalEdits()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 44
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6.0702

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 24
c 1
b 0
f 0
nc 5
nop 0
dl 0
loc 44
ccs 21
cts 24
cp 0.875
crap 6.0702
rs 8.9137
1
<?php
2
declare(strict_types = 1);
3
4
namespace AppBundle\Model;
5
6
use AppBundle\Repository\GlobalContribsRepository;
7
8
/**
9
 * A GlobalContribs provides a list of a user's edits to all projects.
10
 */
11
class GlobalContribs extends Model
12
{
13
    /** @var int Number of results per page. */
14
    public const PAGE_SIZE = 50;
15
16
    /** @var int[] Keys are project DB names. */
17
    protected $globalEditCounts;
18
19
    /** @var array Most recent revisions across all projects. */
20
    protected $globalEdits;
21
22
    /**
23
     * GlobalContribs constructor.
24
     * @param User $user
25
     * @param string|int|null $namespace Namespace ID or 'all'.
26
     * @param false|int $start As Unix timestamp.
27
     * @param false|int $end As Unix timestamp.
28
     * @param false|int $offset As Unix timestamp.
29
     * @param int|null $limit Number of results to return.
30 2
     */
31
    public function __construct(
32 2
        User $user,
33 2
        $namespace = 'all',
34 2
        $start = false,
35 2
        $end = false,
36 2
        $offset = false,
37 2
        ?int $limit = null
38
    ) {
39
        $this->user = $user;
40
        $this->namespace = '' == $namespace ? 0 : $namespace;
41
        $this->start = $start;
42
        $this->end = $end;
43
        $this->offset = $offset;
44
        $this->limit = $limit ?? self::PAGE_SIZE;
45
    }
46
47
    /**
48
     * Get the total edit counts for the top n projects of this user.
49
     * @param int $numProjects
50
     * @return mixed[] Each element has 'total' and 'project' keys.
51
     */
52
    public function globalEditCountsTopN(int $numProjects = 10): array
53
    {
54 1
        // Get counts.
55
        $editCounts = $this->globalEditCounts(true);
56
        // Truncate, and return.
57 1
        return array_slice($editCounts, 0, $numProjects);
58
    }
59 1
60
    /**
61
     * Get the total number of edits excluding the top n.
62
     * @param int $numProjects
63
     * @return int
64
     */
65
    public function globalEditCountWithoutTopN(int $numProjects = 10): int
66
    {
67 1
        $editCounts = $this->globalEditCounts(true);
68
        $bottomM = array_slice($editCounts, $numProjects);
69 1
        $total = 0;
70 1
        foreach ($bottomM as $editCount) {
71 1
            $total += $editCount['total'];
72 1
        }
73 1
        return $total;
74
    }
75 1
76
    /**
77
     * Get the grand total of all edits on all projects.
78
     * @return int
79
     */
80
    public function globalEditCount(): int
81
    {
82 1
        $total = 0;
83
        foreach ($this->globalEditCounts() as $editCount) {
84 1
            $total += $editCount['total'];
85 1
        }
86 1
        return $total;
87
    }
88 1
89
    /**
90
     * Get the total revision counts for all projects for this user.
91
     * @param bool $sorted Whether to sort the list by total, or not.
92
     * @return mixed[] Each element has 'total' and 'project' keys.
93
     */
94
    public function globalEditCounts(bool $sorted = false): array
95
    {
96 1
        if (empty($this->globalEditCounts)) {
97
            $this->globalEditCounts = $this->getRepository()
98 1
                ->globalEditCounts($this->user);
0 ignored issues
show
Bug introduced by
The method globalEditCounts() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\GlobalContribsRepository. ( Ignorable by Annotation )

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

98
                ->/** @scrutinizer ignore-call */ globalEditCounts($this->user);
Loading history...
99 1
        }
100 1
101
        if ($sorted) {
102
            // Sort.
103 1
            uasort($this->globalEditCounts, function ($a, $b) {
104
                return $b['total'] - $a['total'];
105
            });
106 1
        }
107 1
108
        return $this->globalEditCounts;
109
    }
110 1
111
    public function numProjectsWithEdits(): int
112
    {
113
        return count($this->getRepository()->getProjectsWithEdits($this->user));
0 ignored issues
show
Bug introduced by
The method getProjectsWithEdits() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\GlobalContribsRepository. ( Ignorable by Annotation )

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

113
        return count($this->getRepository()->/** @scrutinizer ignore-call */ getProjectsWithEdits($this->user));
Loading history...
114
    }
115
116
    /**
117
     * Get the most recent revisions across all projects.
118
     * @return Edit[]
119
     */
120
    public function globalEdits(): array
121
    {
122 1
        if (is_array($this->globalEdits)) {
0 ignored issues
show
introduced by
The condition is_array($this->globalEdits) is always true.
Loading history...
123
            return $this->globalEdits;
124 1
        }
125
126
        // Get projects with edits.
127
        $projects = $this->getRepository()->getProjectsWithEdits($this->user);
128
        if (0 === count($projects)) {
129 1
            return [];
130 1
        }
131
132
        // Get all revisions for those projects.
133
        /** @var GlobalContribsRepository $globalContribsRepo */
134
        $globalContribsRepo = $this->getRepository();
135
        $globalRevisionsData = $globalContribsRepo->getRevisions(
136 1
            array_keys($projects),
137 1
            $this->user,
138 1
            $this->namespace,
139 1
            $this->start,
140 1
            $this->end,
141 1
            $this->limit + 1,
142 1
            $this->offset
143 1
        );
144 1
        $globalEdits = [];
145
146 1
        foreach ($globalRevisionsData as $revision) {
147
            /** @var Project $project */
148 1
            $project = $projects[$revision['dbName']];
149
150 1
            // Can happen if the project is given from CentralAuth API but the database is not being replicated.
151
            if (null === $project || !$project->exists()) {
152
                continue;
153 1
            }
154
155
            $edit = $this->getEditFromRevision($project, $revision);
156
            $globalEdits[$edit->getTimestamp()->getTimestamp().'-'.$edit->getId()] = $edit;
157 1
        }
158 1
159
        // Sort and prune, before adding more.
160
        krsort($globalEdits);
161
        $this->globalEdits = array_slice($globalEdits, 0, $this->limit);
162 1
163 1
        return $this->globalEdits;
164
    }
165 1
166
    private function getEditFromRevision(Project $project, array $revision): Edit
167
    {
168 1
        $page = Page::newFromRow($project, $revision);
169
        return new Edit($page, $revision);
170 1
    }
171
}
172