MediaWiki  1.31.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->getCheckKey() );
52  }
53 
54  private function getCheckKey() {
55  return wfMemcKey( 'gadgets-definition', Gadget::GADGET_CLASS_VERSION, self::CACHE_VERSION );
56  }
57 
64  protected function loadGadgets() {
65  if ( $this->definitionCache !== null ) {
66  return $this->definitionCache; // process cache hit
67  }
68 
69  // Ideally $t1Cache is APC, and $wanCache is memcached
70  $t1Cache = ObjectCache::getLocalServerInstance( 'hash' );
71  $wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
72 
73  $key = $this->getCheckKey();
74 
75  // (a) Check the tier 1 cache
76  $value = $t1Cache->get( $key );
77  // Check if it passes a blind TTL check (avoids I/O)
78  if ( $value && ( microtime( true ) - $value['time'] ) < 10 ) {
79  $this->definitionCache = $value['gadgets']; // process cache
81  }
82  // Cache generated after the "check" time should be up-to-date
83  $ckTime = $wanCache->getCheckKeyTime( $key ) + WANObjectCache::HOLDOFF_TTL;
84  if ( $value && $value['time'] > $ckTime ) {
85  $this->definitionCache = $value['gadgets']; // process cache
87  }
88 
89  // (b) Fetch value from WAN cache or regenerate if needed.
90  // This is hit occasionally and more so when the list changes.
91  $us = $this;
92  $value = $wanCache->getWithSetCallback(
93  $key,
95  function ( $old, &$ttl, &$setOpts ) use ( $us ) {
96  $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
97 
98  $now = microtime( true );
99  $gadgets = $us->fetchStructuredList();
100  if ( $gadgets === false ) {
102  }
103 
104  return [ 'gadgets' => $gadgets, 'time' => $now ];
105  },
106  [ 'checkKeys' => [ $key ], 'lockTSE' => 300 ]
107  );
108 
109  // Update the tier 1 cache as needed
110  if ( $value['gadgets'] !== false && $value['time'] > $ckTime ) {
111  // Set a modest TTL to keep the WAN key in cache
112  $t1Cache->set( $key, $value, mt_rand( 300, 600 ) );
113  }
114 
115  $this->definitionCache = $value['gadgets'];
116 
117  return $this->definitionCache;
118  }
119 
126  public function fetchStructuredList( $forceNewText = null ) {
127  if ( $forceNewText === null ) {
128  // T157210: avoid using wfMessage() to avoid staleness due to cache layering
129  $title = Title::makeTitle( NS_MEDIAWIKI, 'Gadgets-definition' );
131  if ( !$rev || !$rev->getContent() || $rev->getContent()->isEmpty() ) {
132  return false; // don't cache
133  }
134 
135  $g = $rev->getContent()->getNativeData();
136  } else {
137  $g = $forceNewText;
138  }
139 
140  $gadgets = $this->listFromDefinition( $g );
141  if ( !count( $gadgets ) ) {
142  return false; // don't cache; Bug 37228
143  }
144 
145  $source = $forceNewText !== null ? 'input text' : 'MediaWiki:Gadgets-definition';
146  wfDebug( __METHOD__ . ": $source parsed, cache entry should be updated\n" );
147 
148  return $gadgets;
149  }
150 
157  private function listFromDefinition( $definition ) {
158  $definition = preg_replace( '/<!--.*?-->/s', '', $definition );
159  $lines = preg_split( '/(\r\n|\r|\n)+/', $definition );
160 
161  $gadgets = [];
162  $section = '';
163 
164  foreach ( $lines as $line ) {
165  $m = [];
166  if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', $line, $m ) ) {
167  $section = $m[1];
168  } else {
169  $gadget = $this->newFromDefinition( $line, $section );
170  if ( $gadget ) {
171  $gadgets[$gadget->getName()] = $gadget;
172  }
173  }
174  }
175 
176  return $gadgets;
177  }
178 
185  public function newFromDefinition( $definition, $category ) {
186  $m = [];
187  if ( !preg_match(
188  '/^\*+ *([a-zA-Z](?:[-_:.\w\d ]*[a-zA-Z0-9])?)(\s*\[.*?\])?\s*((\|[^|]*)+)\s*$/',
189  $definition,
190  $m
191  ) ) {
192  return false;
193  }
194  // NOTE: the gadget name is used as part of the name of a form field,
195  // and must follow the rules defined in https://www.w3.org/TR/html4/types.html#type-cdata
196  // Also, title-normalization applies.
197  $info = [ 'category' => $category ];
198  $info['name'] = trim( str_replace( ' ', '_', $m[1] ) );
199  // If the name is too long, then RL will throw an MWException when
200  // we try to register the module
201  if ( !Gadget::isValidGadgetID( $info['name'] ) ) {
202  return false;
203  }
204  $info['definition'] = $definition;
205  $options = trim( $m[2], ' []' );
206 
207  foreach ( preg_split( '/\s*\|\s*/', $options, -1, PREG_SPLIT_NO_EMPTY ) as $option ) {
208  $arr = preg_split( '/\s*=\s*/', $option, 2 );
209  $option = $arr[0];
210  if ( isset( $arr[1] ) ) {
211  $params = explode( ',', $arr[1] );
212  $params = array_map( 'trim', $params );
213  } else {
214  $params = [];
215  }
216 
217  switch ( $option ) {
218  case 'ResourceLoader':
219  $info['resourceLoaded'] = true;
220  break;
221  case 'dependencies':
222  $info['dependencies'] = $params;
223  break;
224  case 'peers':
225  $info['peers'] = $params;
226  break;
227  case 'rights':
228  $info['requiredRights'] = $params;
229  break;
230  case 'hidden':
231  $info['hidden'] = true;
232  break;
233  case 'skins':
234  $info['requiredSkins'] = $params;
235  break;
236  case 'default':
237  $info['onByDefault'] = true;
238  break;
239  case 'targets':
240  $info['targets'] = $params;
241  break;
242  case 'type':
243  // Single value, not a list
244  $info['type'] = isset( $params[0] ) ? $params[0] : '';
245  break;
246  }
247  }
248 
249  foreach ( preg_split( '/\s*\|\s*/', $m[3], -1, PREG_SPLIT_NO_EMPTY ) as $page ) {
250  $page = "MediaWiki:Gadget-$page";
251 
252  if ( preg_match( '/\.js/', $page ) ) {
253  $info['scripts'][] = $page;
254  } elseif ( preg_match( '/\.css/', $page ) ) {
255  $info['styles'][] = $page;
256  }
257  }
258 
259  return new Gadget( $info );
260  }
261 }
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:148
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
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
$params
$params
Definition: styleTest.css.php:40
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
wfMemcKey
wfMemcKey()
Make a cache key for the local wiki.
Definition: GlobalFunctions.php:2700
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2800
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:534
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:126
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:982
MediaWikiGadgetsDefinitionRepo\listFromDefinition
listFromDefinition( $definition)
Generates a structured list of Gadget objects from a definition.
Definition: MediaWikiGadgetsDefinitionRepo.php:157
$line
$line
Definition: cdb.php:59
$value
$value
Definition: styleTest.css.php:45
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:185
MediaWikiGadgetsDefinitionRepo\getCheckKey
getCheckKey()
Definition: MediaWikiGadgetsDefinitionRepo.php:54
MediaWikiGadgetsDefinitionRepo\fetchStructuredList
fetchStructuredList( $forceNewText=null)
Fetch list of gadgets and returns it as associative array of sections with gadgets e....
Definition: MediaWikiGadgetsDefinitionRepo.php:126
$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:1987
$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:3005
$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:1767
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:73
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:64
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
ObjectCache\getLocalServerInstance
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
Definition: ObjectCache.php:288