Passed
Pull Request — main (#442)
by MusikAnimal
07:52 queued 03:55
created

EditSummary::getTotalSummariesMinor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace App\Model;
6
7
use App\Helper\I18nHelper;
8
use App\Repository\EditSummaryRepository;
9
use DateTime;
10
11
/**
12
 * An EditSummary provides statistics about a user's edit summary usage over time.
13
 */
14
class EditSummary extends Model
15
{
16
    protected I18nHelper $i18n;
17
18
    /** @var int Number of edits from present to consider as 'recent'. */
19
    protected int $numEditsRecent;
20
21
    /**
22
     * Counts of summaries, raw edits, and per-month breakdown.
23
     * Keys are underscored because this also is served in the API.
24
     * @var array
25
     */
26
    protected array $data = [
27
        'recent_edits_minor' => 0,
28
        'recent_edits_major' => 0,
29
        'total_edits_minor' => 0,
30
        'total_edits_major' => 0,
31
        'total_edits' => 0,
32
        'recent_summaries_minor' => 0,
33
        'recent_summaries_major' => 0,
34
        'total_summaries_minor' => 0,
35
        'total_summaries_major' => 0,
36
        'total_summaries' => 0,
37
        'month_counts' => [],
38
    ];
39
40
    /**
41
     * EditSummary constructor.
42
     *
43
     * @param EditSummaryRepository $repository
44
     * @param Project $project The project we're working with.
45
     * @param User $user The user to process.
46
     * @param I18nHelper $i18n
47
     * @param int|string $namespace Namespace ID or 'all' for all namespaces.
48
     * @param int|false $start Start date as Unix timestamp.
49
     * @param int|false $end End date as Unix timestamp.
50
     * @param int $numEditsRecent Number of edits from present to consider as 'recent'.
51
     */
52
    public function __construct(
53
        EditSummaryRepository $repository,
54
        Project $project,
55
        User $user,
56
        I18nHelper $i18n,
57
        $namespace,
58
        $start = false,
59
        $end = false,
60
        int $numEditsRecent = 150
61
    ) {
62
        $this->repository = $repository;
63
        $this->project = $project;
64
        $this->user = $user;
65
        $this->i18n = $i18n;
66
        $this->namespace = $namespace;
67
        $this->start = $start;
68
        $this->end = $end;
69
        $this->numEditsRecent = $numEditsRecent;
70
    }
71
72
    /**
73
     * Get the total number of edits.
74
     * @return int
75
     */
76
    public function getTotalEdits(): int
77
    {
78
        return $this->data['total_edits'];
79
    }
80
81
    /**
82
     * Get the total number of minor edits.
83
     * @return int
84
     */
85
    public function getTotalEditsMinor(): int
86
    {
87
        return $this->data['total_edits_minor'];
88
    }
89
90
    /**
91
     * Get the total number of major (non-minor) edits.
92
     * @return int
93
     */
94
    public function getTotalEditsMajor(): int
95
    {
96
        return $this->data['total_edits_major'];
97
    }
98
99
    /**
100
     * Get the total number of recent minor edits.
101
     * @return int
102
     */
103
    public function getRecentEditsMinor(): int
104
    {
105
        return $this->data['recent_edits_minor'];
106
    }
107
108
    /**
109
     * Get the total number of recent major (non-minor) edits.
110
     * @return int
111
     */
112
    public function getRecentEditsMajor(): int
113
    {
114
        return $this->data['recent_edits_major'];
115
    }
116
117
    /**
118
     * Get the total number of edits with summaries.
119
     * @return int
120
     */
121
    public function getTotalSummaries(): int
122
    {
123
        return $this->data['total_summaries'];
124
    }
125
126
    /**
127
     * Get the total number of minor edits with summaries.
128
     * @return int
129
     */
130
    public function getTotalSummariesMinor(): int
131
    {
132
        return $this->data['total_summaries_minor'];
133
    }
134
135
    /**
136
     * Get the total number of major (non-minor) edits with summaries.
137
     * @return int
138
     */
139
    public function getTotalSummariesMajor(): int
140
    {
141
        return $this->data['total_summaries_major'];
142
    }
143
144
    /**
145
     * Get the total number of recent minor edits with with summaries.
146
     * @return int
147
     */
148
    public function getRecentSummariesMinor(): int
149
    {
150
        return $this->data['recent_summaries_minor'];
151
    }
152
153
    /**
154
     * Get the total number of recent major (non-minor) edits with with summaries.
155
     * @return int
156
     */
157
    public function getRecentSummariesMajor(): int
158
    {
159
        return $this->data['recent_summaries_major'];
160
    }
161
162
    /**
163
     * Get the month counts.
164
     * @return array Months as 'YYYY-MM' as the keys,
165
     *   with key 'total' and 'summaries' as the values.
166
     */
167
    public function getMonthCounts(): array
168
    {
169
        return $this->data['month_counts'];
170
    }
171
172
    /**
173
     * Get the whole blob of counts.
174
     * @return array Counts of summaries, raw edits, and per-month breakdown.
175
     * @codeCoverageIgnore
176
     */
177
    public function getData(): array
178
    {
179
        return $this->data;
180
    }
181
182
    /**
183
     * Fetch the data from the database, process, and put in memory.
184
     * @codeCoverageIgnore
185
     */
186
    public function prepareData(): array
187
    {
188
        // Do our database work in the Repository, passing in reference
189
        // to $this->processRow so we can do post-processing here.
190
        $ret = $this->repository->prepareData(
0 ignored issues
show
Bug introduced by
The method prepareData() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\EditSummaryRepository. ( Ignorable by Annotation )

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

190
        /** @scrutinizer ignore-call */ 
191
        $ret = $this->repository->prepareData(
Loading history...
191
            [$this, 'processRow'],
192
            $this->project,
193
            $this->user,
194
            $this->namespace,
195
            $this->start,
196
            $this->end
197
        );
198
199
        // We want to keep all the default zero values if there are no contributions.
200
        if (count($ret) > 0) {
201
            $this->data = $ret;
202
        }
203
204
        return $ret;
205
    }
206
207
    /**
208
     * Process a single row from the database, updating class properties with counts.
209
     * @param string[] $row As retrieved from the revision table.
210
     * @return string[]
211
     */
212
    public function processRow(array $row): array
213
    {
214
        // Extract the date out of the date field
215
        $timestamp = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']);
216
217
        $monthKey = $this->i18n->dateFormat($timestamp, 'yyyy-MM');
218
219
        // Grand total for number of edits
220
        $this->data['total_edits']++;
221
222
        // Update total edit count for this month.
223
        $this->updateMonthCounts($monthKey, 'total');
224
225
        // Total edit summaries
226
        if ($this->hasSummary($row)) {
227
            $this->data['total_summaries']++;
228
229
            // Update summary count for this month.
230
            $this->updateMonthCounts($monthKey, 'summaries');
231
        }
232
233
        if ($this->isMinor($row)) {
234
            $this->updateMajorMinorCounts($row, 'minor');
235
        } else {
236
            $this->updateMajorMinorCounts($row, 'major');
237
        }
238
239
        return $this->data;
240
    }
241
242
    /**
243
     * Given the row in `revision`, update minor counts.
244
     * @param string[] $row As retrieved from the revision table.
245
     * @param string $type Either 'minor' or 'major'.
246
     * @codeCoverageIgnore
247
     */
248
    private function updateMajorMinorCounts(array $row, string $type): void
249
    {
250
        $this->data['total_edits_'.$type]++;
251
252
        $hasSummary = $this->hasSummary($row);
253
        $isRecent = $this->data['recent_edits_'.$type] < $this->numEditsRecent;
254
255
        if ($hasSummary) {
256
            $this->data['total_summaries_'.$type]++;
257
        }
258
259
        // Update recent edits counts.
260
        if ($isRecent) {
261
            $this->data['recent_edits_'.$type]++;
262
263
            if ($hasSummary) {
264
                $this->data['recent_summaries_'.$type]++;
265
            }
266
        }
267
    }
268
269
    /**
270
     * Was the given row in `revision` marked as a minor edit?
271
     * @param string[] $row As retrieved from the revision table.
272
     * @return boolean
273
     */
274
    private function isMinor(array $row): bool
275
    {
276
        return 1 === (int)$row['rev_minor_edit'];
277
    }
278
279
    /**
280
     * Taking into account automated edit summaries, does the given
281
     * row in `revision` have a user-supplied edit summary?
282
     * @param string[] $row As retrieved from the revision table.
283
     * @return boolean
284
     */
285
    private function hasSummary(array $row): bool
286
    {
287
        $summary = preg_replace("/^\/\* (.*?) \*\/\s*/", '', $row['comment']);
288
        return '' !== $summary;
289
    }
290
291
    /**
292
     * Check and see if the month is set for given $monthKey and $type.
293
     * If it is, increment it, otherwise set it to 1.
294
     * @param string $monthKey In the form 'YYYY-MM'.
295
     * @param string $type     Either 'total' or 'summaries'.
296
     * @codeCoverageIgnore
297
     */
298
    private function updateMonthCounts(string $monthKey, string $type): void
299
    {
300
        if (isset($this->data['month_counts'][$monthKey][$type])) {
301
            $this->data['month_counts'][$monthKey][$type]++;
302
        } else {
303
            $this->data['month_counts'][$monthKey][$type] = 1;
304
        }
305
    }
306
}
307