MediaWiki  1.32.0
MediaWikiGadgetsDefinitionRepo.php
Go to the documentation of this file.
1 <?php
2 
6 
11  const CACHE_VERSION = 2;
12 
14 
21  public function getGadget( $id ) {
22  $gadgets = $this->loadGadgets();
23  if ( !isset( $gadgets[$id] ) ) {
24  throw new InvalidArgumentException( "No gadget registered for '$id'" );
25  }
26 
27  return $gadgets[$id];
28  }
29 
30  public function getGadgetIds() {
31  $gadgets = $this->loadGadgets();
32  if ( $gadgets ) {
33  return array_keys( $gadgets );
34  } else {
35  return [];
36  }
37  }
38 
39  public function handlePageUpdate( LinkTarget $target ) {
40  if ( $target->getNamespace() == NS_MEDIAWIKI && $target->getText() == 'Gadgets-definition' ) {
41  $this->purgeDefinitionCache();
42  }
43  }
44 
49  private function purgeDefinitionCache() {
50  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
51  $cache->touchCheckKey( $this->getDefinitionCacheKey() );
52  }
53 
54  private function getDefinitionCacheKey() {
55  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
56 
57  return $cache->makeKey(
58  'gadgets-definition',
60  self::CACHE_VERSION
61  );
62  }
63 
70  protected function loadGadgets() {
71  if ( $this->definitionCache !== null ) {
72  return $this->definitionCache; // process cache hit
73  }
74 
75  // Ideally $t1Cache is APC, and $wanCache is memcached
76  $t1Cache = ObjectCache::getLocalServerInstance( 'hash' );
77  $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
78 
79  $key = $this->getDefinitionCacheKey();
80 
81  // (a) Check the tier 1 cache
82  $value = $t1Cache->get( $key );
83  // Check if it passes a blind TTL check (avoids I/O)
84  if ( $value && ( microtime( true ) - $value['time'] ) < 10 ) {
85  $this->definitionCache = $value['gadgets']; // process cache
87  }
88  // Cache generated after the "check" time should be up-to-date
89  $ckTime = $wanCache->getCheckKeyTime( $key ) + WANObjectCache::HOLDOFF_TTL;
90  if ( $value && $value['time'] > $ckTime ) {
91  $this->definitionCache = $value['gadgets']; // process cache
93  }
94 
95  // (b) Fetch value from WAN cache or regenerate if needed.
96  // This is hit occasionally and more so when the list changes.
97  $us = $this;
98  $value = $wanCache->getWithSetCallback(
99  $key,
101  function ( $old, &$ttl, &$setOpts ) use ( $us ) {
102  $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
103 
104  $now = microtime( true );
105  $gadgets = $us->fetchStructuredList();
106  if ( $gadgets === false ) {
108  }
109 
110  return [ 'gadgets' => $gadgets, 'time' => $now ];
111  },
112  [ 'checkKeys' => [ $key ], 'lockTSE' => 300 ]
113  );
114 
115  // Update the tier 1 cache as needed
116  if ( $value['gadgets'] !== false && $value['time'] > $ckTime ) {
117  // Set a modest TTL to keep the WAN key in cache
118  $t1Cache->set( $key, $value, mt_rand( 300, 600 ) );
119  }
120 
121  $this->definitionCache = $value['gadgets'];
122 
123  return $this->definitionCache;
124  }
125 
132  public function fetchStructuredList( $forceNewText = null ) {
133  if ( $forceNewText === null ) {
134  // T157210: avoid using wfMessage() to avoid staleness due to cache layering
135  $title = Title::makeTitle( NS_MEDIAWIKI, 'Gadgets-definition' );
137  if ( !$rev || !$rev->getContent() || $rev->getContent()->isEmpty() ) {
138  return false; // don't cache
139  }
140 
141  $g = $rev->getContent()->getNativeData();
142  } else {
143  $g = $forceNewText;
144  }
145 
146  $gadgets = $this->listFromDefinition( $g );
147  if ( !count( $gadgets ) ) {
148  return false; // don't cache; Bug 37228
149  }
150 
151  $source = $forceNewText !== null ? 'input text' : 'MediaWiki:Gadgets-definition';
152  wfDebug( __METHOD__ . ": $source parsed, cache entry should be updated\n" );
153 
154  return $gadgets;
155  }
156 
163  private function listFromDefinition( $definition ) {
164  $definition = preg_replace( '/<!--.*?-->/s', '', $definition );
165  $lines = preg_split( '/(\r\n|\r|\n)+/', $definition );
166 
167  $gadgets = [];
168  $section = '';
169 
170  foreach ( $lines as $line ) {
171  $m = [];
172  if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', $line, $m ) ) {
173  $section = $m[1];
174  } else {
175  $gadget = $this->newFromDefinition( $line, $section );
176  if ( $gadget ) {
177  $gadgets[$gadget->getName()] = $gadget;
178  }
179  }
180  }
181 
182  return $gadgets;
183  }
184 
191  public function newFromDefinition( $definition, $category ) {
192  $m = [];
193  if ( !preg_match(
194  '/^\*+ *([a-zA-Z](?:[-_:.\w\d ]*[a-zA-Z0-9])?)(\s*\[.*?\])?\s*((\|[^|]*)+)\s*$/',
195  $definition,
196  $m
197  ) ) {
198  return false;
199  }
200  // NOTE: the gadget name is used as part of the name of a form field,
201  // and must follow the rules defined in https://www.w3.org/TR/html4/types.html#type-cdata
202  // Also, title-normalization applies.
203  $info = [ 'category' => $category ];
204  $info['name'] = trim( str_replace( ' ', '_', $m[1] ) );
205  // If the name is too long, then RL will throw an MWException when
206  // we try to register the module
207  if ( !Gadget::isValidGadgetID( $info['name'] ) ) {
208  return false;
209  }
210  $info['definition'] = $definition;
211  $options = trim( $m[2], ' []' );
212 
213  foreach ( preg_split( '/\s*\|\s*/', $options, -1, PREG_SPLIT_NO_EMPTY ) as $option ) {
214  $arr = preg_split( '/\s*=\s*/', $option, 2 );
215  $option = $arr[0];
216  if ( isset( $arr[1] ) ) {
217  $params = explode( ',', $arr[1] );
218  $params = array_map( 'trim', $params );
219  } else {
220  $params = [];
221  }
222 
223  switch ( $option ) {
224  case 'ResourceLoader':
225  $info['resourceLoaded'] = true;
226  break;
227  case 'dependencies':
228  $info['dependencies'] = $params;
229  break;
230  case 'peers':
231  $info['peers'] = $params;
232  break;
233  case 'rights':
234  $info['requiredRights'] = $params;
235  break;
236  case 'hidden':
237  $info['hidden'] = true;
238  break;
239  case 'skins':
240  $info['requiredSkins'] = $params;
241  break;
242  case 'default':
243  $info['onByDefault'] = true;
244  break;
245  case 'targets':
246  $info['targets'] = $params;
247  break;
248  case 'type':
249  // Single value, not a list
250  $info['type'] = isset( $params[0] ) ? $params[0] : '';
251  break;
252  }
253  }
254 
255  foreach ( preg_split( '/\s*\|\s*/', $m[3], -1, PREG_SPLIT_NO_EMPTY ) as $page ) {
256  $page = "MediaWiki:Gadget-$page";
257 
258  if ( preg_match( '/\.js/', $page ) ) {
259  $info['scripts'][] = $page;
260  } elseif ( preg_match( '/\.css/', $page ) ) {
261  $info['styles'][] = $page;
262  }
263  }
264 
265  return new Gadget( $info );
266  }
267 }
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:48
MediaWiki\Linker\LinkTarget\getText
getText()
Returns the link in text form, without namespace prefix or fragment.
WANObjectCache\TTL_UNCACHEABLE
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
Definition: WANObjectCache.php:184
Gadget\CACHE_TTL
const CACHE_TTL
Definition: Gadget.php:23
captcha-old.count
count
Definition: captcha-old.py:249
MediaWikiGadgetsDefinitionRepo\purgeDefinitionCache
purgeDefinitionCache()
Purge the definitions cache, for example if MediaWiki:Gadgets-definition was edited.
Definition: MediaWikiGadgetsDefinitionRepo.php:49
MediaWikiGadgetsDefinitionRepo\getGadgetIds
getGadgetIds()
Get the ids of the gadgets provided by this repository.
Definition: MediaWikiGadgetsDefinitionRepo.php:30
$params
$params
Definition: styleTest.css.php:44
MediaWikiGadgetsDefinitionRepo
Gadgets repo powered by MediaWiki:Gadgets-definition.
Definition: MediaWikiGadgetsDefinitionRepo.php:10
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Revision\newFromTitle
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition: Revision.php:133
MediaWiki\Linker\LinkTarget\getNamespace
getNamespace()
Get the namespace index.
MediaWikiGadgetsDefinitionRepo\handlePageUpdate
handlePageUpdate(LinkTarget $target)
Given that the provided page was updated, invalidate caches if necessary.
Definition: MediaWikiGadgetsDefinitionRepo.php:39
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:964
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2693
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Gadget
Wrapper for one gadget.
Definition: Gadget.php:17
$lines
$lines
Definition: router.php:61
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:545
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
GadgetRepo
Definition: GadgetRepo.php:5
WANObjectCache\HOLDOFF_TTL
const HOLDOFF_TTL
Seconds to tombstone keys on delete()
Definition: WANObjectCache.php:162
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:988
MediaWikiGadgetsDefinitionRepo\listFromDefinition
listFromDefinition( $definition)
Generates a structured list of Gadget objects from a definition.
Definition: MediaWikiGadgetsDefinitionRepo.php:163
$line
$line
Definition: cdb.php:59
$value
$value
Definition: styleTest.css.php:49
Gadget\isValidGadgetID
static isValidGadgetID( $id)
Whether the provided gadget id is valid.
Definition: Gadget.php:114
MediaWikiGadgetsDefinitionRepo\newFromDefinition
newFromDefinition( $definition, $category)
Creates an instance of this class from definition in MediaWiki:Gadgets-definition.
Definition: MediaWikiGadgetsDefinitionRepo.php:191
MediaWikiGadgetsDefinitionRepo\fetchStructuredList
fetchStructuredList( $forceNewText=null)
Fetch list of gadgets and returns it as associative array of sections with gadgets e....
Definition: MediaWikiGadgetsDefinitionRepo.php:132
$cache
$cache
Definition: mcc.php:33
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:2036
$section
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition: hooks.txt:3090
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1808
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
$source
$source
Definition: mwdoc-filter.php:46
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:72
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
MediaWikiGadgetsDefinitionRepo\CACHE_VERSION
const CACHE_VERSION
Definition: MediaWikiGadgetsDefinitionRepo.php:11
MediaWikiGadgetsDefinitionRepo\getGadget
getGadget( $id)
Definition: MediaWikiGadgetsDefinitionRepo.php:21
MediaWikiGadgetsDefinitionRepo\loadGadgets
loadGadgets()
Loads list of gadgets and returns it as associative array of sections with gadgets e....
Definition: MediaWikiGadgetsDefinitionRepo.php:70
MediaWikiGadgetsDefinitionRepo\$definitionCache
$definitionCache
Definition: MediaWikiGadgetsDefinitionRepo.php:13
Gadget\GADGET_CLASS_VERSION
const GADGET_CLASS_VERSION
Increment this when changing class structure.
Definition: Gadget.php:21
MediaWikiGadgetsDefinitionRepo\getDefinitionCacheKey
getDefinitionCacheKey()
Definition: MediaWikiGadgetsDefinitionRepo.php:54
ObjectCache\getLocalServerInstance
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
Definition: ObjectCache.php:284