MediaWiki  master
PageProps.php
Go to the documentation of this file.
1 <?php
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;
47 
51  public static function getInstance() {
52  return MediaWikiServices::getInstance()->getPageProps();
53  }
54 
59  public function __construct(
62  ) {
63  $this->linkBatchFactory = $linkBatchFactory;
64  $this->loadBalancer = $loadBalancer;
65  $this->cache = new MapCacheLRU( self::CACHE_SIZE );
66  }
67 
72  public function ensureCacheSize( $size ) {
73  if ( $this->cache->getMaxSize() < $size ) {
74  $this->cache->setMaxSize( $size );
75  }
76  }
77 
96  public function getProperties( $titles, $propertyNames ) {
97  if ( is_array( $propertyNames ) ) {
98  $gotArray = true;
99  } else {
100  $propertyNames = [ $propertyNames ];
101  $gotArray = false;
102  }
103 
104  $values = [];
105  $goodIDs = $this->getGoodIDs( $titles );
106  $queryIDs = [];
107  foreach ( $goodIDs as $pageID ) {
108  foreach ( $propertyNames as $propertyName ) {
109  $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
110  if ( $propertyValue === false ) {
111  $queryIDs[] = $pageID;
112  break;
113  } elseif ( $gotArray ) {
114  $values[$pageID][$propertyName] = $propertyValue;
115  } else {
116  $values[$pageID] = $propertyValue;
117  }
118  }
119  }
120 
121  if ( $queryIDs ) {
122  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
123  $result = $dbr->select(
124  'page_props',
125  [
126  'pp_page',
127  'pp_propname',
128  'pp_value'
129  ],
130  [
131  'pp_page' => $queryIDs,
132  'pp_propname' => $propertyNames
133  ],
134  __METHOD__
135  );
136 
137  foreach ( $result as $row ) {
138  $pageID = $row->pp_page;
139  $propertyName = $row->pp_propname;
140  $propertyValue = $row->pp_value;
141  $this->cache->setField( $pageID, $propertyName, $propertyValue );
142  if ( $gotArray ) {
143  $values[$pageID][$propertyName] = $propertyValue;
144  } else {
145  $values[$pageID] = $propertyValue;
146  }
147  }
148  }
149 
150  return $values;
151  }
152 
166  public function getAllProperties( $titles ) {
167  $values = [];
168  $goodIDs = $this->getGoodIDs( $titles );
169  $queryIDs = [];
170  foreach ( $goodIDs as $pageID ) {
171  $pageProperties = $this->getCachedProperties( $pageID );
172  if ( $pageProperties === false ) {
173  $queryIDs[] = $pageID;
174  } else {
175  $values[$pageID] = $pageProperties;
176  }
177  }
178 
179  if ( $queryIDs != [] ) {
180  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
181  $result = $dbr->select(
182  'page_props',
183  [
184  'pp_page',
185  'pp_propname',
186  'pp_value'
187  ],
188  [
189  'pp_page' => $queryIDs,
190  ],
191  __METHOD__
192  );
193 
194  $currentPageID = 0;
195  $pageProperties = [];
196  foreach ( $result as $row ) {
197  $pageID = $row->pp_page;
198  if ( $currentPageID != $pageID ) {
199  if ( $pageProperties ) {
200  // @phan-suppress-next-line PhanTypeMismatchArgument False positive
201  $this->cacheProperties( $currentPageID, $pageProperties );
202  $values[$currentPageID] = $pageProperties;
203  }
204  $currentPageID = $pageID;
205  $pageProperties = [];
206  }
207  $pageProperties[$row->pp_propname] = $row->pp_value;
208  }
209  if ( $pageProperties != [] ) {
210  $this->cacheProperties( $pageID, $pageProperties );
211  $values[$pageID] = $pageProperties;
212  }
213  }
214 
215  return $values;
216  }
217 
222  private function getGoodIDs( $titles ) {
223  $result = [];
224  if ( is_iterable( $titles ) ) {
225  if ( $titles instanceof TitleArray ||
226  ( is_array( $titles ) && reset( $titles ) instanceof Title
227  ) ) {
228  // If the first element is a Title, assume all elements are Titles,
229  // and pre-fetch their IDs using a batch query. For PageIdentityValues
230  // or PageStoreRecords, this is not necessary, since they already
231  // know their ID.
232  $this->linkBatchFactory->newLinkBatch( $titles )->execute();
233  }
234 
235  foreach ( $titles as $title ) {
236  // Until we only allow ProperPageIdentity, Title objects
237  // can deceive us with an unexpected Special page
238  if ( $title->canExist() ) {
239  $pageID = $title->getId();
240  if ( $pageID > 0 ) {
241  $result[] = $pageID;
242  }
243  }
244  }
245  } else {
246  // Until we only allow ProperPageIdentity, Title objects
247  // can deceive us with an unexpected Special page
248  if ( $titles->canExist() ) {
249  $pageID = $titles->getId();
250  if ( $pageID > 0 ) {
251  $result[] = $pageID;
252  }
253  }
254  }
255  return $result;
256  }
257 
265  private function getCachedProperty( $pageID, $propertyName ) {
266  if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
267  return $this->cache->getField( $pageID, $propertyName );
268  }
269  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
270  $pageProperties = $this->cache->getField( 0, $pageID );
271  if ( isset( $pageProperties[$propertyName] ) ) {
272  return $pageProperties[$propertyName];
273  }
274  }
275  return false;
276  }
277 
284  private function getCachedProperties( $pageID ) {
285  if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
286  return $this->cache->getField( 0, $pageID );
287  }
288  return false;
289  }
290 
297  private function cacheProperties( $pageID, $pageProperties ) {
298  $this->cache->clear( $pageID );
299  $this->cache->setField( 0, $pageID, $pageProperties );
300  }
301 }
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:193
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:96
PageProps\getCachedProperty
getCachedProperty( $pageID, $propertyName)
Get a property from the cache.
Definition: PageProps.php:265
$dbr
$dbr
Definition: testCompression.php:54
PageProps\$loadBalancer
ILoadBalancer $loadBalancer
Definition: PageProps.php:39
PageProps\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: PageProps.php:36
PageProps\getInstance
static getInstance()
Definition: PageProps.php:51
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:39
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:36
$title
$title
Definition: testCompression.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
PageProps\getGoodIDs
getGoodIDs( $titles)
Definition: PageProps.php:222
PageProps\CACHE_TTL
const CACHE_TTL
Cache parameters.
Definition: PageProps.php:42
PageProps\getAllProperties
getAllProperties( $titles)
Get all page property values.
Definition: PageProps.php:166
PageProps\CACHE_SIZE
const CACHE_SIZE
Definition: PageProps.php:43
PageProps\__construct
__construct(LinkBatchFactory $linkBatchFactory, ILoadBalancer $loadBalancer)
Definition: PageProps.php:59
Title
Represents a title within MediaWiki.
Definition: Title.php:48
PageProps\ensureCacheSize
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition: PageProps.php:72
PageProps
Gives access to properties of a page.
Definition: PageProps.php:33
PageProps\getCachedProperties
getCachedProperties( $pageID)
Get properties from the cache.
Definition: PageProps.php:284
TitleArray
The TitleArray class only exists to provide the newFromResult method at pre- sent.
Definition: TitleArray.php:37
PageProps\cacheProperties
cacheProperties( $pageID, $pageProperties)
Save properties to the cache.
Definition: PageProps.php:297
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