Index: trunk/extensions/EducationProgram/compat/SpecialCachedPage.php |
— | — | @@ -0,0 +1,261 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Abstract special page class with scaffolding for caching the HTML output. |
| 6 | + * |
| 7 | + * To enable the caching functionality, the cacheExpiry field should be set |
| 8 | + * in the constructor. |
| 9 | + * |
| 10 | + * To add HTML that should be cached, use addCachedHTML like this: |
| 11 | + * $this->addCachedHTML( array( $this, 'displayCachedContent' ) ); |
| 12 | + * |
| 13 | + * After adding the last HTML that should be cached, call $this->saveCache(); |
| 14 | + * |
| 15 | + * @since 0.1 |
| 16 | + * |
| 17 | + * @file SpecialCachedPage.php |
| 18 | + * @ingroup EducationProgram |
| 19 | + * |
| 20 | + * @licence GNU GPL v3 or later |
| 21 | + * @author Jeroen De Dauw < jeroendedauw@gmail.com > |
| 22 | + */ |
| 23 | +abstract class SpecialCachedPage extends SpecialPage { |
| 24 | + |
| 25 | + /** |
| 26 | + * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry. |
| 27 | + * |
| 28 | + * @since 0.1 |
| 29 | + * @var integer|null |
| 30 | + */ |
| 31 | + protected $cacheExpiry = null; |
| 32 | + |
| 33 | + /** |
| 34 | + * List of HTML chunks to be cached (if !hasCached) or that where cashed (of hasCached). |
| 35 | + * If no cached already, then the newly computed chunks are added here, |
| 36 | + * if it as cached already, chunks are removed from this list as they are needed. |
| 37 | + * |
| 38 | + * @since 0.1 |
| 39 | + * @var array |
| 40 | + */ |
| 41 | + protected $cachedChunks; |
| 42 | + |
| 43 | + /** |
| 44 | + * Indicates if the to be cached content was already cached. |
| 45 | + * Null if this information is not available yet. |
| 46 | + * |
| 47 | + * @since 0.1 |
| 48 | + * @var boolean|null |
| 49 | + */ |
| 50 | + protected $hasCached = null; |
| 51 | + |
| 52 | + /** |
| 53 | + * Main method. |
| 54 | + * |
| 55 | + * @since 0.1 |
| 56 | + * |
| 57 | + * @param string|null $subPage |
| 58 | + */ |
| 59 | + public function execute( $subPage ) { |
| 60 | + //parent::execute( $subPage ); |
| 61 | + |
| 62 | + if ( $this->getRequest()->getText( 'action' ) === 'purge' ) { |
| 63 | + $this->hasCached = false; |
| 64 | + } |
| 65 | + |
| 66 | + if ( !is_null( $this->cacheExpiry ) ) { |
| 67 | + $this->initCaching(); |
| 68 | + |
| 69 | + if ( $this->hasCached === true ) { |
| 70 | + $this->getOutput()->setSubtitle( $this->getCachedNotice( $subPage ) ); |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * Returns a message that notifies the user he/she is looking at |
| 77 | + * a cached version of the page, including a refresh link. |
| 78 | + * |
| 79 | + * @since 0.1 |
| 80 | + * |
| 81 | + * @param string|null $subPage |
| 82 | + * |
| 83 | + * @return string |
| 84 | + */ |
| 85 | + protected function getCachedNotice( $subPage ) { |
| 86 | + $refreshArgs = $_GET; |
| 87 | + unset( $refreshArgs['title'] ); |
| 88 | + $refreshArgs['action'] = 'purge'; |
| 89 | + |
| 90 | + $refreshLink = Linker::link( |
| 91 | + $this->getTitle( $subPage ), |
| 92 | + $this->msg( 'cachedspecial-refresh-now' )->escaped(), |
| 93 | + array(), |
| 94 | + $refreshArgs |
| 95 | + ); |
| 96 | + |
| 97 | + if ( $this->cacheExpiry < 1000000000 ) { |
| 98 | + $message = $this->msg( |
| 99 | + 'cachedspecial-viewing-cached-ttl', |
| 100 | + $this->getDurationText( $this->cacheExpiry ) |
| 101 | + )->escaped(); |
| 102 | + } |
| 103 | + else { |
| 104 | + $message = $this->msg( |
| 105 | + 'cachedspecial-viewing-cached-ts' |
| 106 | + )->escaped(); |
| 107 | + } |
| 108 | + |
| 109 | + return $message . ' ' . $refreshLink; |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * Returns a message with the time to live of the cache. |
| 114 | + * Takes care of compatibility with MW < 1.20, in which Language::duration was introduced. |
| 115 | + * |
| 116 | + * @since 0.1 |
| 117 | + * |
| 118 | + * @param integer $seconds |
| 119 | + * @param array $chosenIntervals |
| 120 | + * |
| 121 | + * @return string |
| 122 | + */ |
| 123 | + protected function getDurationText( $seconds, array $chosenIntervals = array( 'years', 'days', 'hours', 'minutes', 'seconds' ) ) { |
| 124 | + if ( method_exists( $this->getLanguage(), 'duration' ) ) { |
| 125 | + return $this->getLanguage()->duration( $seconds, $chosenIntervals ); |
| 126 | + } |
| 127 | + else { |
| 128 | + $intervals = array( |
| 129 | + 'years' => 31557600, // 86400 * 365.25 |
| 130 | + 'weeks' => 604800, |
| 131 | + 'days' => 86400, |
| 132 | + 'hours' => 3600, |
| 133 | + 'minutes' => 60, |
| 134 | + 'seconds' => 1, |
| 135 | + ); |
| 136 | + |
| 137 | + if ( !empty( $chosenIntervals ) ) { |
| 138 | + $intervals = array_intersect_key( $intervals, array_flip( $chosenIntervals ) ); |
| 139 | + } |
| 140 | + |
| 141 | + $segments = array(); |
| 142 | + |
| 143 | + foreach ( $intervals as $name => $length ) { |
| 144 | + $value = floor( $seconds / $length ); |
| 145 | + |
| 146 | + if ( $value > 0 || ( $name == 'seconds' && empty( $segments ) ) ) { |
| 147 | + $seconds -= $value * $length; |
| 148 | + $segments[] = $this->msg( 'duration-' . $name, array( $value ) )->escaped(); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + return $this->getLanguage()->listToText( $segments ); |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + * Initializes the caching if not already done so. |
| 158 | + * Should be called before any of the caching functionality is used. |
| 159 | + * |
| 160 | + * @since 0.1 |
| 161 | + */ |
| 162 | + protected function initCaching() { |
| 163 | + if ( is_null( $this->hasCached ) ) { |
| 164 | + $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKey() ); |
| 165 | + |
| 166 | + $this->hasCached = is_array( $cachedChunks ); |
| 167 | + $this->cachedChunks = $this->hasCached ? $cachedChunks : array(); |
| 168 | + } |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Add some HTML to be cached. |
| 173 | + * This is done by providing a callback function that should |
| 174 | + * return the HTML to be added. It will only be called if the |
| 175 | + * item is not in the cache yet or when the cache has been invalidated. |
| 176 | + * |
| 177 | + * @since 0.1 |
| 178 | + * |
| 179 | + * @param {function} $callback |
| 180 | + * @param array $args |
| 181 | + * @param string|null $key |
| 182 | + */ |
| 183 | + public function addCachedHTML( $callback, $args = array(), $key = null ) { |
| 184 | + $this->initCaching(); |
| 185 | + |
| 186 | + if ( $this->hasCached ) { |
| 187 | + $html = ''; |
| 188 | + |
| 189 | + if ( is_null( $key ) ) { |
| 190 | + $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) ); |
| 191 | + $itemKey = array_shift( $itemKey ); |
| 192 | + |
| 193 | + if ( !is_integer( $itemKey ) ) { |
| 194 | + wfWarn( "Attempted to get item with non-numeric key while the next item in the queue has a key ($itemKey) in " . __METHOD__ ); |
| 195 | + } |
| 196 | + elseif ( is_null( $itemKey ) ) { |
| 197 | + wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ ); |
| 198 | + } |
| 199 | + else { |
| 200 | + $html = array_shift( $this->cachedChunks ); |
| 201 | + } |
| 202 | + } |
| 203 | + else { |
| 204 | + if ( array_key_exists( $key, $this->cachedChunks ) ) { |
| 205 | + $html = $this->cachedChunks[$key]; |
| 206 | + unset( $this->cachedChunks[$key] ); |
| 207 | + } |
| 208 | + else { |
| 209 | + wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ ); |
| 210 | + } |
| 211 | + } |
| 212 | + } |
| 213 | + else { |
| 214 | + $html = call_user_func_array( $callback, $args ); |
| 215 | + |
| 216 | + if ( is_null( $key ) ) { |
| 217 | + $this->cachedChunks[] = $html; |
| 218 | + } |
| 219 | + else { |
| 220 | + $this->cachedChunks[$key] = $html; |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + $this->getOutput()->addHTML( $html ); |
| 225 | + } |
| 226 | + |
| 227 | + /** |
| 228 | + * Saves the HTML to the cache in case it got recomputed. |
| 229 | + * Should be called after the last time anything is added via addCachedHTML. |
| 230 | + * |
| 231 | + * @since 0.1 |
| 232 | + */ |
| 233 | + public function saveCache() { |
| 234 | + if ( $this->hasCached === false && !empty( $this->cachedChunks ) ) { |
| 235 | + wfGetCache( CACHE_ANYTHING )->set( $this->getCacheKey(), $this->cachedChunks, $this->cacheExpiry ); |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + /** |
| 240 | + * Sets the time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.. |
| 241 | + * |
| 242 | + * @since 0.1 |
| 243 | + * |
| 244 | + * @param integer $cacheExpiry |
| 245 | + */ |
| 246 | + protected function setExpirey( $cacheExpiry ) { |
| 247 | + $this->cacheExpiry = $cacheExpiry; |
| 248 | + } |
| 249 | + |
| 250 | + /** |
| 251 | + * Returns the cache key to use to cache this page's HTML output. |
| 252 | + * Is constructed from the special page name and language code. |
| 253 | + * |
| 254 | + * @since 0.1 |
| 255 | + * |
| 256 | + * @return string |
| 257 | + */ |
| 258 | + protected function getCacheKey() { |
| 259 | + return wfMemcKey( $this->mName, $this->getLanguage()->getCode() ); |
| 260 | + } |
| 261 | + |
| 262 | +} |
Index: trunk/extensions/EducationProgram/EducationProgram.php |
— | — | @@ -144,8 +144,17 @@ |
145 | 145 | $wgAutoloadClasses['SpecialCAProfile'] = dirname( __FILE__ ) . '/specials/SpecialCAProfile.php'; |
146 | 146 | $wgAutoloadClasses['SpecialAmbassadorProfile'] = dirname( __FILE__ ) . '/specials/SpecialAmbassadorProfile.php'; |
147 | 147 | $wgAutoloadClasses['SpecialStudentActivity'] = dirname( __FILE__ ) . '/specials/SpecialStudentActivity.php'; |
148 | | -$wgAutoloadClasses['SpecialCachedPage'] = dirname( __FILE__ ) . '/specials/SpecialCachedPage.php'; |
149 | 148 | |
| 149 | +// Compat classes |
| 150 | +foreach ( array( |
| 151 | + 'SpecialCachedPage' => 'SpecialCachedPage.php' // MW < 1.20 |
| 152 | + ) as $className => $fileName ) { |
| 153 | + |
| 154 | + if ( !array_key_exists( $className, $wgAutoloadLocalClasses ) ) { |
| 155 | + $wgAutoloadClasses[$className] = dirname( __FILE__ ) . '/compat/' . $fileName; |
| 156 | + } |
| 157 | +} |
| 158 | + |
150 | 159 | // Special pages |
151 | 160 | $wgSpecialPages['MyCourses'] = 'SpecialMyCourses'; |
152 | 161 | $wgSpecialPages['Institutions'] = 'SpecialInstitutions'; |
Index: trunk/extensions/EducationProgram/specials/SpecialCachedPage.php |
— | — | @@ -1,261 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -/** |
5 | | - * Abstract special page class with scaffolding for caching the HTML output. |
6 | | - * |
7 | | - * To enable the caching functionality, the cacheExpiry field should be set |
8 | | - * in the constructor. |
9 | | - * |
10 | | - * To add HTML that should be cached, use addCachedHTML like this: |
11 | | - * $this->addCachedHTML( array( $this, 'displayCachedContent' ) ); |
12 | | - * |
13 | | - * After adding the last HTML that should be cached, call $this->saveCache(); |
14 | | - * |
15 | | - * @since 0.1 |
16 | | - * |
17 | | - * @file SpecialCachedPage.php |
18 | | - * @ingroup EducationProgram |
19 | | - * |
20 | | - * @licence GNU GPL v3 or later |
21 | | - * @author Jeroen De Dauw < jeroendedauw@gmail.com > |
22 | | - */ |
23 | | -abstract class SpecialCachedPage extends SpecialPage { |
24 | | - |
25 | | - /** |
26 | | - * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry. |
27 | | - * |
28 | | - * @since 0.1 |
29 | | - * @var integer|null |
30 | | - */ |
31 | | - protected $cacheExpiry = null; |
32 | | - |
33 | | - /** |
34 | | - * List of HTML chunks to be cached (if !hasCached) or that where cashed (of hasCached). |
35 | | - * If no cached already, then the newly computed chunks are added here, |
36 | | - * if it as cached already, chunks are removed from this list as they are needed. |
37 | | - * |
38 | | - * @since 0.1 |
39 | | - * @var array |
40 | | - */ |
41 | | - protected $cachedChunks; |
42 | | - |
43 | | - /** |
44 | | - * Indicates if the to be cached content was already cached. |
45 | | - * Null if this information is not available yet. |
46 | | - * |
47 | | - * @since 0.1 |
48 | | - * @var boolean|null |
49 | | - */ |
50 | | - protected $hasCached = null; |
51 | | - |
52 | | - /** |
53 | | - * Main method. |
54 | | - * |
55 | | - * @since 0.1 |
56 | | - * |
57 | | - * @param string|null $subPage |
58 | | - */ |
59 | | - public function execute( $subPage ) { |
60 | | - //parent::execute( $subPage ); |
61 | | - |
62 | | - if ( $this->getRequest()->getText( 'action' ) === 'purge' ) { |
63 | | - $this->hasCached = false; |
64 | | - } |
65 | | - |
66 | | - if ( !is_null( $this->cacheExpiry ) ) { |
67 | | - $this->initCaching(); |
68 | | - |
69 | | - if ( $this->hasCached === true ) { |
70 | | - $this->getOutput()->setSubtitle( $this->getCachedNotice( $subPage ) ); |
71 | | - } |
72 | | - } |
73 | | - } |
74 | | - |
75 | | - /** |
76 | | - * Returns a message that notifies the user he/she is looking at |
77 | | - * a cached version of the page, including a refresh link. |
78 | | - * |
79 | | - * @since 0.1 |
80 | | - * |
81 | | - * @param string|null $subPage |
82 | | - * |
83 | | - * @return string |
84 | | - */ |
85 | | - protected function getCachedNotice( $subPage ) { |
86 | | - $refreshArgs = $_GET; |
87 | | - unset( $refreshArgs['title'] ); |
88 | | - $refreshArgs['action'] = 'purge'; |
89 | | - |
90 | | - $refreshLink = Linker::link( |
91 | | - $this->getTitle( $subPage ), |
92 | | - $this->msg( 'cachedspecial-refresh-now' )->escaped(), |
93 | | - array(), |
94 | | - $refreshArgs |
95 | | - ); |
96 | | - |
97 | | - if ( $this->cacheExpiry < 1000000000 ) { |
98 | | - $message = $this->msg( |
99 | | - 'cachedspecial-viewing-cached-ttl', |
100 | | - $this->getDurationText( $this->cacheExpiry ) |
101 | | - )->escaped(); |
102 | | - } |
103 | | - else { |
104 | | - $message = $this->msg( |
105 | | - 'cachedspecial-viewing-cached-ts' |
106 | | - )->escaped(); |
107 | | - } |
108 | | - |
109 | | - return $message . ' ' . $refreshLink; |
110 | | - } |
111 | | - |
112 | | - /** |
113 | | - * Returns a message with the time to live of the cache. |
114 | | - * Takes care of compatibility with MW < 1.20, in which Language::duration was introduced. |
115 | | - * |
116 | | - * @since 0.1 |
117 | | - * |
118 | | - * @param integer $seconds |
119 | | - * @param array $chosenIntervals |
120 | | - * |
121 | | - * @return string |
122 | | - */ |
123 | | - protected function getDurationText( $seconds, array $chosenIntervals = array( 'years', 'days', 'hours', 'minutes', 'seconds' ) ) { |
124 | | - if ( method_exists( $this->getLanguage(), 'duration' ) ) { |
125 | | - return $this->getLanguage()->duration( $seconds, $chosenIntervals ); |
126 | | - } |
127 | | - else { |
128 | | - $intervals = array( |
129 | | - 'years' => 31557600, // 86400 * 365.25 |
130 | | - 'weeks' => 604800, |
131 | | - 'days' => 86400, |
132 | | - 'hours' => 3600, |
133 | | - 'minutes' => 60, |
134 | | - 'seconds' => 1, |
135 | | - ); |
136 | | - |
137 | | - if ( !empty( $chosenIntervals ) ) { |
138 | | - $intervals = array_intersect_key( $intervals, array_flip( $chosenIntervals ) ); |
139 | | - } |
140 | | - |
141 | | - $segments = array(); |
142 | | - |
143 | | - foreach ( $intervals as $name => $length ) { |
144 | | - $value = floor( $seconds / $length ); |
145 | | - |
146 | | - if ( $value > 0 || ( $name == 'seconds' && empty( $segments ) ) ) { |
147 | | - $seconds -= $value * $length; |
148 | | - $segments[] = $this->msg( 'duration-' . $name, array( $value ) )->escaped(); |
149 | | - } |
150 | | - } |
151 | | - |
152 | | - return $this->getLanguage()->listToText( $segments ); |
153 | | - } |
154 | | - } |
155 | | - |
156 | | - /** |
157 | | - * Initializes the caching if not already done so. |
158 | | - * Should be called before any of the caching functionality is used. |
159 | | - * |
160 | | - * @since 0.1 |
161 | | - */ |
162 | | - protected function initCaching() { |
163 | | - if ( is_null( $this->hasCached ) ) { |
164 | | - $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKey() ); |
165 | | - |
166 | | - $this->hasCached = is_array( $cachedChunks ); |
167 | | - $this->cachedChunks = $this->hasCached ? $cachedChunks : array(); |
168 | | - } |
169 | | - } |
170 | | - |
171 | | - /** |
172 | | - * Add some HTML to be cached. |
173 | | - * This is done by providing a callback function that should |
174 | | - * return the HTML to be added. It will only be called if the |
175 | | - * item is not in the cache yet or when the cache has been invalidated. |
176 | | - * |
177 | | - * @since 0.1 |
178 | | - * |
179 | | - * @param {function} $callback |
180 | | - * @param array $args |
181 | | - * @param string|null $key |
182 | | - */ |
183 | | - public function addCachedHTML( $callback, $args = array(), $key = null ) { |
184 | | - $this->initCaching(); |
185 | | - |
186 | | - if ( $this->hasCached ) { |
187 | | - $html = ''; |
188 | | - |
189 | | - if ( is_null( $key ) ) { |
190 | | - $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) ); |
191 | | - $itemKey = array_shift( $itemKey ); |
192 | | - |
193 | | - if ( !is_integer( $itemKey ) ) { |
194 | | - wfWarn( "Attempted to get item with non-numeric key while the next item in the queue has a key ($itemKey) in " . __METHOD__ ); |
195 | | - } |
196 | | - elseif ( is_null( $itemKey ) ) { |
197 | | - wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ ); |
198 | | - } |
199 | | - else { |
200 | | - $html = array_shift( $this->cachedChunks ); |
201 | | - } |
202 | | - } |
203 | | - else { |
204 | | - if ( array_key_exists( $key, $this->cachedChunks ) ) { |
205 | | - $html = $this->cachedChunks[$key]; |
206 | | - unset( $this->cachedChunks[$key] ); |
207 | | - } |
208 | | - else { |
209 | | - wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ ); |
210 | | - } |
211 | | - } |
212 | | - } |
213 | | - else { |
214 | | - $html = call_user_func_array( $callback, $args ); |
215 | | - |
216 | | - if ( is_null( $key ) ) { |
217 | | - $this->cachedChunks[] = $html; |
218 | | - } |
219 | | - else { |
220 | | - $this->cachedChunks[$key] = $html; |
221 | | - } |
222 | | - } |
223 | | - |
224 | | - $this->getOutput()->addHTML( $html ); |
225 | | - } |
226 | | - |
227 | | - /** |
228 | | - * Saves the HTML to the cache in case it got recomputed. |
229 | | - * Should be called after the last time anything is added via addCachedHTML. |
230 | | - * |
231 | | - * @since 0.1 |
232 | | - */ |
233 | | - public function saveCache() { |
234 | | - if ( $this->hasCached === false && !empty( $this->cachedChunks ) ) { |
235 | | - wfGetCache( CACHE_ANYTHING )->set( $this->getCacheKey(), $this->cachedChunks, $this->cacheExpiry ); |
236 | | - } |
237 | | - } |
238 | | - |
239 | | - /** |
240 | | - * Sets the time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.. |
241 | | - * |
242 | | - * @since 0.1 |
243 | | - * |
244 | | - * @param integer $cacheExpiry |
245 | | - */ |
246 | | - protected function setExpirey( $cacheExpiry ) { |
247 | | - $this->cacheExpiry = $cacheExpiry; |
248 | | - } |
249 | | - |
250 | | - /** |
251 | | - * Returns the cache key to use to cache this page's HTML output. |
252 | | - * Is constructed from the special page name and language code. |
253 | | - * |
254 | | - * @since 0.1 |
255 | | - * |
256 | | - * @return string |
257 | | - */ |
258 | | - protected function getCacheKey() { |
259 | | - return wfMemcKey( $this->mName, $this->getLanguage()->getCode() ); |
260 | | - } |
261 | | - |
262 | | -} |
Index: trunk/extensions/EducationProgram/EducationProgram.i18n.php |
— | — | @@ -783,7 +783,7 @@ |
784 | 784 | You can find a full list of students on [[Special:Students|the student list]].', |
785 | 785 | 'ep-studentactivity-count' => 'There {{PLURAL:$1|is|are}} currently $1 {{PLURAL:$1|student|students}} that {{PLURAL:$1|was|where}} active in the last 24 hours.', |
786 | 786 | |
787 | | - // Cached special page |
| 787 | + // Cached special page, back compat for MW < 1.20 |
788 | 788 | 'cachedspecial-viewing-cached-ttl' => 'You are viewing a cached version of this page, which can be up to $1 old.', |
789 | 789 | 'cachedspecial-viewing-cached-ts' => 'You are viewing a cached version of this page, which might not be completely actual.', |
790 | 790 | 'cachedspecial-refresh-now' => 'View latest.', |