|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* This file contains only the AutoEdits class. |
|
4
|
|
|
*/ |
|
5
|
|
|
|
|
6
|
|
|
declare(strict_types = 1); |
|
7
|
|
|
|
|
8
|
|
|
namespace AppBundle\Model; |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* AutoEdits returns statistics about automated edits made by a user. |
|
12
|
|
|
*/ |
|
13
|
|
|
class AutoEdits extends Model |
|
14
|
|
|
{ |
|
15
|
|
|
/** @var null|string The tool we're searching for when fetching (semi-)automated edits. */ |
|
16
|
|
|
protected $tool; |
|
17
|
|
|
|
|
18
|
|
|
/** @var Edit[] The list of non-automated contributions. */ |
|
19
|
|
|
protected $nonAutomatedEdits; |
|
20
|
|
|
|
|
21
|
|
|
/** @var Edit[] The list of automated contributions. */ |
|
22
|
|
|
protected $automatedEdits; |
|
23
|
|
|
|
|
24
|
|
|
/** @var int Total number of edits. */ |
|
25
|
|
|
protected $editCount; |
|
26
|
|
|
|
|
27
|
|
|
/** @var int Total number of non-automated edits. */ |
|
28
|
|
|
protected $automatedCount; |
|
29
|
|
|
|
|
30
|
|
|
/** @var array Counts of known automated tools used by the given user. */ |
|
31
|
|
|
protected $toolCounts; |
|
32
|
|
|
|
|
33
|
|
|
/** @var int Total number of edits made with the tools. */ |
|
34
|
|
|
protected $toolsTotal; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* Constructor for the AutoEdits class. |
|
38
|
|
|
* @param Project $project |
|
39
|
|
|
* @param User $user |
|
40
|
|
|
* @param int|string $namespace Namespace ID or 'all' |
|
41
|
|
|
* @param int|false $start Start date in a format accepted by strtotime() |
|
42
|
|
|
* @param int|false $end End date in a format accepted by strtotime() |
|
43
|
|
|
* @param string $tool The tool we're searching for when fetching (semi-)automated edits. |
|
44
|
|
|
* @param int|string $offset Used for pagination, offset results by N edits. |
|
45
|
|
|
*/ |
|
46
|
5 |
|
public function __construct( |
|
47
|
|
|
Project $project, |
|
48
|
|
|
User $user, |
|
49
|
|
|
$namespace = 0, |
|
50
|
|
|
$start = false, |
|
51
|
|
|
$end = false, |
|
52
|
|
|
$tool = null, |
|
53
|
|
|
$offset = 0 |
|
54
|
|
|
) { |
|
55
|
5 |
|
$this->project = $project; |
|
56
|
5 |
|
$this->user = $user; |
|
57
|
5 |
|
$this->namespace = $namespace; |
|
58
|
5 |
|
$this->start = false === $start ? '' : date('Y-m-d', $start); |
|
59
|
5 |
|
$this->end = false === $end ? '' : date('Y-m-d', $end); |
|
60
|
5 |
|
$this->tool = $tool; |
|
61
|
5 |
|
$this->offset = $offset; |
|
|
|
|
|
|
62
|
5 |
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* The tool we're limiting the results to when fetching |
|
66
|
|
|
* (semi-)automated contributions. |
|
67
|
|
|
* @return null|string |
|
68
|
|
|
*/ |
|
69
|
1 |
|
public function getTool(): ?string |
|
70
|
|
|
{ |
|
71
|
1 |
|
return $this->tool; |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
/** |
|
75
|
|
|
* Get the raw edit count of the user. |
|
76
|
|
|
* @return int |
|
77
|
|
|
*/ |
|
78
|
1 |
|
public function getEditCount(): int |
|
79
|
|
|
{ |
|
80
|
1 |
|
if (!is_int($this->editCount)) { |
|
|
|
|
|
|
81
|
1 |
|
$this->editCount = $this->user->countEdits( |
|
82
|
1 |
|
$this->project, |
|
83
|
1 |
|
$this->namespace, |
|
84
|
1 |
|
$this->start, |
|
85
|
1 |
|
$this->end |
|
86
|
|
|
); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
1 |
|
return $this->editCount; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* Get the number of edits this user made using semi-automated tools. |
|
94
|
|
|
* This is not the same as self::getToolCounts because the regex can overlap. |
|
95
|
|
|
* @return int Result of query, see below. |
|
96
|
|
|
*/ |
|
97
|
1 |
|
public function getAutomatedCount(): int |
|
98
|
|
|
{ |
|
99
|
1 |
|
if (is_int($this->automatedCount)) { |
|
|
|
|
|
|
100
|
1 |
|
return $this->automatedCount; |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
1 |
|
$this->automatedCount = (int)$this->getRepository()->countAutomatedEdits( |
|
104
|
1 |
|
$this->project, |
|
105
|
1 |
|
$this->user, |
|
106
|
1 |
|
$this->namespace, |
|
107
|
1 |
|
$this->start, |
|
108
|
1 |
|
$this->end |
|
109
|
|
|
); |
|
110
|
|
|
|
|
111
|
1 |
|
return $this->automatedCount; |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* Get the percentage of all edits made using automated tools. |
|
116
|
|
|
* @return float |
|
117
|
|
|
*/ |
|
118
|
1 |
|
public function getAutomatedPercentage(): float |
|
119
|
|
|
{ |
|
120
|
1 |
|
return $this->getEditCount() > 0 |
|
121
|
1 |
|
? ($this->getAutomatedCount() / $this->getEditCount()) * 100 |
|
122
|
1 |
|
: 0; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* Get non-automated contributions for this user. |
|
127
|
|
|
* @param bool $raw Wether to return raw data from the database, or get Edit objects. |
|
128
|
|
|
* @return string[]|Edit[] |
|
129
|
|
|
*/ |
|
130
|
1 |
|
public function getNonAutomatedEdits(bool $raw = false) |
|
131
|
|
|
{ |
|
132
|
1 |
|
if (is_array($this->nonAutomatedEdits)) { |
|
|
|
|
|
|
133
|
1 |
|
return $this->nonAutomatedEdits; |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
1 |
|
$revs = $this->getRepository()->getNonAutomatedEdits( |
|
137
|
1 |
|
$this->project, |
|
138
|
1 |
|
$this->user, |
|
139
|
1 |
|
$this->namespace, |
|
140
|
1 |
|
$this->start, |
|
141
|
1 |
|
$this->end, |
|
142
|
1 |
|
$this->offset |
|
143
|
|
|
); |
|
144
|
|
|
|
|
145
|
1 |
|
if ($raw) { |
|
146
|
1 |
|
return $revs; |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
1 |
|
$this->nonAutomatedEdits = Edit::getEditsFromRevs($this->project, $this->user, $revs); |
|
150
|
|
|
|
|
151
|
1 |
|
return $this->nonAutomatedEdits; |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
/** |
|
155
|
|
|
* Get automated contributions for this user. |
|
156
|
|
|
* @param bool $raw Whether to return raw data from the database, or get Edit objects. |
|
157
|
|
|
* @return Edit[] |
|
158
|
|
|
*/ |
|
159
|
1 |
|
public function getAutomatedEdits(bool $raw = false): array |
|
160
|
|
|
{ |
|
161
|
1 |
|
if (is_array($this->automatedEdits)) { |
|
|
|
|
|
|
162
|
1 |
|
return $this->automatedEdits; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
1 |
|
$revs = $this->getRepository()->getAutomatedEdits( |
|
166
|
1 |
|
$this->project, |
|
167
|
1 |
|
$this->user, |
|
168
|
1 |
|
$this->namespace, |
|
169
|
1 |
|
$this->start, |
|
170
|
1 |
|
$this->end, |
|
171
|
1 |
|
$this->tool, |
|
172
|
1 |
|
$this->offset |
|
173
|
|
|
); |
|
174
|
|
|
|
|
175
|
1 |
|
if ($raw) { |
|
176
|
1 |
|
return $revs; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
1 |
|
$this->automatedEdits = Edit::getEditsFromRevs($this->project, $this->user, $revs); |
|
180
|
|
|
|
|
181
|
1 |
|
return $this->automatedEdits; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* Get counts of known automated tools used by the given user. |
|
186
|
|
|
* @return array Each tool that they used along with the count and link: |
|
187
|
|
|
* [ |
|
188
|
|
|
* 'Twinkle' => [ |
|
189
|
|
|
* 'count' => 50, |
|
190
|
|
|
* 'link' => 'Wikipedia:Twinkle', |
|
191
|
2 |
|
* ], |
|
192
|
|
|
* ] |
|
193
|
2 |
|
*/ |
|
194
|
2 |
|
public function getToolCounts(): array |
|
195
|
|
|
{ |
|
196
|
2 |
|
if (is_array($this->toolCounts)) { |
|
|
|
|
|
|
197
|
2 |
|
return $this->toolCounts; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
$this->toolCounts = $this->getRepository()->getToolCounts( |
|
201
|
|
|
$this->project, |
|
202
|
|
|
$this->user, |
|
203
|
|
|
$this->namespace, |
|
204
|
|
|
$this->start, |
|
205
|
2 |
|
$this->end |
|
206
|
|
|
); |
|
207
|
2 |
|
|
|
208
|
2 |
|
return $this->toolCounts; |
|
209
|
|
|
} |
|
210
|
2 |
|
|
|
211
|
1 |
|
/** |
|
212
|
|
|
* Get a list of all available tools for the Project. |
|
213
|
1 |
|
* @return array |
|
214
|
|
|
*/ |
|
215
|
|
|
public function getAllTools(): array |
|
216
|
2 |
|
{ |
|
217
|
|
|
return $this->getRepository()->getTools($this->project); |
|
|
|
|
|
|
218
|
|
|
} |
|
219
|
|
|
|
|
220
|
|
|
/** |
|
221
|
|
|
* Get the combined number of edits made with each tool. This is calculated separately from |
|
222
|
|
|
* self::getAutomatedCount() because the regex can sometimes overlap, and the counts are actually different. |
|
223
|
|
|
* @return int |
|
224
|
|
|
*/ |
|
225
|
|
|
public function getToolsTotal(): int |
|
226
|
|
|
{ |
|
227
|
|
|
if (!is_int($this->toolsTotal)) { |
|
|
|
|
|
|
228
|
|
|
$this->toolsTotal = array_reduce($this->getToolCounts(), function ($a, $b) { |
|
229
|
1 |
|
return $a + $b['count']; |
|
230
|
|
|
}); |
|
231
|
1 |
|
} |
|
232
|
1 |
|
|
|
233
|
|
|
return $this->toolsTotal; |
|
234
|
|
|
} |
|
235
|
|
|
} |
|
236
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.