1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file contains only the Pages class. |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace Xtools; |
7
|
|
|
|
8
|
|
|
use Xtools\Project; |
9
|
|
|
use Xtools\User; |
10
|
|
|
use DateTime; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* A Pages provides statistics about the pages created by a given User. |
14
|
|
|
*/ |
15
|
|
|
class Pages extends Model |
16
|
|
|
{ |
17
|
|
|
const RESULTS_LIMIT_SINGLE_NAMESPACE = 1000; |
18
|
|
|
const RESULTS_LIMIT_ALL_NAMESPACES = 100; |
19
|
|
|
|
20
|
|
|
/** @var Project The project. */ |
21
|
|
|
protected $project; |
22
|
|
|
|
23
|
|
|
/** @var User The user. */ |
24
|
|
|
protected $user; |
25
|
|
|
|
26
|
|
|
/** @var string Which namespace we are querying for. */ |
27
|
|
|
protected $namespace; |
28
|
|
|
|
29
|
|
|
/** @var string One of 'noredirects', 'onlyredirects' or blank for both. */ |
30
|
|
|
protected $redirects; |
31
|
|
|
|
32
|
|
|
/** @var string One of 'both', 'live' or 'deleted' */ |
33
|
|
|
protected $deleted; |
34
|
|
|
|
35
|
|
|
/** @var int Pagination offset. */ |
36
|
|
|
protected $offset; |
37
|
|
|
|
38
|
|
|
/** @var array The list of pages including various statistics. */ |
39
|
|
|
protected $pages; |
40
|
|
|
|
41
|
|
|
/** @var array Number of redirects/pages that were created/deleted, broken down by namespace. */ |
42
|
|
|
protected $countsByNamespace; |
43
|
|
|
|
44
|
|
|
/** @var bool Whether or not the Project supports page assessments. */ |
45
|
|
|
protected $hasPageAssessments; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Pages constructor. |
49
|
|
|
* @param Project $project |
50
|
|
|
* @param User $user |
51
|
|
|
* @param string|int $namespace Namespace ID or 'all'. |
52
|
|
|
* @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both. |
53
|
|
|
* @param string $deleted One of 'live', 'deleted' or 'both'. |
54
|
|
|
* @param int $offset Pagination offset. |
55
|
|
|
*/ |
56
|
2 |
|
public function __construct( |
57
|
|
|
Project $project, |
58
|
|
|
User $user, |
59
|
|
|
$namespace = 0, |
60
|
|
|
$redirects = 'noredirects', |
61
|
|
|
$deleted = 'both', |
62
|
|
|
$offset = 0 |
63
|
|
|
) { |
64
|
2 |
|
$this->project = $project; |
65
|
2 |
|
$this->user = $user; |
66
|
2 |
|
$this->namespace = $namespace === 'all' ? 'all' : (string)$namespace; |
67
|
2 |
|
$this->redirects = $redirects; |
68
|
2 |
|
$this->deleted = $deleted; |
69
|
2 |
|
$this->offset = $offset; |
70
|
2 |
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* The project associated with this Pages instance. |
74
|
|
|
* @return Project |
75
|
|
|
*/ |
76
|
1 |
|
public function getProject() |
77
|
|
|
{ |
78
|
1 |
|
return $this->project; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* The user associated with this Pages instance. |
83
|
|
|
* @return User |
84
|
|
|
*/ |
85
|
1 |
|
public function getUser() |
86
|
|
|
{ |
87
|
1 |
|
return $this->user; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* The namespace associated with this Pages instance. |
92
|
|
|
* @return int|string |
93
|
|
|
*/ |
94
|
1 |
|
public function getNamespace() |
95
|
|
|
{ |
96
|
1 |
|
return $this->namespace; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* The redirects option associated with this Pages instance. |
101
|
|
|
* @return string |
102
|
|
|
*/ |
103
|
1 |
|
public function getRedirects() |
104
|
|
|
{ |
105
|
1 |
|
return $this->redirects; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* The deleted pages option associated with this Page instance. |
110
|
|
|
* @return string |
111
|
|
|
*/ |
112
|
|
|
public function getDeleted() |
113
|
|
|
{ |
114
|
|
|
return $this->deleted; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* The pagination offset associated with this Pages instance. |
119
|
|
|
* @return int |
120
|
|
|
*/ |
121
|
1 |
|
public function getOffset() |
122
|
|
|
{ |
123
|
1 |
|
return $this->offset; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Fetch and prepare the pages created by the user. |
128
|
|
|
* @codeCoverageIgnore |
129
|
|
|
*/ |
130
|
|
|
public function prepareData() |
131
|
|
|
{ |
132
|
|
|
$this->pages = []; |
133
|
|
|
|
134
|
|
|
foreach ($this->getNamespaces() as $ns) { |
135
|
|
|
$data = $this->fetchPagesCreated($ns); |
136
|
|
|
$this->pages[$ns] = $this->formatPages($data)[$ns]; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return $this->pages; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* The public function to get the list of all pages created by the user, |
144
|
|
|
* up to self::resultsPerPage(), across all namespaces. |
145
|
|
|
* @return array |
146
|
|
|
*/ |
147
|
1 |
|
public function getResults() |
148
|
|
|
{ |
149
|
1 |
|
if ($this->pages === null) { |
150
|
|
|
$this->prepareData(); |
151
|
|
|
} |
152
|
1 |
|
return $this->pages; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Get the total number of pages the user has created. |
157
|
|
|
* @return int |
158
|
|
|
*/ |
159
|
|
|
public function getNumPages() |
160
|
|
|
{ |
161
|
|
|
$total = 0; |
162
|
|
|
foreach ($this->getCounts() as $ns => $values) { |
163
|
|
|
$total += $values['count']; |
164
|
|
|
} |
165
|
|
|
return $total; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Get the total number of pages we're showing data for. |
170
|
|
|
* @return int |
171
|
|
|
*/ |
172
|
1 |
|
public function getNumResults() |
173
|
|
|
{ |
174
|
1 |
|
$total = 0; |
175
|
1 |
|
foreach ($this->getResults() as $ns => $pages) { |
176
|
1 |
|
$total += count($pages); |
177
|
|
|
} |
178
|
1 |
|
return $total; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Get the total number of pages that are currently deleted. |
183
|
|
|
* @return int |
184
|
|
|
*/ |
185
|
1 |
|
public function getNumDeleted() |
186
|
|
|
{ |
187
|
1 |
|
$total = 0; |
188
|
1 |
|
foreach ($this->getCounts() as $ns => $values) { |
189
|
1 |
|
$total += $values['deleted']; |
190
|
|
|
} |
191
|
1 |
|
return $total; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Get the total number of pages that are currently redirects. |
196
|
|
|
* @return int |
197
|
|
|
*/ |
198
|
1 |
|
public function getNumRedirects() |
199
|
|
|
{ |
200
|
1 |
|
$total = 0; |
201
|
1 |
|
foreach ($this->getCounts() as $ns => $values) { |
202
|
1 |
|
$total += $values['redirects']; |
203
|
|
|
} |
204
|
1 |
|
return $total; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Get the namespaces in which this user has created pages. |
209
|
|
|
* @return string[] The IDs. |
210
|
|
|
*/ |
211
|
1 |
|
public function getNamespaces() |
212
|
|
|
{ |
213
|
1 |
|
return array_keys($this->getCounts()); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Number of namespaces being reported. |
218
|
|
|
* @return int |
219
|
|
|
*/ |
220
|
|
|
public function getNumNamespaces() |
221
|
|
|
{ |
222
|
|
|
return count(array_keys($this->getCounts())); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Number of redirects/pages that were created/deleted, broken down by namespace. |
227
|
|
|
* @return array Namespace IDs as the keys, with values 'count', 'deleted' and 'redirects'. |
228
|
|
|
*/ |
229
|
1 |
|
public function getCounts() |
230
|
|
|
{ |
231
|
1 |
|
if ($this->countsByNamespace !== null) { |
232
|
1 |
|
return $this->countsByNamespace; |
233
|
|
|
} |
234
|
|
|
|
235
|
1 |
|
$counts = []; |
236
|
|
|
|
237
|
1 |
|
foreach ($this->countPagesCreated() as $row) { |
238
|
1 |
|
$counts[$row['namespace']] = [ |
239
|
1 |
|
'count' => (int)$row['count'], |
240
|
1 |
|
'deleted' => (int)$row['deleted'], |
241
|
1 |
|
'redirects' => (int)$row['redirects'] |
242
|
|
|
]; |
243
|
|
|
} |
244
|
|
|
|
245
|
1 |
|
$this->countsByNamespace = $counts; |
246
|
1 |
|
return $this->countsByNamespace; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Number of results to show, depending on the namespace. |
251
|
|
|
* @return int |
252
|
|
|
*/ |
253
|
1 |
|
public function resultsPerPage() |
254
|
|
|
{ |
255
|
1 |
|
if ($this->namespace === 'all') { |
256
|
|
|
return self::RESULTS_LIMIT_ALL_NAMESPACES; |
257
|
|
|
} |
258
|
1 |
|
return self::RESULTS_LIMIT_SINGLE_NAMESPACE; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Whether or not the results include page assessments. |
263
|
|
|
* @return bool |
264
|
|
|
*/ |
265
|
1 |
|
public function hasPageAssessments() |
266
|
|
|
{ |
267
|
1 |
|
if ($this->hasPageAssessments === null) { |
268
|
1 |
|
$this->hasPageAssessments = $this->project->hasPageAssessments(); |
269
|
|
|
} |
270
|
1 |
|
return $this->hasPageAssessments; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Run the query to get pages created by the user with options. |
275
|
|
|
* This is ran independently for each namespace if $this->namespace is 'all'. |
276
|
|
|
* @param string $namespace Namespace ID. |
277
|
|
|
* @return array |
278
|
|
|
*/ |
279
|
1 |
|
private function fetchPagesCreated($namespace) |
280
|
|
|
{ |
281
|
1 |
|
return $this->user->getRepository()->getPagesCreated( |
|
|
|
|
282
|
1 |
|
$this->project, |
283
|
1 |
|
$this->user, |
284
|
1 |
|
$namespace, |
285
|
1 |
|
$this->redirects, |
286
|
1 |
|
$this->deleted, |
287
|
1 |
|
$this->resultsPerPage(), |
288
|
1 |
|
$this->offset * $this->resultsPerPage() |
289
|
|
|
); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Run the query to get the number of pages created by the user |
294
|
|
|
* with given options. |
295
|
|
|
* @return array |
296
|
|
|
*/ |
297
|
1 |
|
private function countPagesCreated() |
298
|
|
|
{ |
299
|
1 |
|
return $this->user->getRepository()->countPagesCreated( |
|
|
|
|
300
|
1 |
|
$this->project, |
301
|
1 |
|
$this->user, |
302
|
1 |
|
$this->namespace, |
303
|
1 |
|
$this->redirects, |
304
|
1 |
|
$this->deleted |
305
|
|
|
); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Format the data, adding humanized timestamps, page titles, assessment badges, |
310
|
|
|
* and sorting by namespace and then timestamp. |
311
|
|
|
* @param array $pages As returned by self::fetchPagesCreated() |
312
|
|
|
* @return array |
313
|
|
|
*/ |
314
|
1 |
|
private function formatPages($pages) |
315
|
|
|
{ |
316
|
1 |
|
$results = []; |
317
|
|
|
|
318
|
1 |
|
foreach ($pages as $row) { |
319
|
|
|
// if (!isset($results[$row['namespace']])) { |
320
|
|
|
// $results[$row['namespace']] = []; |
321
|
|
|
// } |
322
|
|
|
|
323
|
1 |
|
$datetime = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']); |
324
|
1 |
|
$datetimeHuman = $datetime->format('Y-m-d H:i'); |
325
|
|
|
|
326
|
1 |
|
$pageData = array_merge($row, [ |
327
|
1 |
|
'raw_time' => $row['rev_timestamp'], |
328
|
1 |
|
'human_time' => $datetimeHuman, |
329
|
1 |
|
'page_title' => str_replace('_', ' ', $row['page_title']) |
330
|
|
|
]); |
331
|
|
|
|
332
|
1 |
|
if ($this->hasPageAssessments()) { |
333
|
1 |
|
$pageData['badge'] = $this->project->getAssessmentBadgeURL($pageData['pa_class']); |
334
|
|
|
} |
335
|
|
|
|
336
|
1 |
|
$results[$row['namespace']][] = $pageData; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
// ksort($results); |
340
|
|
|
|
341
|
|
|
// foreach (array_keys($results) as $key) { |
342
|
|
|
// krsort($results[$key]); |
343
|
|
|
// } |
344
|
|
|
|
345
|
1 |
|
return $results; |
346
|
|
|
} |
347
|
|
|
} |
348
|
|
|
|