MediaWiki  master
CategoryMembershipChange.php
Go to the documentation of this file.
1 <?php
2 
9 
35 
36  private const CATEGORY_ADDITION = 1;
37  private const CATEGORY_REMOVAL = -1;
38 
42  private $timestamp;
43 
47  private $pageTitle;
48 
52  private $revision;
53 
59  private $numTemplateLinks = 0;
60 
64  private $newForCategorizationCallback = null;
65 
67  private $backlinkCache;
68 
74  public function __construct(
75  Title $pageTitle, BacklinkCache $backlinkCache, RevisionRecord $revision = null
76  ) {
77  $this->pageTitle = $pageTitle;
78  $this->revision = $revision;
79  if ( $revision === null ) {
80  $this->timestamp = wfTimestampNow();
81  } else {
82  $this->timestamp = $revision->getTimestamp();
83  }
84  $this->newForCategorizationCallback = [ RecentChange::class, 'newForCategorization' ];
85  $this->backlinkCache = $backlinkCache;
86  }
87 
95  public function overrideNewForCategorizationCallback( callable $callback ) {
96  if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
97  throw new LogicException( 'Cannot override newForCategorization callback in operation.' );
98  }
99  $this->newForCategorizationCallback = $callback;
100  }
101 
105  public function checkTemplateLinks() {
106  $this->numTemplateLinks = $this->backlinkCache->getNumLinks( 'templatelinks' );
107  }
108 
114  public function triggerCategoryAddedNotification( Title $categoryTitle ) {
115  $this->createRecentChangesEntry( $categoryTitle, self::CATEGORY_ADDITION );
116  }
117 
123  public function triggerCategoryRemovedNotification( Title $categoryTitle ) {
124  $this->createRecentChangesEntry( $categoryTitle, self::CATEGORY_REMOVAL );
125  }
126 
133  private function createRecentChangesEntry( Title $categoryTitle, $type ) {
134  $this->notifyCategorization(
135  $this->timestamp,
136  $categoryTitle,
137  $this->getUser(),
138  $this->getChangeMessageText(
139  $type,
140  $this->pageTitle->getPrefixedText(),
141  $this->numTemplateLinks
142  ),
143  $this->pageTitle,
144  $this->getPreviousRevisionTimestamp(),
145  $this->revision,
146  $type === self::CATEGORY_ADDITION
147  );
148  }
149 
160  private function notifyCategorization(
161  $timestamp,
162  Title $categoryTitle,
163  ?UserIdentity $user,
164  $comment,
165  Title $pageTitle,
166  $lastTimestamp,
167  $revision,
168  $added
169  ) {
170  $deleted = $revision ? $revision->getVisibility() & RevisionRecord::SUPPRESSED_USER : 0;
171  $newRevId = $revision ? $revision->getId() : 0;
172 
178  $bot = 1;
179  $lastRevId = 0;
180  $ip = '';
181 
182  # If no revision is given, the change was probably triggered by parser functions
183  if ( $revision !== null ) {
184  $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
185 
186  $correspondingRc = $revisionStore->getRecentChange( $this->revision ) ??
187  $revisionStore->getRecentChange( $this->revision, RevisionStore::READ_LATEST );
188  if ( $correspondingRc !== null ) {
189  $bot = $correspondingRc->getAttribute( 'rc_bot' ) ?: 0;
190  $ip = $correspondingRc->getAttribute( 'rc_ip' ) ?: '';
191  $lastRevId = $correspondingRc->getAttribute( 'rc_last_oldid' ) ?: 0;
192  }
193  }
194 
196  $rc = ( $this->newForCategorizationCallback )(
197  $timestamp,
198  $categoryTitle,
199  $user,
200  $comment,
201  $pageTitle,
202  $lastRevId,
203  $newRevId,
204  $lastTimestamp,
205  $bot,
206  $ip,
207  $deleted,
208  $added
209  );
210  $rc->save();
211  }
212 
224  private function getUser(): ?UserIdentity {
225  if ( $this->revision ) {
226  $user = $this->revision->getUser( RevisionRecord::RAW );
227  if ( $user ) {
228  return $user;
229  }
230  }
231 
232  $username = wfMessage( 'autochange-username' )->inContentLanguage()->text();
233 
234  $user = User::newSystemUser( $username );
235  if ( $user && !$user->isRegistered() ) {
236  $user->addToDatabase();
237  }
238 
239  return $user ?: null;
240  }
241 
258  private function getChangeMessageText( $type, $prefixedText, $numTemplateLinks ) {
259  $array = [
260  self::CATEGORY_ADDITION => 'recentchanges-page-added-to-category',
261  self::CATEGORY_REMOVAL => 'recentchanges-page-removed-from-category',
262  ];
263 
264  $msgKey = $array[$type];
265 
266  if ( intval( $numTemplateLinks ) > 0 ) {
267  $msgKey .= '-bundled';
268  }
269 
270  return wfMessage( $msgKey, $prefixedText )->inContentLanguage()->text();
271  }
272 
279  private function getPreviousRevisionTimestamp() {
280  $rl = MediaWikiServices::getInstance()->getRevisionLookup();
281  $latestRev = $rl->getRevisionByTitle( $this->pageTitle );
282  if ( $latestRev ) {
283  $previousRev = $rl->getPreviousRevision( $latestRev );
284  if ( $previousRev ) {
285  return $previousRev->getTimestamp();
286  }
287  }
288  return null;
289  }
290 
291 }
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
Definition: WebStart.php:88
Class for fetching backlink lists, approximate backlink counts and partitions.
triggerCategoryRemovedNotification(Title $categoryTitle)
Create a recentchanges entry for category removals.
triggerCategoryAddedNotification(Title $categoryTitle)
Create a recentchanges entry for category additions.
overrideNewForCategorizationCallback(callable $callback)
Overrides the default new for categorization callback This is intended for use while testing and will...
__construct(Title $pageTitle, BacklinkCache $backlinkCache, RevisionRecord $revision=null)
checkTemplateLinks()
Determines the number of template links for recursive link updates.
Service locator for MediaWiki core services.
Page revision base class.
getVisibility()
Get the deletion bitfield of the revision.
getTimestamp()
MCR migration note: this replaced Revision::getTimestamp.
getId( $wikiId=self::LOCAL)
Get revision ID.
Service for looking up page revisions.
Represents a title within MediaWiki.
Definition: Title.php:76
internal since 1.36
Definition: User.php:98
Interface for objects representing user identity.
isRegistered()
This must be equivalent to getId() != 0 and is provided for code readability.