MediaWiki master
PageProps.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Page;
8
13
20class PageProps {
21 /* TTL in seconds */
22 private const CACHE_TTL = 10;
23 /* max cached pages */
24 private const CACHE_SIZE = 100;
25
26 private LinkBatchFactory $linkBatchFactory;
27 private IConnectionProvider $dbProvider;
28 private MapCacheLRU $cache;
29
30 public function __construct(
31 LinkBatchFactory $linkBatchFactory,
32 IConnectionProvider $dbProvider
33 ) {
34 $this->linkBatchFactory = $linkBatchFactory;
35 $this->dbProvider = $dbProvider;
36 $this->cache = new MapCacheLRU( self::CACHE_SIZE );
37 }
38
43 public function ensureCacheSize( $size ) {
44 if ( $this->cache->getMaxSize() < $size ) {
45 $this->cache->setMaxSize( $size );
46 }
47 }
48
72 public function getProperties( $titles, $propertyNames ) {
73 if ( is_array( $propertyNames ) ) {
74 $gotArray = true;
75 } else {
76 $propertyNames = [ $propertyNames ];
77 $gotArray = false;
78 }
79
80 $values = [];
81 $goodIDs = $this->getGoodIDs( $titles );
82 $queryIDs = [];
83 foreach ( $goodIDs as $pageID ) {
84 foreach ( $propertyNames as $propertyName ) {
85 $propertyValue = $this->getCachedProperty( $pageID, $propertyName );
86 if ( $propertyValue === false ) {
87 $queryIDs[] = $pageID;
88 break;
89 } elseif ( $gotArray ) {
90 $values[$pageID][$propertyName] = $propertyValue;
91 } else {
92 $values[$pageID] = $propertyValue;
93 }
94 }
95 }
96
97 if ( $queryIDs ) {
98 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
99 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
100 ->from( 'page_props' )
101 ->where( [ 'pp_page' => $queryIDs, 'pp_propname' => $propertyNames ] )
102 ->caller( __METHOD__ );
103 $result = $queryBuilder->fetchResultSet();
104
105 foreach ( $result as $row ) {
106 $pageID = $row->pp_page;
107 $propertyName = $row->pp_propname;
108 $propertyValue = $row->pp_value;
109 $this->cache->setField( $pageID, $propertyName, $propertyValue );
110 if ( $gotArray ) {
111 $values[$pageID][$propertyName] = $propertyValue;
112 } else {
113 $values[$pageID] = $propertyValue;
114 }
115 }
116 }
117
118 return $values;
119 }
120
138 public function getAllProperties( $titles ) {
139 $values = [];
140 $goodIDs = $this->getGoodIDs( $titles );
141 $queryIDs = [];
142 foreach ( $goodIDs as $pageID ) {
143 $pageProperties = $this->getCachedProperties( $pageID );
144 if ( $pageProperties === false ) {
145 $queryIDs[] = $pageID;
146 } else {
147 $values[$pageID] = $pageProperties;
148 }
149 }
150
151 if ( $queryIDs != [] ) {
152 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder();
153 $queryBuilder->select( [ 'pp_page', 'pp_propname', 'pp_value' ] )
154 ->from( 'page_props' )
155 ->where( [ 'pp_page' => $queryIDs ] )
156 ->caller( __METHOD__ );
157 $result = $queryBuilder->fetchResultSet();
158
159 $currentPageID = 0;
160 $pageProperties = [];
161 foreach ( $result as $row ) {
162 $pageID = $row->pp_page;
163 if ( $currentPageID != $pageID ) {
164 if ( $pageProperties ) {
165 // @phan-suppress-next-line PhanTypeMismatchArgument False positive
166 $this->cacheProperties( $currentPageID, $pageProperties );
167 $values[$currentPageID] = $pageProperties;
168 }
169 $currentPageID = $pageID;
170 $pageProperties = [];
171 }
172 $pageProperties[$row->pp_propname] = $row->pp_value;
173 }
174 if ( $pageProperties != [] ) {
175 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable pageID set when used
176 $this->cacheProperties( $pageID, $pageProperties );
177 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable pageID set when used
178 $values[$pageID] = $pageProperties;
179 }
180 }
181
182 return $values;
183 }
184
189 private function getGoodIDs( $titles ) {
190 $result = [];
191 if ( is_iterable( $titles ) ) {
192 if ( $titles instanceof TitleArrayFromResult ||
193 ( is_array( $titles ) && reset( $titles ) instanceof Title
194 ) ) {
195 // If the first element is a Title, assume all elements are Titles,
196 // and pre-fetch their IDs using a batch query. For PageIdentityValues
197 // or PageStoreRecords, this is not necessary, since they already
198 // know their ID.
199 $this->linkBatchFactory->newLinkBatch( $titles )->execute();
200 }
201
202 foreach ( $titles as $title ) {
203 // Until we only allow ProperPageIdentity, Title objects
204 // can deceive us with an unexpected Special page
205 if ( $title->canExist() ) {
206 $pageID = $title->getId();
207 if ( $pageID > 0 ) {
208 $result[] = $pageID;
209 }
210 }
211 }
212 } else {
213 // Until we only allow ProperPageIdentity, Title objects
214 // can deceive us with an unexpected Special page
215 if ( $titles->canExist() ) {
216 $pageID = $titles->getId();
217 if ( $pageID > 0 ) {
218 $result[] = $pageID;
219 }
220 }
221 }
222 return $result;
223 }
224
232 private function getCachedProperty( $pageID, $propertyName ) {
233 if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
234 return $this->cache->getField( $pageID, $propertyName );
235 }
236 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
237 $pageProperties = $this->cache->getField( 0, $pageID );
238 if ( isset( $pageProperties[$propertyName] ) ) {
239 return $pageProperties[$propertyName];
240 }
241 }
242 return false;
243 }
244
251 private function getCachedProperties( $pageID ) {
252 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
253 return $this->cache->getField( 0, $pageID );
254 }
255 return false;
256 }
257
264 private function cacheProperties( $pageID, $pageProperties ) {
265 $this->cache->clear( $pageID );
266 $this->cache->setField( 0, $pageID, $pageProperties );
267 }
268}
Factory for LinkBatch objects to batch query page metadata.
Gives access to properties of a page.
Definition PageProps.php:20
ensureCacheSize( $size)
Ensure that cache has at least this size.
Definition PageProps.php:43
__construct(LinkBatchFactory $linkBatchFactory, IConnectionProvider $dbProvider)
Definition PageProps.php:30
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:72
Represents a title within MediaWiki.
Definition Title.php:69
Store key-value entries in a size-limited in-memory LRU cache.
Provide primary and replica IDatabase connections.