These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Contain classes for dealing with individual log entries |
||
4 | * |
||
5 | * This is how I see the log system history: |
||
6 | * - appending to plain wiki pages |
||
7 | * - formatting log entries based on database fields |
||
8 | * - user is now part of the action message |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or modify |
||
11 | * it under the terms of the GNU General Public License as published by |
||
12 | * the Free Software Foundation; either version 2 of the License, or |
||
13 | * (at your option) any later version. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU General Public License along |
||
21 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
23 | * http://www.gnu.org/copyleft/gpl.html |
||
24 | * |
||
25 | * @file |
||
26 | * @author Niklas Laxström |
||
27 | * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
||
28 | * @since 1.19 |
||
29 | */ |
||
30 | |||
31 | /** |
||
32 | * Interface for log entries. Every log entry has these methods. |
||
33 | * |
||
34 | * @since 1.19 |
||
35 | */ |
||
36 | interface LogEntry { |
||
37 | |||
38 | /** |
||
39 | * The main log type. |
||
40 | * |
||
41 | * @return string |
||
42 | */ |
||
43 | public function getType(); |
||
44 | |||
45 | /** |
||
46 | * The log subtype. |
||
47 | * |
||
48 | * @return string |
||
49 | */ |
||
50 | public function getSubtype(); |
||
51 | |||
52 | /** |
||
53 | * The full logtype in format maintype/subtype. |
||
54 | * |
||
55 | * @return string |
||
56 | */ |
||
57 | public function getFullType(); |
||
58 | |||
59 | /** |
||
60 | * Get the extra parameters stored for this message. |
||
61 | * |
||
62 | * @return array |
||
63 | */ |
||
64 | public function getParameters(); |
||
65 | |||
66 | /** |
||
67 | * Get the user for performed this action. |
||
68 | * |
||
69 | * @return User |
||
70 | */ |
||
71 | public function getPerformer(); |
||
72 | |||
73 | /** |
||
74 | * Get the target page of this action. |
||
75 | * |
||
76 | * @return Title |
||
77 | */ |
||
78 | public function getTarget(); |
||
79 | |||
80 | /** |
||
81 | * Get the timestamp when the action was executed. |
||
82 | * |
||
83 | * @return string |
||
84 | */ |
||
85 | public function getTimestamp(); |
||
86 | |||
87 | /** |
||
88 | * Get the user provided comment. |
||
89 | * |
||
90 | * @return string |
||
91 | */ |
||
92 | public function getComment(); |
||
93 | |||
94 | /** |
||
95 | * Get the access restriction. |
||
96 | * |
||
97 | * @return string |
||
98 | */ |
||
99 | public function getDeleted(); |
||
100 | |||
101 | /** |
||
102 | * @param int $field One of LogPage::DELETED_* bitfield constants |
||
103 | * @return bool |
||
104 | */ |
||
105 | public function isDeleted( $field ); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Extends the LogEntryInterface with some basic functionality |
||
110 | * |
||
111 | * @since 1.19 |
||
112 | */ |
||
113 | abstract class LogEntryBase implements LogEntry { |
||
114 | |||
115 | public function getFullType() { |
||
116 | return $this->getType() . '/' . $this->getSubtype(); |
||
117 | } |
||
118 | |||
119 | public function isDeleted( $field ) { |
||
120 | return ( $this->getDeleted() & $field ) === $field; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Whether the parameters for this log are stored in new or |
||
125 | * old format. |
||
126 | * |
||
127 | * @return bool |
||
128 | */ |
||
129 | public function isLegacy() { |
||
130 | return false; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Create a blob from a parameter array |
||
135 | * |
||
136 | * @since 1.26 |
||
137 | * @param array $params |
||
138 | * @return string |
||
139 | */ |
||
140 | public static function makeParamBlob( $params ) { |
||
141 | return serialize( (array)$params ); |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Extract a parameter array from a blob |
||
146 | * |
||
147 | * @since 1.26 |
||
148 | * @param string $blob |
||
149 | * @return array |
||
150 | */ |
||
151 | public static function extractParams( $blob ) { |
||
152 | return unserialize( $blob ); |
||
153 | } |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * This class wraps around database result row. |
||
158 | * |
||
159 | * @since 1.19 |
||
160 | */ |
||
161 | class DatabaseLogEntry extends LogEntryBase { |
||
162 | |||
163 | /** |
||
164 | * Returns array of information that is needed for querying |
||
165 | * log entries. Array contains the following keys: |
||
166 | * tables, fields, conds, options and join_conds |
||
167 | * |
||
168 | * @return array |
||
169 | */ |
||
170 | public static function getSelectQueryData() { |
||
171 | $tables = [ 'logging', 'user' ]; |
||
172 | $fields = [ |
||
173 | 'log_id', 'log_type', 'log_action', 'log_timestamp', |
||
174 | 'log_user', 'log_user_text', |
||
175 | 'log_namespace', 'log_title', // unused log_page |
||
176 | 'log_comment', 'log_params', 'log_deleted', |
||
177 | 'user_id', 'user_name', 'user_editcount', |
||
178 | ]; |
||
179 | |||
180 | $joins = [ |
||
181 | // IPs don't have an entry in user table |
||
182 | 'user' => [ 'LEFT JOIN', 'log_user=user_id' ], |
||
183 | ]; |
||
184 | |||
185 | return [ |
||
186 | 'tables' => $tables, |
||
187 | 'fields' => $fields, |
||
188 | 'conds' => [], |
||
189 | 'options' => [], |
||
190 | 'join_conds' => $joins, |
||
191 | ]; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Constructs new LogEntry from database result row. |
||
196 | * Supports rows from both logging and recentchanges table. |
||
197 | * |
||
198 | * @param stdClass|array $row |
||
199 | * @return DatabaseLogEntry |
||
200 | */ |
||
201 | public static function newFromRow( $row ) { |
||
202 | $row = (object)$row; |
||
203 | if ( isset( $row->rc_logid ) ) { |
||
204 | return new RCDatabaseLogEntry( $row ); |
||
205 | } else { |
||
206 | return new self( $row ); |
||
207 | } |
||
208 | } |
||
209 | |||
210 | /** @var stdClass Database result row. */ |
||
211 | protected $row; |
||
212 | |||
213 | /** @var User */ |
||
214 | protected $performer; |
||
215 | |||
216 | /** @var array Parameters for log entry */ |
||
217 | protected $params; |
||
218 | |||
219 | /** @var int A rev id associated to the log entry */ |
||
220 | protected $revId = null; |
||
221 | |||
222 | /** @var bool Whether the parameters for this log entry are stored in new or old format. */ |
||
223 | protected $legacy; |
||
224 | |||
225 | protected function __construct( $row ) { |
||
226 | $this->row = $row; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Returns the unique database id. |
||
231 | * |
||
232 | * @return int |
||
233 | */ |
||
234 | public function getId() { |
||
235 | return (int)$this->row->log_id; |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Returns whatever is stored in the database field. |
||
240 | * |
||
241 | * @return string |
||
242 | */ |
||
243 | protected function getRawParameters() { |
||
244 | return $this->row->log_params; |
||
245 | } |
||
246 | |||
247 | public function isLegacy() { |
||
248 | // This extracts the property |
||
249 | $this->getParameters(); |
||
250 | return $this->legacy; |
||
251 | } |
||
252 | |||
253 | public function getType() { |
||
254 | return $this->row->log_type; |
||
255 | } |
||
256 | |||
257 | public function getSubtype() { |
||
258 | return $this->row->log_action; |
||
259 | } |
||
260 | |||
261 | public function getParameters() { |
||
262 | if ( !isset( $this->params ) ) { |
||
263 | $blob = $this->getRawParameters(); |
||
264 | MediaWiki\suppressWarnings(); |
||
265 | $params = LogEntryBase::extractParams( $blob ); |
||
266 | MediaWiki\restoreWarnings(); |
||
267 | if ( $params !== false ) { |
||
268 | $this->params = $params; |
||
269 | $this->legacy = false; |
||
270 | } else { |
||
271 | $this->params = LogPage::extractParams( $blob ); |
||
272 | $this->legacy = true; |
||
273 | } |
||
274 | |||
275 | if ( isset( $this->params['associated_rev_id'] ) ) { |
||
276 | $this->revId = $this->params['associated_rev_id']; |
||
277 | unset( $this->params['associated_rev_id'] ); |
||
278 | } |
||
279 | } |
||
280 | |||
281 | return $this->params; |
||
282 | } |
||
283 | |||
284 | public function getAssociatedRevId() { |
||
285 | // This extracts the property |
||
286 | $this->getParameters(); |
||
287 | return $this->revId; |
||
288 | } |
||
289 | |||
290 | public function getPerformer() { |
||
291 | if ( !$this->performer ) { |
||
292 | $userId = (int)$this->row->log_user; |
||
293 | View Code Duplication | if ( $userId !== 0 ) { |
|
294 | // logged-in users |
||
295 | if ( isset( $this->row->user_name ) ) { |
||
296 | $this->performer = User::newFromRow( $this->row ); |
||
297 | } else { |
||
298 | $this->performer = User::newFromId( $userId ); |
||
299 | } |
||
300 | } else { |
||
301 | // IP users |
||
302 | $userText = $this->row->log_user_text; |
||
303 | $this->performer = User::newFromName( $userText, false ); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | return $this->performer; |
||
308 | } |
||
309 | |||
310 | public function getTarget() { |
||
311 | $namespace = $this->row->log_namespace; |
||
312 | $page = $this->row->log_title; |
||
313 | $title = Title::makeTitle( $namespace, $page ); |
||
314 | |||
315 | return $title; |
||
316 | } |
||
317 | |||
318 | public function getTimestamp() { |
||
319 | return wfTimestamp( TS_MW, $this->row->log_timestamp ); |
||
320 | } |
||
321 | |||
322 | public function getComment() { |
||
323 | return $this->row->log_comment; |
||
324 | } |
||
325 | |||
326 | public function getDeleted() { |
||
327 | return $this->row->log_deleted; |
||
328 | } |
||
329 | } |
||
330 | |||
331 | class RCDatabaseLogEntry extends DatabaseLogEntry { |
||
332 | |||
333 | public function getId() { |
||
334 | return $this->row->rc_logid; |
||
335 | } |
||
336 | |||
337 | protected function getRawParameters() { |
||
338 | return $this->row->rc_params; |
||
339 | } |
||
340 | |||
341 | public function getAssociatedRevId() { |
||
342 | return $this->row->rc_this_oldid; |
||
343 | } |
||
344 | |||
345 | public function getType() { |
||
346 | return $this->row->rc_log_type; |
||
347 | } |
||
348 | |||
349 | public function getSubtype() { |
||
350 | return $this->row->rc_log_action; |
||
351 | } |
||
352 | |||
353 | public function getPerformer() { |
||
354 | View Code Duplication | if ( !$this->performer ) { |
|
355 | $userId = (int)$this->row->rc_user; |
||
356 | if ( $userId !== 0 ) { |
||
357 | $this->performer = User::newFromId( $userId ); |
||
358 | } else { |
||
359 | $userText = $this->row->rc_user_text; |
||
360 | // Might be an IP, don't validate the username |
||
361 | $this->performer = User::newFromName( $userText, false ); |
||
362 | } |
||
363 | } |
||
364 | |||
365 | return $this->performer; |
||
366 | } |
||
367 | |||
368 | public function getTarget() { |
||
369 | $namespace = $this->row->rc_namespace; |
||
370 | $page = $this->row->rc_title; |
||
371 | $title = Title::makeTitle( $namespace, $page ); |
||
372 | |||
373 | return $title; |
||
374 | } |
||
375 | |||
376 | public function getTimestamp() { |
||
377 | return wfTimestamp( TS_MW, $this->row->rc_timestamp ); |
||
378 | } |
||
379 | |||
380 | public function getComment() { |
||
381 | return $this->row->rc_comment; |
||
382 | } |
||
383 | |||
384 | public function getDeleted() { |
||
385 | return $this->row->rc_deleted; |
||
386 | } |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Class for creating log entries manually, to inject them into the database. |
||
391 | * |
||
392 | * @since 1.19 |
||
393 | */ |
||
394 | class ManualLogEntry extends LogEntryBase { |
||
395 | /** @var string Type of log entry */ |
||
396 | protected $type; |
||
397 | |||
398 | /** @var string Sub type of log entry */ |
||
399 | protected $subtype; |
||
400 | |||
401 | /** @var array Parameters for log entry */ |
||
402 | protected $parameters = []; |
||
403 | |||
404 | /** @var array */ |
||
405 | protected $relations = []; |
||
406 | |||
407 | /** @var User Performer of the action for the log entry */ |
||
408 | protected $performer; |
||
409 | |||
410 | /** @var Title Target title for the log entry */ |
||
411 | protected $target; |
||
412 | |||
413 | /** @var string Timestamp of creation of the log entry */ |
||
414 | protected $timestamp; |
||
415 | |||
416 | /** @var string Comment for the log entry */ |
||
417 | protected $comment = ''; |
||
418 | |||
419 | /** @var int A rev id associated to the log entry */ |
||
420 | protected $revId = 0; |
||
421 | |||
422 | /** @var array Change tags add to the log entry */ |
||
423 | protected $tags = null; |
||
424 | |||
425 | /** @var int Deletion state of the log entry */ |
||
426 | protected $deleted; |
||
427 | |||
428 | /** @var int ID of the log entry */ |
||
429 | protected $id; |
||
430 | |||
431 | /** @var Can this log entry be patrolled? */ |
||
432 | protected $isPatrollable = false; |
||
433 | |||
434 | /** @var bool Whether this is a legacy log entry */ |
||
435 | protected $legacy = false; |
||
436 | |||
437 | /** |
||
438 | * Constructor. |
||
439 | * |
||
440 | * @since 1.19 |
||
441 | * @param string $type |
||
442 | * @param string $subtype |
||
443 | */ |
||
444 | public function __construct( $type, $subtype ) { |
||
445 | $this->type = $type; |
||
446 | $this->subtype = $subtype; |
||
447 | } |
||
448 | |||
449 | /** |
||
450 | * Set extra log parameters. |
||
451 | * |
||
452 | * You can pass params to the log action message by prefixing the keys with |
||
453 | * a number and optional type, using colons to separate the fields. The |
||
454 | * numbering should start with number 4, the first three parameters are |
||
455 | * hardcoded for every message. |
||
456 | * |
||
457 | * If you want to store stuff that should not be available in messages, don't |
||
458 | * prefix the array key with a number and don't use the colons. |
||
459 | * |
||
460 | * Example: |
||
461 | * $entry->setParameters( |
||
462 | * '4::color' => 'blue', |
||
463 | * '5:number:count' => 3000, |
||
464 | * 'animal' => 'dog' |
||
465 | * ); |
||
466 | * |
||
467 | * @since 1.19 |
||
468 | * @param array $parameters Associative array |
||
469 | */ |
||
470 | public function setParameters( $parameters ) { |
||
471 | $this->parameters = $parameters; |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Declare arbitrary tag/value relations to this log entry. |
||
476 | * These can be used to filter log entries later on. |
||
477 | * |
||
478 | * @param array $relations Map of (tag => (list of values|value)) |
||
479 | * @since 1.22 |
||
480 | */ |
||
481 | public function setRelations( array $relations ) { |
||
482 | $this->relations = $relations; |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Set the user that performed the action being logged. |
||
487 | * |
||
488 | * @since 1.19 |
||
489 | * @param User $performer |
||
490 | */ |
||
491 | public function setPerformer( User $performer ) { |
||
492 | $this->performer = $performer; |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Set the title of the object changed. |
||
497 | * |
||
498 | * @since 1.19 |
||
499 | * @param Title $target |
||
500 | */ |
||
501 | public function setTarget( Title $target ) { |
||
502 | $this->target = $target; |
||
503 | } |
||
504 | |||
505 | /** |
||
506 | * Set the timestamp of when the logged action took place. |
||
507 | * |
||
508 | * @since 1.19 |
||
509 | * @param string $timestamp |
||
510 | */ |
||
511 | public function setTimestamp( $timestamp ) { |
||
512 | $this->timestamp = $timestamp; |
||
513 | } |
||
514 | |||
515 | /** |
||
516 | * Set a comment associated with the action being logged. |
||
517 | * |
||
518 | * @since 1.19 |
||
519 | * @param string $comment |
||
520 | */ |
||
521 | public function setComment( $comment ) { |
||
522 | $this->comment = $comment; |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Set an associated revision id. |
||
527 | * |
||
528 | * For example, the ID of the revision that was inserted to mark a page move |
||
529 | * or protection, file upload, etc. |
||
530 | * |
||
531 | * @since 1.27 |
||
532 | * @param int $revId |
||
533 | */ |
||
534 | public function setAssociatedRevId( $revId ) { |
||
535 | $this->revId = $revId; |
||
536 | } |
||
537 | |||
538 | /** |
||
539 | * Set change tags for the log entry. |
||
540 | * |
||
541 | * @since 1.27 |
||
542 | * @param string|string[] $tags |
||
543 | */ |
||
544 | public function setTags( $tags ) { |
||
545 | if ( is_string( $tags ) ) { |
||
546 | $tags = [ $tags ]; |
||
547 | } |
||
548 | $this->tags = $tags; |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * Set whether this log entry should be made patrollable |
||
553 | * This shouldn't depend on config, only on whether there is full support |
||
554 | * in the software for patrolling this log entry. |
||
555 | * False by default |
||
556 | * |
||
557 | * @since 1.27 |
||
558 | * @param bool $patrollable |
||
559 | */ |
||
560 | public function setIsPatrollable( $patrollable ) { |
||
561 | $this->isPatrollable = (bool)$patrollable; |
||
0 ignored issues
–
show
|
|||
562 | } |
||
563 | |||
564 | /** |
||
565 | * Set the 'legacy' flag |
||
566 | * |
||
567 | * @since 1.25 |
||
568 | * @param bool $legacy |
||
569 | */ |
||
570 | public function setLegacy( $legacy ) { |
||
571 | $this->legacy = $legacy; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Set the 'deleted' flag. |
||
576 | * |
||
577 | * @since 1.19 |
||
578 | * @param int $deleted One of LogPage::DELETED_* bitfield constants |
||
579 | */ |
||
580 | public function setDeleted( $deleted ) { |
||
581 | $this->deleted = $deleted; |
||
582 | } |
||
583 | |||
584 | /** |
||
585 | * Insert the entry into the `logging` table. |
||
586 | * |
||
587 | * @param IDatabase $dbw |
||
588 | * @return int ID of the log entry |
||
589 | * @throws MWException |
||
590 | */ |
||
591 | public function insert( IDatabase $dbw = null ) { |
||
592 | global $wgContLang; |
||
593 | |||
594 | $dbw = $dbw ?: wfGetDB( DB_MASTER ); |
||
595 | $id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); |
||
596 | |||
597 | if ( $this->timestamp === null ) { |
||
598 | $this->timestamp = wfTimestampNow(); |
||
599 | } |
||
600 | |||
601 | // Trim spaces on user supplied text |
||
602 | $comment = trim( $this->getComment() ); |
||
603 | |||
604 | // Truncate for whole multibyte characters. |
||
605 | $comment = $wgContLang->truncate( $comment, 255 ); |
||
606 | |||
607 | $params = $this->getParameters(); |
||
608 | $relations = $this->relations; |
||
609 | |||
610 | // Additional fields for which there's no space in the database table schema |
||
611 | $revId = $this->getAssociatedRevId(); |
||
612 | if ( $revId ) { |
||
613 | $params['associated_rev_id'] = $revId; |
||
614 | $relations['associated_rev_id'] = $revId; |
||
615 | } |
||
616 | |||
617 | $data = [ |
||
618 | 'log_id' => $id, |
||
619 | 'log_type' => $this->getType(), |
||
620 | 'log_action' => $this->getSubtype(), |
||
621 | 'log_timestamp' => $dbw->timestamp( $this->getTimestamp() ), |
||
622 | 'log_user' => $this->getPerformer()->getId(), |
||
623 | 'log_user_text' => $this->getPerformer()->getName(), |
||
624 | 'log_namespace' => $this->getTarget()->getNamespace(), |
||
625 | 'log_title' => $this->getTarget()->getDBkey(), |
||
626 | 'log_page' => $this->getTarget()->getArticleID(), |
||
627 | 'log_comment' => $comment, |
||
628 | 'log_params' => LogEntryBase::makeParamBlob( $params ), |
||
629 | ]; |
||
630 | if ( isset( $this->deleted ) ) { |
||
631 | $data['log_deleted'] = $this->deleted; |
||
632 | } |
||
633 | |||
634 | $dbw->insert( 'logging', $data, __METHOD__ ); |
||
635 | $this->id = !is_null( $id ) ? $id : $dbw->insertId(); |
||
636 | |||
637 | $rows = []; |
||
638 | foreach ( $relations as $tag => $values ) { |
||
639 | if ( !strlen( $tag ) ) { |
||
640 | throw new MWException( "Got empty log search tag." ); |
||
641 | } |
||
642 | |||
643 | if ( !is_array( $values ) ) { |
||
644 | $values = [ $values ]; |
||
645 | } |
||
646 | |||
647 | View Code Duplication | foreach ( $values as $value ) { |
|
648 | $rows[] = [ |
||
649 | 'ls_field' => $tag, |
||
650 | 'ls_value' => $value, |
||
651 | 'ls_log_id' => $this->id |
||
652 | ]; |
||
653 | } |
||
654 | } |
||
655 | if ( count( $rows ) ) { |
||
656 | $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' ); |
||
657 | } |
||
658 | |||
659 | return $this->id; |
||
660 | } |
||
661 | |||
662 | /** |
||
663 | * Get a RecentChanges object for the log entry |
||
664 | * |
||
665 | * @param int $newId |
||
666 | * @return RecentChange |
||
667 | * @since 1.23 |
||
668 | */ |
||
669 | public function getRecentChange( $newId = 0 ) { |
||
670 | $formatter = LogFormatter::newFromEntry( $this ); |
||
671 | $context = RequestContext::newExtraneousContext( $this->getTarget() ); |
||
672 | $formatter->setContext( $context ); |
||
673 | |||
674 | $logpage = SpecialPage::getTitleFor( 'Log', $this->getType() ); |
||
675 | $user = $this->getPerformer(); |
||
676 | $ip = ""; |
||
677 | if ( $user->isAnon() ) { |
||
678 | // "MediaWiki default" and friends may have |
||
679 | // no IP address in their name |
||
680 | if ( IP::isIPAddress( $user->getName() ) ) { |
||
681 | $ip = $user->getName(); |
||
682 | } |
||
683 | } |
||
684 | |||
685 | return RecentChange::newLogEntry( |
||
686 | $this->getTimestamp(), |
||
687 | $logpage, |
||
688 | $user, |
||
689 | $formatter->getPlainActionText(), |
||
690 | $ip, |
||
691 | $this->getType(), |
||
692 | $this->getSubtype(), |
||
693 | $this->getTarget(), |
||
694 | $this->getComment(), |
||
695 | LogEntryBase::makeParamBlob( $this->getParameters() ), |
||
696 | $newId, |
||
697 | $formatter->getIRCActionComment(), // Used for IRC feeds |
||
698 | $this->getAssociatedRevId(), // Used for e.g. moves and uploads |
||
699 | $this->getIsPatrollable() |
||
700 | ); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * Publish the log entry. |
||
705 | * |
||
706 | * @param int $newId Id of the log entry. |
||
707 | * @param string $to One of: rcandudp (default), rc, udp |
||
708 | */ |
||
709 | public function publish( $newId, $to = 'rcandudp' ) { |
||
710 | DeferredUpdates::addCallableUpdate( |
||
711 | function () use ( $newId, $to ) { |
||
712 | $log = new LogPage( $this->getType() ); |
||
713 | if ( !$log->isRestricted() ) { |
||
714 | $rc = $this->getRecentChange( $newId ); |
||
715 | |||
716 | if ( $to === 'rc' || $to === 'rcandudp' ) { |
||
717 | // save RC, passing tags so they are applied there |
||
718 | $tags = $this->getTags(); |
||
719 | if ( is_null( $tags ) ) { |
||
720 | $tags = []; |
||
721 | } |
||
722 | $rc->addTags( $tags ); |
||
723 | $rc->save( 'pleasedontudp' ); |
||
724 | } |
||
725 | |||
726 | if ( $to === 'udp' || $to === 'rcandudp' ) { |
||
727 | $rc->notifyRCFeeds(); |
||
728 | } |
||
729 | |||
730 | // Log the autopatrol if the log entry is patrollable |
||
731 | if ( $this->getIsPatrollable() && |
||
732 | $rc->getAttribute( 'rc_patrolled' ) === 1 |
||
733 | ) { |
||
734 | PatrolLog::record( $rc, true, $this->getPerformer() ); |
||
735 | } |
||
736 | } |
||
737 | }, |
||
738 | DeferredUpdates::POSTSEND, |
||
739 | wfGetDB( DB_MASTER ) |
||
740 | ); |
||
741 | } |
||
742 | |||
743 | public function getType() { |
||
744 | return $this->type; |
||
745 | } |
||
746 | |||
747 | public function getSubtype() { |
||
748 | return $this->subtype; |
||
749 | } |
||
750 | |||
751 | public function getParameters() { |
||
752 | return $this->parameters; |
||
753 | } |
||
754 | |||
755 | /** |
||
756 | * @return User |
||
757 | */ |
||
758 | public function getPerformer() { |
||
759 | return $this->performer; |
||
760 | } |
||
761 | |||
762 | /** |
||
763 | * @return Title |
||
764 | */ |
||
765 | public function getTarget() { |
||
766 | return $this->target; |
||
767 | } |
||
768 | |||
769 | public function getTimestamp() { |
||
770 | $ts = $this->timestamp !== null ? $this->timestamp : wfTimestampNow(); |
||
771 | |||
772 | return wfTimestamp( TS_MW, $ts ); |
||
773 | } |
||
774 | |||
775 | public function getComment() { |
||
776 | return $this->comment; |
||
777 | } |
||
778 | |||
779 | /** |
||
780 | * @since 1.27 |
||
781 | * @return int |
||
782 | */ |
||
783 | public function getAssociatedRevId() { |
||
784 | return $this->revId; |
||
785 | } |
||
786 | |||
787 | /** |
||
788 | * @since 1.27 |
||
789 | * @return array |
||
790 | */ |
||
791 | public function getTags() { |
||
792 | return $this->tags; |
||
793 | } |
||
794 | |||
795 | /** |
||
796 | * Whether this log entry is patrollable |
||
797 | * |
||
798 | * @since 1.27 |
||
799 | * @return bool |
||
800 | */ |
||
801 | public function getIsPatrollable() { |
||
802 | return $this->isPatrollable; |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * @since 1.25 |
||
807 | * @return bool |
||
808 | */ |
||
809 | public function isLegacy() { |
||
810 | return $this->legacy; |
||
811 | } |
||
812 | |||
813 | public function getDeleted() { |
||
814 | return (int)$this->deleted; |
||
815 | } |
||
816 | } |
||
817 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..