MediaWiki master
PageProps.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Page;
22
23use MapCacheLRU;
28
35class PageProps {
36 /* TTL in seconds */
37 private const CACHE_TTL = 10;
38 /* max cached pages */
39 private const CACHE_SIZE = 100;
40
41 private LinkBatchFactory $linkBatchFactory;
42 private IConnectionProvider $dbProvider;
43 private MapCacheLRU $cache;
44
49 public function __construct(
50 LinkBatchFactory $linkBatchFactory,
51 IConnectionProvider $dbProvider
52 ) {
53 $this->linkBatchFactory = $linkBatchFactory;
54 $this->dbProvider = $dbProvider;
55 $this->cache = new MapCacheLRU( self::CACHE_SIZE );
56 }
57
62 public function ensureCacheSize( $size ) {
63 if ( $this->cache->getMaxSize() < $size ) {
64 $this->cache->setMaxSize( $size );
65 }
66 }
67
91 public function getProperties( $titles, $propertyNames ) {
92 if ( is_array( $propertyNames ) ) {
93 $gotArray = true;
94 } else {
95 $propertyNames = [ $propertyNames ];
96 $gotArray = false;
97 }
98
99 $values = [];
100 $goodIDs = $this->getGoodIDs( $titles );
101 $queryIDs = [];
102 foreach ( $goodIDs as $pageID ) {
103 foreach ( $propertyNames as $propertyName ) {
104 $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
105 if ( $propertyValue === false ) {
106 $queryIDs[] = $pageID;
107 break;
108 } elseif ( $gotArray ) {
109 $values[$pageID][$propertyName] = $propertyValue;
110 } else {
111 $values[$pageID] = $propertyValue;
112 }
113 }
114 }
115
116 if ( $queryIDs ) {
117 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
118 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
119 ->from( 'page_props' )
120 ->where( [ 'pp_page' => $queryIDs, 'pp_propname' => $propertyNames ] )
121 ->caller( __METHOD__ );
122 $result = $queryBuilder->fetchResultSet();
123
124 foreach ( $result as $row ) {
125 $pageID = $row->pp_page;
126 $propertyName = $row->pp_propname;
127 $propertyValue = $row->pp_value;
128 $this->cache->setField( $pageID, $propertyName, $propertyValue );
129 if ( $gotArray ) {
130 $values[$pageID][$propertyName] = $propertyValue;
131 } else {
132 $values[$pageID] = $propertyValue;
133 }
134 }
135 }
136
137 return $values;
138 }
139
157 public function getAllProperties( $titles ) {
158 $values = [];
159 $goodIDs = $this->getGoodIDs( $titles );
160 $queryIDs = [];
161 foreach ( $goodIDs as $pageID ) {
162 $pageProperties = $this->getCachedProperties( $pageID );
163 if ( $pageProperties === false ) {
164 $queryIDs[] = $pageID;
165 } else {
166 $values[$pageID] = $pageProperties;
167 }
168 }
169
170 if ( $queryIDs != [] ) {
171 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
172 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
173 ->from( 'page_props' )
174 ->where( [ 'pp_page' => $queryIDs ] )
175 ->caller( __METHOD__ );
176 $result = $queryBuilder->fetchResultSet();
177
178 $currentPageID = 0;
179 $pageProperties = [];
180 foreach ( $result as $row ) {
181 $pageID = $row->pp_page;
182 if ( $currentPageID != $pageID ) {
183 if ( $pageProperties ) {
184 // @phan-suppress-next-line PhanTypeMismatchArgument False positive
185 $this->cacheProperties( $currentPageID, $pageProperties );
186 $values[$currentPageID] = $pageProperties;
187 }
188 $currentPageID = $pageID;
189 $pageProperties = [];
190 }
191 $pageProperties[$row->pp_propname] = $row->pp_value;
192 }
193 if ( $pageProperties != [] ) {
194 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
195 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable pageID set when used
196 $this->cacheProperties( $pageID, $pageProperties );
197 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
198 // @phan-suppress-next-line PhanTypeMismatchDimAssignment pageID set when used
199 $values[$pageID] = $pageProperties;
200 }
201 }
202
203 return $values;
204 }
205
210 private function getGoodIDs( $titles ) {
211 $result = [];
212 if ( is_iterable( $titles ) ) {
213 if ( $titles instanceof TitleArrayFromResult ||
214 ( is_array( $titles ) && reset( $titles ) instanceof Title
215 ) ) {
216 // If the first element is a Title, assume all elements are Titles,
217 // and pre-fetch their IDs using a batch query. For PageIdentityValues
218 // or PageStoreRecords, this is not necessary, since they already
219 // know their ID.
220 $this->linkBatchFactory->newLinkBatch( $titles )->execute();
221 }
222
223 foreach ( $titles as $title ) {
224 // Until we only allow ProperPageIdentity, Title objects
225 // can deceive us with an unexpected Special page
226 if ( $title->canExist() ) {
227 $pageID = $title->getId();
228 if ( $pageID > 0 ) {
229 $result[] = $pageID;
230 }
231 }
232 }
233 } else {
234 // Until we only allow ProperPageIdentity, Title objects
235 // can deceive us with an unexpected Special page
236 if ( $titles->canExist() ) {
237 $pageID = $titles->getId();
238 if ( $pageID > 0 ) {
239 $result[] = $pageID;
240 }
241 }
242 }
243 return $result;
244 }
245
253 private function getCachedProperty( $pageID, $propertyName ) {
254 if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
255 return $this->cache->getField( $pageID, $propertyName );
256 }
257 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
258 $pageProperties = $this->cache->getField( 0, $pageID );
259 if ( isset( $pageProperties[$propertyName] ) ) {
260 return $pageProperties[$propertyName];
261 }
262 }
263 return false;
264 }
265
272 private function getCachedProperties( $pageID ) {
273 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
274 return $this->cache->getField( 0, $pageID );
275 }
276 return false;
277 }
278
285 private function cacheProperties( $pageID, $pageProperties ) {
286 $this->cache->clear( $pageID );
287 $this->cache->setField( 0, $pageID, $pageProperties );
288 }
289}
290
292class_alias( PageProps::class, 'PageProps' );
Store key-value entries in a size-limited in-memory LRU cache.
Gives access to properties of a page.
Definition PageProps.php:35
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition PageProps.php:62
__construct(LinkBatchFactory $linkBatchFactory, IConnectionProvider $dbProvider)
Definition PageProps.php:49
getAllProperties( $titles)
Get all page properties of one or more page titles.
getProperties( $titles, $propertyNames)
Fetch one or more properties for one or more Titles.
Definition PageProps.php:91
Represents a title within MediaWiki.
Definition Title.php:78
Provide primary and replica IDatabase connections.