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-next-line PhanPossiblyUndeclaredVariable pageID set when used
176 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable pageID set when used
177 $this->cacheProperties( $pageID, $pageProperties );
178 // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable pageID set when used
179 // @phan-suppress-next-line PhanTypeMismatchDimAssignment pageID set when used
180 $values[$pageID] = $pageProperties;
181 }
182 }
183
184 return $values;
185 }
186
191 private function getGoodIDs( $titles ) {
192 $result = [];
193 if ( is_iterable( $titles ) ) {
194 if ( $titles instanceof TitleArrayFromResult ||
195 ( is_array( $titles ) && reset( $titles ) instanceof Title
196 ) ) {
197 // If the first element is a Title, assume all elements are Titles,
198 // and pre-fetch their IDs using a batch query. For PageIdentityValues
199 // or PageStoreRecords, this is not necessary, since they already
200 // know their ID.
201 $this->linkBatchFactory->newLinkBatch( $titles )->execute();
202 }
203
204 foreach ( $titles as $title ) {
205 // Until we only allow ProperPageIdentity, Title objects
206 // can deceive us with an unexpected Special page
207 if ( $title->canExist() ) {
208 $pageID = $title->getId();
209 if ( $pageID > 0 ) {
210 $result[] = $pageID;
211 }
212 }
213 }
214 } else {
215 // Until we only allow ProperPageIdentity, Title objects
216 // can deceive us with an unexpected Special page
217 if ( $titles->canExist() ) {
218 $pageID = $titles->getId();
219 if ( $pageID > 0 ) {
220 $result[] = $pageID;
221 }
222 }
223 }
224 return $result;
225 }
226
234 private function getCachedProperty( $pageID, $propertyName ) {
235 if ( $this->cache->hasField( $pageID, $propertyName, self::CACHE_TTL ) ) {
236 return $this->cache->getField( $pageID, $propertyName );
237 }
238 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
239 $pageProperties = $this->cache->getField( 0, $pageID );
240 if ( isset( $pageProperties[$propertyName] ) ) {
241 return $pageProperties[$propertyName];
242 }
243 }
244 return false;
245 }
246
253 private function getCachedProperties( $pageID ) {
254 if ( $this->cache->hasField( 0, $pageID, self::CACHE_TTL ) ) {
255 return $this->cache->getField( 0, $pageID );
256 }
257 return false;
258 }
259
266 private function cacheProperties( $pageID, $pageProperties ) {
267 $this->cache->clear( $pageID );
268 $this->cache->setField( 0, $pageID, $pageProperties );
269 }
270}
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.