MediaWiki  master
TrackingCategories.php
Go to the documentation of this file.
1 <?php
26 use Psr\Log\LoggerInterface;
27 
34 
38  public const CONSTRUCTOR_OPTIONS = [
39  MainConfigNames::TrackingCategories,
40  MainConfigNames::EnableMagicLinks,
41  ];
42 
44  private $options;
45 
47  private $namespaceInfo;
48 
50  private $titleParser;
51 
53  private $extensionRegistry;
54 
56  private $logger;
57 
63  private const CORE_TRACKING_CATEGORIES = [
64  'broken-file-category',
65  'duplicate-args-category',
66  'expansion-depth-exceeded-category',
67  'expensive-parserfunction-category',
68  'hidden-category-category',
69  'index-category',
70  'node-count-exceeded-category',
71  'noindex-category',
72  'nonnumeric-formatnum',
73  'post-expand-template-argument-category',
74  'post-expand-template-inclusion-category',
75  'restricted-displaytitle-ignored',
76  # template-equals-category is unused in MW>=1.39, but the category
77  # can be left around for a major release or so for an easier
78  # transition for anyone who didn't do the cleanup. T91154
79  'template-equals-category',
80  'template-loop-category',
81  'unstrip-depth-category',
82  'unstrip-size-category',
83  ];
84 
91  public function __construct(
92  ServiceOptions $options,
93  NamespaceInfo $namespaceInfo,
94  TitleParser $titleParser,
95  LoggerInterface $logger
96  ) {
97  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
98  $this->options = $options;
99  $this->namespaceInfo = $namespaceInfo;
100  $this->titleParser = $titleParser;
101  $this->logger = $logger;
102 
103  // TODO convert ExtensionRegistry to a service and inject it
104  $this->extensionRegistry = ExtensionRegistry::getInstance();
105  }
106 
117  public function getTrackingCategories() {
118  $categories = array_merge(
119  self::CORE_TRACKING_CATEGORIES,
120  $this->extensionRegistry->getAttribute( MainConfigNames::TrackingCategories ),
121  $this->options->get( MainConfigNames::TrackingCategories ) // deprecated
122  );
123 
124  // Only show magic link tracking categories if they are enabled
125  $enableMagicLinks = $this->options->get( MainConfigNames::EnableMagicLinks );
126  if ( $enableMagicLinks['ISBN'] ) {
127  $categories[] = 'magiclink-tracking-isbn';
128  }
129  if ( $enableMagicLinks['RFC'] ) {
130  $categories[] = 'magiclink-tracking-rfc';
131  }
132  if ( $enableMagicLinks['PMID'] ) {
133  $categories[] = 'magiclink-tracking-pmid';
134  }
135 
136  $trackingCategories = [];
137  foreach ( $categories as $catMsg ) {
138  /*
139  * Check if the tracking category varies by namespace
140  * Otherwise only pages in the current namespace will be displayed
141  * If it does vary, show pages considering all namespaces
142  *
143  * TODO replace uses of wfMessage with an injected service once that is available
144  */
145  $msgObj = wfMessage( $catMsg )->inContentLanguage();
146  $allCats = [];
147  $catMsgTitle = $this->titleParser->makeTitleValueSafe( NS_MEDIAWIKI, $catMsg );
148  if ( !$catMsgTitle ) {
149  continue;
150  }
151 
152  // Match things like {{NAMESPACE}} and {{NAMESPACENUMBER}}.
153  // False positives are ok, this is just an efficiency shortcut
154  if ( strpos( $msgObj->plain(), '{{' ) !== false ) {
155  $ns = $this->namespaceInfo->getValidNamespaces();
156  foreach ( $ns as $namesp ) {
157  $tempTitle = $this->titleParser->makeTitleValueSafe( $namesp, $catMsg );
158  if ( !$tempTitle ) {
159  continue;
160  }
161  // XXX: should be a better way to convert a TitleValue
162  // to a PageReference!
163  $tempTitle = Title::newFromLinkTarget( $tempTitle );
164  $catName = $msgObj->page( $tempTitle )->text();
165  # Allow tracking categories to be disabled by setting them to "-"
166  if ( $catName !== '-' ) {
167  $catTitle = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $catName );
168  if ( $catTitle ) {
169  $allCats[] = $catTitle;
170  }
171  }
172  }
173  } else {
174  $catName = $msgObj->text();
175  # Allow tracking categories to be disabled by setting them to "-"
176  if ( $catName !== '-' ) {
177  $catTitle = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $catName );
178  if ( $catTitle ) {
179  $allCats[] = $catTitle;
180  }
181  }
182  }
183  $trackingCategories[$catMsg] = [
184  'cats' => $allCats,
185  'msg' => $catMsgTitle,
186  ];
187  }
188 
189  return $trackingCategories;
190  }
191 
200  public function resolveTrackingCategory( string $msg, ?PageReference $contextPage ): ?LinkTarget {
201  if ( !$contextPage ) {
202  $this->logger->debug( "Not adding tracking category $msg to missing page!" );
203  return null;
204  }
205 
206  if ( $contextPage->getNamespace() === NS_SPECIAL ) {
207  $this->logger->debug( "Not adding tracking category $msg to special page!" );
208  return null;
209  }
210 
211  // Important to parse with correct title (T33469)
212  // TODO replace uses of wfMessage with an injected service once that is available
213  $cat = wfMessage( $msg )
214  ->page( $contextPage )
215  ->inContentLanguage()
216  ->text();
217 
218  # Allow tracking categories to be disabled by setting them to "-"
219  if ( $cat === '-' ) {
220  return null;
221  }
222 
223  $containerCategory = $this->titleParser->makeTitleValueSafe( NS_CATEGORY, $cat );
224  if ( $containerCategory === null ) {
225  $this->logger->debug( "[[MediaWiki:$msg]] is not a valid title!" );
226  return null;
227  }
228  return $containerCategory;
229  }
230 
239  public function addTrackingCategory( ParserOutput $parserOutput, string $msg, ?PageReference $contextPage ): bool {
240  $categoryPage = $this->resolveTrackingCategory( $msg, $contextPage );
241  if ( $categoryPage === null ) {
242  return false;
243  }
244  $parserOutput->addCategory(
245  $categoryPage->getDBkey(),
246  $parserOutput->getPageProperty( 'defaultsort' ) ?? ''
247  );
248  return true;
249  }
250 }
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'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
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.
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.
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:282
This class performs some operations related to tracking categories, such as creating a list of all su...
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
getNamespace()
Returns the page's namespace number.
A title parser service for MediaWiki.
Definition: TitleParser.php:33