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
45 public function __construct(
46 LinkBatchFactory $linkBatchFactory,
47 IConnectionProvider $dbProvider
48 ) {
49 $this->linkBatchFactory = $linkBatchFactory;
50 $this->dbProvider = $dbProvider;
51 $this->cache = new MapCacheLRU( self::CACHE_SIZE );
52 }
53
58 public function ensureCacheSize( $size ) {
59 if ( $this->cache->getMaxSize() < $size ) {
60 $this->cache->setMaxSize( $size );
61 }
62 }
63
87 public function getProperties( $titles, $propertyNames ) {
88 if ( is_array( $propertyNames ) ) {
89 $gotArray = true;
90 } else {
91 $propertyNames = [ $propertyNames ];
92 $gotArray = false;
93 }
94
95 $values = [];
96 $goodIDs = $this->getGoodIDs( $titles );
97 $queryIDs = [];
98 foreach ( $goodIDs as $pageID ) {
99 foreach ( $propertyNames as $propertyName ) {
100 $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
101 if ( $propertyValue === false ) {
102 $queryIDs[] = $pageID;
103 break;
104 } elseif ( $gotArray ) {
105 $values[$pageID][$propertyName] = $propertyValue;
106 } else {
107 $values[$pageID] = $propertyValue;
108 }
109 }
110 }
111
112 if ( $queryIDs ) {
113 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
114 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
115 ->from( 'page_props' )
116 ->where( [ 'pp_page' => $queryIDs, 'pp_propname' => $propertyNames ] )
117 ->caller( __METHOD__ );
118 $result = $queryBuilder->fetchResultSet();
119
120 foreach ( $result as $row ) {
121 $pageID = $row->pp_page;
122 $propertyName = $row->pp_propname;
123 $propertyValue = $row->pp_value;
124 $this->cache->setField( $pageID, $propertyName, $propertyValue );
125 if ( $gotArray ) {
126 $values[$pageID][$propertyName] = $propertyValue;
127 } else {
128 $values[$pageID] = $propertyValue;
129 }
130 }
131 }
132
133 return $values;
134 }
135
153 public function getAllProperties( $titles ) {
154 $values = [];
155 $goodIDs = $this->getGoodIDs( $titles );
156 $queryIDs = [];
157 foreach ( $goodIDs as $pageID ) {
158 $pageProperties = $this->getCachedProperties( $pageID );
159 if ( $pageProperties === false ) {
160 $queryIDs[] = $pageID;
161 } else {
162 $values[$pageID] = $pageProperties;
163 }
164 }
165
166 if ( $queryIDs != [] ) {
167 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
168 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
169 ->from( 'page_props' )
170 ->where( [ 'pp_page' => $queryIDs ] )
171 ->caller( __METHOD__ );
172 $result = $queryBuilder->fetchResultSet();
173
174 $currentPageID = 0;
175 $pageProperties = [];
176 foreach ( $result as $row ) {
177 $pageID = $row->pp_page;
178 if ( $currentPageID != $pageID ) {
179 if ( $pageProperties ) {
180 // @phan-suppress-next-line PhanTypeMismatchArgument False positive
181 $this->cacheProperties( $currentPageID, $pageProperties );
182 $values[$currentPageID] = $pageProperties;
183 }
184 $currentPageID = $pageID;
185 $pageProperties = [];
186 }
187 $pageProperties[$row->pp_propname] = $row->pp_value;
188 }
189 if ( $pageProperties != [] ) {
190 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
191 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable pageID set when used
192 $this->cacheProperties( $pageID, $pageProperties );
193 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
194 // @phan-suppress-next-line PhanTypeMismatchDimAssignment pageID set when used
195 $values[$pageID] = $pageProperties;
196 }
197 }
198
199 return $values;
200 }
201
206 private function getGoodIDs( $titles ) {
207 $result = [];
208 if ( is_iterable( $titles ) ) {
209 if ( $titles instanceof TitleArrayFromResult ||
210 ( is_array( $titles ) && reset( $titles ) instanceof Title
211 ) ) {
212 // If the first element is a Title, assume all elements are Titles,
213 // and pre-fetch their IDs using a batch query. For PageIdentityValues
214 // or PageStoreRecords, this is not necessary, since they already
215 // know their ID.
216 $this->linkBatchFactory->newLinkBatch( $titles )->execute();
217 }
218
219 foreach ( $titles as $title ) {
220 // Until we only allow ProperPageIdentity, Title objects
221 // can deceive us with an unexpected Special page
222 if ( $title->canExist() ) {
223 $pageID = $title->getId();
224 if ( $pageID > 0 ) {
225 $result[] = $pageID;
226 }
227 }
228 }
229 } else {
230 // Until we only allow ProperPageIdentity, Title objects
231 // can deceive us with an unexpected Special page
232 if ( $titles->canExist() ) {
233 $pageID = $titles->getId();
234 if ( $pageID > 0 ) {
235 $result[] = $pageID;
236 }
237 }
238 }
239 return $result;
240 }
241
249 private function getCachedProperty( $pageID, $propertyName ) {
250 if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
251 return $this->cache->getField( $pageID, $propertyName );
252 }
253 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
254 $pageProperties = $this->cache->getField( 0, $pageID );
255 if ( isset( $pageProperties[$propertyName] ) ) {
256 return $pageProperties[$propertyName];
257 }
258 }
259 return false;
260 }
261
268 private function getCachedProperties( $pageID ) {
269 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
270 return $this->cache->getField( 0, $pageID );
271 }
272 return false;
273 }
274
281 private function cacheProperties( $pageID, $pageProperties ) {
282 $this->cache->clear( $pageID );
283 $this->cache->setField( 0, $pageID, $pageProperties );
284 }
285}
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:58
__construct(LinkBatchFactory $linkBatchFactory, IConnectionProvider $dbProvider)
Definition PageProps.php:45
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:87
Represents a title within MediaWiki.
Definition Title.php:78
Provide primary and replica IDatabase connections.