MediaWiki REL1_40
PageProps.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Page;
24
25use MapCacheLRU;
30
36class PageProps {
37
39 private $linkBatchFactory;
40
42 private $loadBalancer;
43
45 private const CACHE_TTL = 10; // integer; TTL in seconds
46 private const CACHE_SIZE = 100; // integer; max cached pages
47
49 private $cache;
50
55 public function __construct(
56 LinkBatchFactory $linkBatchFactory,
57 ILoadBalancer $loadBalancer
58 ) {
59 $this->linkBatchFactory = $linkBatchFactory;
60 $this->loadBalancer = $loadBalancer;
61 $this->cache = new MapCacheLRU( self::CACHE_SIZE );
62 }
63
68 public function ensureCacheSize( $size ) {
69 if ( $this->cache->getMaxSize() < $size ) {
70 $this->cache->setMaxSize( $size );
71 }
72 }
73
92 public function getProperties( $titles, $propertyNames ) {
93 if ( is_array( $propertyNames ) ) {
94 $gotArray = true;
95 } else {
96 $propertyNames = [ $propertyNames ];
97 $gotArray = false;
98 }
99
100 $values = [];
101 $goodIDs = $this->getGoodIDs( $titles );
102 $queryIDs = [];
103 foreach ( $goodIDs as $pageID ) {
104 foreach ( $propertyNames as $propertyName ) {
105 $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
106 if ( $propertyValue === false ) {
107 $queryIDs[] = $pageID;
108 break;
109 } elseif ( $gotArray ) {
110 $values[$pageID][$propertyName] = $propertyValue;
111 } else {
112 $values[$pageID] = $propertyValue;
113 }
114 }
115 }
116
117 if ( $queryIDs ) {
118 $queryBuilder = $this->loadBalancer->getConnectionRef( DB_REPLICA )->newSelectQueryBuilder();
119 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
120 ->from( 'page_props' )
121 ->where( [ 'pp_page' => $queryIDs, 'pp_propname' => $propertyNames ] )
122 ->caller( __METHOD__ );
123 $result = $queryBuilder->fetchResultSet();
124
125 foreach ( $result as $row ) {
126 $pageID = $row->pp_page;
127 $propertyName = $row->pp_propname;
128 $propertyValue = $row->pp_value;
129 $this->cache->setField( $pageID, $propertyName, $propertyValue );
130 if ( $gotArray ) {
131 $values[$pageID][$propertyName] = $propertyValue;
132 } else {
133 $values[$pageID] = $propertyValue;
134 }
135 }
136 }
137
138 return $values;
139 }
140
154 public function getAllProperties( $titles ) {
155 $values = [];
156 $goodIDs = $this->getGoodIDs( $titles );
157 $queryIDs = [];
158 foreach ( $goodIDs as $pageID ) {
159 $pageProperties = $this->getCachedProperties( $pageID );
160 if ( $pageProperties === false ) {
161 $queryIDs[] = $pageID;
162 } else {
163 $values[$pageID] = $pageProperties;
164 }
165 }
166
167 if ( $queryIDs != [] ) {
168 $queryBuilder = $this->loadBalancer->getConnectionRef( DB_REPLICA )->newSelectQueryBuilder();
169 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
170 ->from( 'page_props' )
171 ->where( [ 'pp_page' => $queryIDs ] )
172 ->caller( __METHOD__ );
173 $result = $queryBuilder->fetchResultSet();
174
175 $currentPageID = 0;
176 $pageProperties = [];
177 foreach ( $result as $row ) {
178 $pageID = $row->pp_page;
179 if ( $currentPageID != $pageID ) {
180 if ( $pageProperties ) {
181 // @phan-suppress-next-line PhanTypeMismatchArgument False positive
182 $this->cacheProperties( $currentPageID, $pageProperties );
183 $values[$currentPageID] = $pageProperties;
184 }
185 $currentPageID = $pageID;
186 $pageProperties = [];
187 }
188 $pageProperties[$row->pp_propname] = $row->pp_value;
189 }
190 if ( $pageProperties != [] ) {
191 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
192 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable pageID set when used
193 $this->cacheProperties( $pageID, $pageProperties );
194 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
195 // @phan-suppress-next-line PhanTypeMismatchDimAssignment pageID set when used
196 $values[$pageID] = $pageProperties;
197 }
198 }
199
200 return $values;
201 }
202
207 private function getGoodIDs( $titles ) {
208 $result = [];
209 if ( is_iterable( $titles ) ) {
210 if ( $titles instanceof TitleArray ||
211 ( is_array( $titles ) && reset( $titles ) instanceof Title
212 ) ) {
213 // If the first element is a Title, assume all elements are Titles,
214 // and pre-fetch their IDs using a batch query. For PageIdentityValues
215 // or PageStoreRecords, this is not necessary, since they already
216 // know their ID.
217 $this->linkBatchFactory->newLinkBatch( $titles )->execute();
218 }
219
220 foreach ( $titles as $title ) {
221 // Until we only allow ProperPageIdentity, Title objects
222 // can deceive us with an unexpected Special page
223 if ( $title->canExist() ) {
224 $pageID = $title->getId();
225 if ( $pageID > 0 ) {
226 $result[] = $pageID;
227 }
228 }
229 }
230 } else {
231 // Until we only allow ProperPageIdentity, Title objects
232 // can deceive us with an unexpected Special page
233 if ( $titles->canExist() ) {
234 $pageID = $titles->getId();
235 if ( $pageID > 0 ) {
236 $result[] = $pageID;
237 }
238 }
239 }
240 return $result;
241 }
242
250 private function getCachedProperty( $pageID, $propertyName ) {
251 if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
252 return $this->cache->getField( $pageID, $propertyName );
253 }
254 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
255 $pageProperties = $this->cache->getField( 0, $pageID );
256 if ( isset( $pageProperties[$propertyName] ) ) {
257 return $pageProperties[$propertyName];
258 }
259 }
260 return false;
261 }
262
269 private function getCachedProperties( $pageID ) {
270 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
271 return $this->cache->getField( 0, $pageID );
272 }
273 return false;
274 }
275
282 private function cacheProperties( $pageID, $pageProperties ) {
283 $this->cache->clear( $pageID );
284 $this->cache->setField( 0, $pageID, $pageProperties );
285 }
286}
287
288class_alias( PageProps::class, 'PageProps' );
Handles a simple LRU key/value map with a maximum number of entries.
Gives access to properties of a page.
Definition PageProps.php:36
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition PageProps.php:68
getAllProperties( $titles)
Get all page property values.
__construct(LinkBatchFactory $linkBatchFactory, ILoadBalancer $loadBalancer)
Definition PageProps.php:55
getProperties( $titles, $propertyNames)
Given one or more Titles and one or more names of properties, returns an associative array mapping pa...
Definition PageProps.php:92
The TitleArray class only exists to provide the newFromResult method at pre- sent.
Represents a title within MediaWiki.
Definition Title.php:82
This class is a delegate to ILBFactory for a given database cluster.
const DB_REPLICA
Definition defines.php:26