MediaWiki  master
PageProps.php
Go to the documentation of this file.
1 <?php
22 use Wikimedia\ScopedCallback;
23 
29 class PageProps {
30 
34  private static $instance;
35 
50  public static function overrideInstance( PageProps $store = null ) {
51  if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
52  throw new MWException(
53  'Cannot override ' . __CLASS__ . 'default instance in operation.'
54  );
55  }
56  $previousValue = self::$instance;
57  self::$instance = $store;
58  return new ScopedCallback( function () use ( $previousValue ) {
59  self::$instance = $previousValue;
60  } );
61  }
62 
66  public static function getInstance() {
67  if ( self::$instance === null ) {
68  self::$instance = new self();
69  }
70  return self::$instance;
71  }
72 
74  private const CACHE_TTL = 10; // integer; TTL in seconds
75  private const CACHE_SIZE = 100; // integer; max cached pages
76 
78  private $cache = null;
79 
83  private function __construct() {
84  $this->cache = new MapCacheLRU( self::CACHE_SIZE );
85  }
86 
91  public function ensureCacheSize( $size ) {
92  if ( $this->cache->getMaxSize() < $size ) {
93  $this->cache->setMaxSize( $size );
94  }
95  }
96 
115  public function getProperties( $titles, $propertyNames ) {
116  if ( is_array( $propertyNames ) ) {
117  $gotArray = true;
118  } else {
119  $propertyNames = [ $propertyNames ];
120  $gotArray = false;
121  }
122 
123  $values = [];
124  $goodIDs = $this->getGoodIDs( $titles );
125  $queryIDs = [];
126  foreach ( $goodIDs as $pageID ) {
127  foreach ( $propertyNames as $propertyName ) {
128  $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
129  if ( $propertyValue === false ) {
130  $queryIDs[] = $pageID;
131  break;
132  } elseif ( $gotArray ) {
133  $values[$pageID][$propertyName] = $propertyValue;
134  } else {
135  $values[$pageID] = $propertyValue;
136  }
137  }
138  }
139 
140  if ( $queryIDs ) {
141  $dbr = wfGetDB( DB_REPLICA );
142  $result = $dbr->select(
143  'page_props',
144  [
145  'pp_page',
146  'pp_propname',
147  'pp_value'
148  ],
149  [
150  'pp_page' => $queryIDs,
151  'pp_propname' => $propertyNames
152  ],
153  __METHOD__
154  );
155 
156  foreach ( $result as $row ) {
157  $pageID = $row->pp_page;
158  $propertyName = $row->pp_propname;
159  $propertyValue = $row->pp_value;
160  $this->cacheProperty( $pageID, $propertyName, $propertyValue );
161  if ( $gotArray ) {
162  $values[$pageID][$propertyName] = $propertyValue;
163  } else {
164  $values[$pageID] = $propertyValue;
165  }
166  }
167  }
168 
169  return $values;
170  }
171 
185  public function getAllProperties( $titles ) {
186  $values = [];
187  $goodIDs = $this->getGoodIDs( $titles );
188  $queryIDs = [];
189  foreach ( $goodIDs as $pageID ) {
190  $pageProperties = $this->getCachedProperties( $pageID );
191  if ( $pageProperties === false ) {
192  $queryIDs[] = $pageID;
193  } else {
194  $values[$pageID] = $pageProperties;
195  }
196  }
197 
198  if ( $queryIDs != [] ) {
199  $dbr = wfGetDB( DB_REPLICA );
200  $result = $dbr->select(
201  'page_props',
202  [
203  'pp_page',
204  'pp_propname',
205  'pp_value'
206  ],
207  [
208  'pp_page' => $queryIDs,
209  ],
210  __METHOD__
211  );
212 
213  $currentPageID = 0;
214  $pageProperties = [];
215  foreach ( $result as $row ) {
216  $pageID = $row->pp_page;
217  if ( $currentPageID != $pageID ) {
218  if ( $pageProperties ) {
219  // @phan-suppress-next-line PhanTypeMismatchArgument False positive
220  $this->cacheProperties( $currentPageID, $pageProperties );
221  $values[$currentPageID] = $pageProperties;
222  }
223  $currentPageID = $pageID;
224  $pageProperties = [];
225  }
226  $pageProperties[$row->pp_propname] = $row->pp_value;
227  }
228  if ( $pageProperties != [] ) {
229  $this->cacheProperties( $pageID, $pageProperties );
230  $values[$pageID] = $pageProperties;
231  }
232  }
233 
234  return $values;
235  }
236 
241  private function getGoodIDs( $titles ) {
242  $result = [];
243  if ( is_array( $titles ) ) {
244  ( new LinkBatch( $titles ) )->execute();
245 
246  foreach ( $titles as $title ) {
247  $pageID = $title->getArticleID();
248  if ( $pageID > 0 ) {
249  $result[] = $pageID;
250  }
251  }
252  } else {
253  $pageID = $titles->getArticleID();
254  if ( $pageID > 0 ) {
255  $result[] = $pageID;
256  }
257  }
258  return $result;
259  }
260 
268  private function getCachedProperty( $pageID, $propertyName ) {
269  if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
270  return $this->cache->getField( $pageID, $propertyName );
271  }
272  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
273  $pageProperties = $this->cache->getField( 0, $pageID );
274  if ( isset( $pageProperties[$propertyName] ) ) {
275  return $pageProperties[$propertyName];
276  }
277  }
278  return false;
279  }
280 
287  private function getCachedProperties( $pageID ) {
288  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
289  return $this->cache->getField( 0, $pageID );
290  }
291  return false;
292  }
293 
301  private function cacheProperty( $pageID, $propertyName, $propertyValue ) {
302  $this->cache->setField( $pageID, $propertyName, $propertyValue );
303  }
304 
311  private function cacheProperties( $pageID, $pageProperties ) {
312  $this->cache->clear( $pageID );
313  $this->cache->setField( 0, $pageID, $pageProperties );
314  }
315 }
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:35
PageProps\getProperties
getProperties( $titles, $propertyNames)
Given one or more Titles and one or more names of properties, returns an associative array mapping pa...
Definition: PageProps.php:115
PageProps\getCachedProperty
getCachedProperty( $pageID, $propertyName)
Get a property from the cache.
Definition: PageProps.php:268
$dbr
$dbr
Definition: testCompression.php:54
MWException
MediaWiki exception.
Definition: MWException.php:26
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2463
PageProps\getInstance
static getInstance()
Definition: PageProps.php:66
PageProps\overrideInstance
static overrideInstance(PageProps $store=null)
Overrides the default instance of this class This is intended for use while testing and will fail if ...
Definition: PageProps.php:50
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:38
$title
$title
Definition: testCompression.php:38
PageProps\__construct
__construct()
Create a PageProps object.
Definition: PageProps.php:83
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
PageProps\getGoodIDs
getGoodIDs( $titles)
Definition: PageProps.php:241
PageProps\$instance
static PageProps $instance
Definition: PageProps.php:34
PageProps\CACHE_TTL
const CACHE_TTL
Cache parameters.
Definition: PageProps.php:74
PageProps\getAllProperties
getAllProperties( $titles)
Get all page property values.
Definition: PageProps.php:185
PageProps\CACHE_SIZE
const CACHE_SIZE
Definition: PageProps.php:75
PageProps\cacheProperty
cacheProperty( $pageID, $propertyName, $propertyValue)
Save a property to the cache.
Definition: PageProps.php:301
PageProps\ensureCacheSize
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition: PageProps.php:91
PageProps
Gives access to properties of a page.
Definition: PageProps.php:29
PageProps\getCachedProperties
getCachedProperties( $pageID)
Get properties from the cache.
Definition: PageProps.php:287
PageProps\$cache
$cache
Property cache.
Definition: PageProps.php:78
PageProps\cacheProperties
cacheProperties( $pageID, $pageProperties)
Save properties to the cache.
Definition: PageProps.php:311