MediaWiki  master
TrackingCategories.php
Go to the documentation of this file.
1 <?php
22 namespace MediaWiki\Category;
23 
30 use NamespaceInfo;
31 use ParserOutput;
32 use Psr\Log\LoggerInterface;
33 use TitleParser;
34 
41 
45  public const CONSTRUCTOR_OPTIONS = [
48  ];
49 
51  private $options;
52 
54  private $namespaceInfo;
55 
57  private $titleParser;
58 
60  private $extensionRegistry;
61 
63  private $logger;
64 
70  private const CORE_TRACKING_CATEGORIES = [
71  'broken-file-category',
72  'duplicate-args-category',
73  'expansion-depth-exceeded-category',
74  'expensive-parserfunction-category',
75  'hidden-category-category',
76  'index-category',
77  'node-count-exceeded-category',
78  'noindex-category',
79  'nonnumeric-formatnum',
80  'post-expand-template-argument-category',
81  'post-expand-template-inclusion-category',
82  'restricted-displaytitle-ignored',
83  # template-equals-category is unused in MW>=1.39, but the category
84  # can be left around for a major release or so for an easier
85  # transition for anyone who didn't do the cleanup. T91154
86  'template-equals-category',
87  'template-loop-category',
88  'unstrip-depth-category',
89  'unstrip-size-category',
90  ];
91 
98  public function __construct(
99  ServiceOptions $options,
100  NamespaceInfo $namespaceInfo,
101  TitleParser $titleParser,
102  LoggerInterface $logger
103  ) {
104  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
105  $this->options = $options;
106  $this->namespaceInfo = $namespaceInfo;
107  $this->titleParser = $titleParser;
108  $this->logger = $logger;
109 
110  // TODO convert ExtensionRegistry to a service and inject it
111  $this->extensionRegistry = ExtensionRegistry::getInstance();
112  }
113 
124  public function getTrackingCategories() {
125  $categories = array_merge(
126  self::CORE_TRACKING_CATEGORIES,
127  $this->extensionRegistry->getAttribute( MainConfigNames::TrackingCategories ),
128  $this->options->get( MainConfigNames::TrackingCategories ) // deprecated
129  );
130 
131  // Only show magic link tracking categories if they are enabled
132  $enableMagicLinks = $this->options->get( MainConfigNames::EnableMagicLinks );
133  if ( $enableMagicLinks['ISBN'] ) {
134  $categories[] = 'magiclink-tracking-isbn';
135  }
136  if ( $enableMagicLinks['RFC'] ) {
137  $categories[] = 'magiclink-tracking-rfc';
138  }
139  if ( $enableMagicLinks['PMID'] ) {
140  $categories[] = 'magiclink-tracking-pmid';
141  }
142 
143  $trackingCategories = [];
144  foreach ( $categories as $catMsg ) {
145  /*
146  * Check if the tracking category varies by namespace
147  * Otherwise only pages in the current namespace will be displayed
148  * If it does vary, show pages considering all namespaces
149  *
150  * TODO replace uses of wfMessage with an injected service once that is available
151  */
152  $msgObj = wfMessage( $catMsg )->inContentLanguage();
153  $allCats = [];
154  $catMsgTitle = $this->titleParser->makeTitleValueSafe( NS_MEDIAWIKI, $catMsg );
155  if ( !$catMsgTitle ) {
156  continue;
157  }
158 
159  // Match things like {{NAMESPACE}} and {{NAMESPACENUMBER}}.
160  // False positives are ok, this is just an efficiency shortcut
161  if ( strpos( $msgObj->plain(), '{{' ) !== false ) {
162  $ns = $this->namespaceInfo->getValidNamespaces();
163  foreach ( $ns as $namesp ) {
164  $tempTitle = $this->titleParser->makeTitleValueSafe( $namesp, $catMsg );
165  if ( !$tempTitle ) {
166  continue;
167  }
168  // XXX: should be a better way to convert a TitleValue
169  // to a PageReference!
170  $tempTitle = Title::newFromLinkTarget( $tempTitle );
171  $catName = $msgObj->page( $tempTitle )->text();
172  # Allow tracking categories to be disabled by setting them to "-"
173  if ( $catName !== '-' ) {
174  $catTitle = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $catName );
175  if ( $catTitle ) {
176  $allCats[] = $catTitle;
177  }
178  }
179  }
180  } else {
181  $catName = $msgObj->text();
182  # Allow tracking categories to be disabled by setting them to "-"
183  if ( $catName !== '-' ) {
184  $catTitle = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $catName );
185  if ( $catTitle ) {
186  $allCats[] = $catTitle;
187  }
188  }
189  }
190  $trackingCategories[$catMsg] = [
191  'cats' => $allCats,
192  'msg' => $catMsgTitle,
193  ];
194  }
195 
196  return $trackingCategories;
197  }
198 
207  public function resolveTrackingCategory( string $msg, ?PageReference $contextPage ): ?LinkTarget {
208  if ( !$contextPage ) {
209  $this->logger->debug( "Not adding tracking category $msg to missing page!" );
210  return null;
211  }
212 
213  if ( $contextPage->getNamespace() === NS_SPECIAL ) {
214  $this->logger->debug( "Not adding tracking category $msg to special page!" );
215  return null;
216  }
217 
218  // Important to parse with correct title (T33469)
219  // TODO replace uses of wfMessage with an injected service once that is available
220  $cat = wfMessage( $msg )
221  ->page( $contextPage )
222  ->inContentLanguage()
223  ->text();
224 
225  # Allow tracking categories to be disabled by setting them to "-"
226  if ( $cat === '-' ) {
227  return null;
228  }
229 
230  $containerCategory = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $cat );
231  if ( $containerCategory === null ) {
232  $this->logger->debug( "[[MediaWiki:$msg]] is not a valid title!" );
233  return null;
234  }
235  return $containerCategory;
236  }
237 
246  public function addTrackingCategory( ParserOutput $parserOutput, string $msg, ?PageReference $contextPage ): bool {
247  $categoryPage = $this->resolveTrackingCategory( $msg, $contextPage );
248  if ( $categoryPage === null ) {
249  return false;
250  }
251  $parserOutput->addCategory(
252  $categoryPage->getDBkey(),
253  $parserOutput->getPageProperty( 'defaultsort' ) ?? ''
254  );
255  return true;
256  }
257 }
258 
259 class_alias( TrackingCategories::class, 'TrackingCategories' );
const NS_MEDIAWIKI
Definition: Defines.php:72
const NS_SPECIAL
Definition: Defines.php:53
const NS_CATEGORY
Definition: Defines.php:78
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
Definition: WebStart.php:88
Load JSON files, and uses a Processor to extract information.
This class performs some operations related to tracking categories, such as creating a list of all su...
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
A class containing constants representing the names of configuration variables.
const EnableMagicLinks
Name constant for the EnableMagicLinks setting, for use with Config::get()
const TrackingCategories
Name constant for the TrackingCategories setting, for use with Config::get()
Represents a title within MediaWiki.
Definition: Title.php:82
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:315
__construct(IContextSource $context=null)
Definition: MediaWiki.php:63
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
getPageProperty(string $name)
Look up a page property.
addCategory( $c, $sort='')
Add a category.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
A title parser service for MediaWiki.
Definition: TitleParser.php:33
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...