MediaWiki  master
PageProps.php
Go to the documentation of this file.
1 <?php
26 use Wikimedia\ScopedCallback;
27 
33 class PageProps {
34 
37 
39  private $loadBalancer;
40 
42  private const CACHE_TTL = 10; // integer; TTL in seconds
43  private const CACHE_SIZE = 100; // integer; max cached pages
44 
46  private $cache = null;
47 
60  public static function overrideInstance( PageProps $store ) {
61  if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
62  throw new MWException(
63  'Cannot override ' . __CLASS__ . 'default instance in operation.'
64  );
65  }
66 
67  MediaWikiServices::getInstance()->redefineService(
68  'PageProps',
69  function () use ( $store ) {
70  return $store;
71  }
72  );
73 
74  return new ScopedCallback( function () {
75  MediaWikiServices::getInstance()->resetServiceForTesting( 'PageProps' );
76  } );
77  }
78 
82  public static function getInstance() {
83  return MediaWikiServices::getInstance()->getPageProps();
84  }
85 
90  public function __construct(
93  ) {
94  $this->linkBatchFactory = $linkBatchFactory;
95  $this->loadBalancer = $loadBalancer;
96  $this->cache = new MapCacheLRU( self::CACHE_SIZE );
97  }
98 
103  public function ensureCacheSize( $size ) {
104  if ( $this->cache->getMaxSize() < $size ) {
105  $this->cache->setMaxSize( $size );
106  }
107  }
108 
127  public function getProperties( $titles, $propertyNames ) {
128  if ( is_array( $propertyNames ) ) {
129  $gotArray = true;
130  } else {
131  $propertyNames = [ $propertyNames ];
132  $gotArray = false;
133  }
134 
135  $values = [];
136  $goodIDs = $this->getGoodIDs( $titles );
137  $queryIDs = [];
138  foreach ( $goodIDs as $pageID ) {
139  foreach ( $propertyNames as $propertyName ) {
140  $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
141  if ( $propertyValue === false ) {
142  $queryIDs[] = $pageID;
143  break;
144  } elseif ( $gotArray ) {
145  $values[$pageID][$propertyName] = $propertyValue;
146  } else {
147  $values[$pageID] = $propertyValue;
148  }
149  }
150  }
151 
152  if ( $queryIDs ) {
153  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
154  $result = $dbr->select(
155  'page_props',
156  [
157  'pp_page',
158  'pp_propname',
159  'pp_value'
160  ],
161  [
162  'pp_page' => $queryIDs,
163  'pp_propname' => $propertyNames
164  ],
165  __METHOD__
166  );
167 
168  foreach ( $result as $row ) {
169  $pageID = $row->pp_page;
170  $propertyName = $row->pp_propname;
171  $propertyValue = $row->pp_value;
172  $this->cache->setField( $pageID, $propertyName, $propertyValue );
173  if ( $gotArray ) {
174  $values[$pageID][$propertyName] = $propertyValue;
175  } else {
176  $values[$pageID] = $propertyValue;
177  }
178  }
179  }
180 
181  return $values;
182  }
183 
197  public function getAllProperties( $titles ) {
198  $values = [];
199  $goodIDs = $this->getGoodIDs( $titles );
200  $queryIDs = [];
201  foreach ( $goodIDs as $pageID ) {
202  $pageProperties = $this->getCachedProperties( $pageID );
203  if ( $pageProperties === false ) {
204  $queryIDs[] = $pageID;
205  } else {
206  $values[$pageID] = $pageProperties;
207  }
208  }
209 
210  if ( $queryIDs != [] ) {
211  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
212  $result = $dbr->select(
213  'page_props',
214  [
215  'pp_page',
216  'pp_propname',
217  'pp_value'
218  ],
219  [
220  'pp_page' => $queryIDs,
221  ],
222  __METHOD__
223  );
224 
225  $currentPageID = 0;
226  $pageProperties = [];
227  foreach ( $result as $row ) {
228  $pageID = $row->pp_page;
229  if ( $currentPageID != $pageID ) {
230  if ( $pageProperties ) {
231  // @phan-suppress-next-line PhanTypeMismatchArgument False positive
232  $this->cacheProperties( $currentPageID, $pageProperties );
233  $values[$currentPageID] = $pageProperties;
234  }
235  $currentPageID = $pageID;
236  $pageProperties = [];
237  }
238  $pageProperties[$row->pp_propname] = $row->pp_value;
239  }
240  if ( $pageProperties != [] ) {
241  $this->cacheProperties( $pageID, $pageProperties );
242  $values[$pageID] = $pageProperties;
243  }
244  }
245 
246  return $values;
247  }
248 
253  private function getGoodIDs( $titles ) {
254  $result = [];
255  if ( is_iterable( $titles ) ) {
256  $this->linkBatchFactory->newLinkBatch( $titles )->execute();
257 
258  foreach ( $titles as $title ) {
259  $pageID = $title->getArticleID();
260  if ( $pageID > 0 ) {
261  $result[] = $pageID;
262  }
263  }
264  } else {
265  $pageID = $titles->getArticleID();
266  if ( $pageID > 0 ) {
267  $result[] = $pageID;
268  }
269  }
270  return $result;
271  }
272 
280  private function getCachedProperty( $pageID, $propertyName ) {
281  if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
282  return $this->cache->getField( $pageID, $propertyName );
283  }
284  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
285  $pageProperties = $this->cache->getField( 0, $pageID );
286  if ( isset( $pageProperties[$propertyName] ) ) {
287  return $pageProperties[$propertyName];
288  }
289  }
290  return false;
291  }
292 
299  private function getCachedProperties( $pageID ) {
300  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
301  return $this->cache->getField( 0, $pageID );
302  }
303  return false;
304  }
305 
312  private function cacheProperties( $pageID, $pageProperties ) {
313  $this->cache->clear( $pageID );
314  $this->cache->setField( 0, $pageID, $pageProperties );
315  }
316 }
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:166
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:127
PageProps\getCachedProperty
getCachedProperty( $pageID, $propertyName)
Get a property from the cache.
Definition: PageProps.php:280
$dbr
$dbr
Definition: testCompression.php:54
PageProps\$loadBalancer
ILoadBalancer $loadBalancer
Definition: PageProps.php:39
PageProps\overrideInstance
static overrideInstance(PageProps $store)
Overrides the default instance of this class This is intended for use while testing and will fail if ...
Definition: PageProps.php:60
PageProps\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: PageProps.php:36
MWException
MediaWiki exception.
Definition: MWException.php:29
PageProps\getInstance
static getInstance()
Definition: PageProps.php:82
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:38
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:37
$title
$title
Definition: testCompression.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
PageProps\getGoodIDs
getGoodIDs( $titles)
Definition: PageProps.php:253
PageProps\CACHE_TTL
const CACHE_TTL
Cache parameters.
Definition: PageProps.php:42
PageProps\getAllProperties
getAllProperties( $titles)
Get all page property values.
Definition: PageProps.php:197
PageProps\CACHE_SIZE
const CACHE_SIZE
Definition: PageProps.php:43
PageProps\__construct
__construct(LinkBatchFactory $linkBatchFactory, ILoadBalancer $loadBalancer)
Definition: PageProps.php:90
PageProps\ensureCacheSize
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition: PageProps.php:103
PageProps
Gives access to properties of a page.
Definition: PageProps.php:33
PageProps\getCachedProperties
getCachedProperties( $pageID)
Get properties from the cache.
Definition: PageProps.php:299
PageProps\cacheProperties
cacheProperties( $pageID, $pageProperties)
Save properties to the cache.
Definition: PageProps.php:312
PageProps\$cache
MapCacheLRU $cache
Definition: PageProps.php:46
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81