r67747 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r67746‎ | r67747 | r67748 >
Date:19:17, 9 June 2010
Author:daniel
Status:deferred
Tags:
Comment:
reverting stylizification in r67480; need to commmit some stuff first.
Modified paths:
  • /trunk/extensions/DataTransclusion/DBDataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/DataTransclusion.i18n.magic.php (modified) (history)
  • /trunk/extensions/DataTransclusion/DataTransclusion.php (modified) (history)
  • /trunk/extensions/DataTransclusion/DataTransclusionHandler.php (modified) (history)
  • /trunk/extensions/DataTransclusion/DataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/WebDataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php (modified) (history)

Diff [purge]

Index: trunk/extensions/DataTransclusion/DataTransclusion.i18n.magic.php
@@ -15,6 +15,3 @@
1616 'record' => array( 0, 'record' ),
1717 );
1818
19 -$magicWords['ar'] = array(
20 - 'record' => array( '0', 'تسجيل', 'record' ),
21 -);
\ No newline at end of file
Index: trunk/extensions/DataTransclusion/DataTransclusionHandler.php
@@ -9,314 +9,275 @@
1010 * @licence GNU General Public Licence 2.0 or later
1111 */
1212
13 -class DataTransclusionHandler {
14 - static function buildAssociativeArguments ( $params ) {
15 - // build associative arguments from flat parameter list
16 - $argv = array();
17 - $i = 1;
18 - foreach ( $params as $p ) {
19 - if ( preg_match( '/^\s*(\S.*?)\s*=\s*(.*?)\s*$/', $p, $m ) ) {
20 - $k = $m[1];
21 - $v = preg_replace( '/^"\s*(.*?)\s*"$/', '$1', $m[2] ); // strip any quotes enclosing the value
22 - } else {
23 - $v = trim( $p );
24 - $k = $i;
25 - $i += 1;
26 - }
 13+if( !defined( 'MEDIAWIKI' ) ) {
 14+ echo( "Not a valid entry point.\n" );
 15+ die( 1 );
 16+}
2717
28 - $argv[$k] = $v;
 18+class DataTransclusionHandler {
 19+ static function buildAssociativeArguments ( $params ) {
 20+ // build associative arguments from flat parameter list
 21+ $argv = array();
 22+ $i = 1;
 23+ foreach ( $params as $p ) {
 24+ if ( preg_match( '/^\s*(\S.*?)\s*=\s*(.*?)\s*$/', $p, $m ) ) {
 25+ $k = $m[1];
 26+ $v = preg_replace( '/^"\s*(.*?)\s*"$/', '$1', $m[2] ); // strip any quotes enclosing the value
2927 }
30 -
31 - return $argv;
32 - }
33 -
34 - /**
35 - * Entry point for the {{#record}} parser function.
36 - * This is a wrapper around handleRecordTag
37 - */
38 - static function handleRecordFunction ( $parser ) {
39 - $params = func_get_args();
40 - array_shift( $params ); // first is &$parser, strip it
41 -
42 - // first user-supplied parameter must be category name
43 - if ( !$params ) {
44 - return ''; // no category specified, return nothing
 28+ else {
 29+ $v = trim( $p );
 30+ $k = $i;
 31+ $i += 1;
4532 }
4633
47 - // build associative arguments from flat parameter list
48 - $argv = DataTransclusionHandler::buildAssociativeArguments( $params );
49 -
50 - // FIXME: error messages contining special blocks like <nowiki> don't get re-substitutet correctly.
51 - $text = DataTransclusionHandler::handleRecordTransclusion( null, $argv, $parser, false );
52 -
53 - return array( $text, 'noparse' => false, 'isHTML' => false );
 34+ $argv[$k] = $v;
5435 }
5536
56 - static function errorMessage( $key, $asHTML ) {
57 - $params = func_get_args();
58 - array_shift( $params ); // $key
59 - array_shift( $params ); // $asHTML
 37+ return $argv;
 38+ }
6039
61 - if ( $asHTML ) {
62 - $mode = 'parseinline';
63 - } else {
64 - $mode = 'parsemag';
65 - }
 40+ /**
 41+ * Entry point for the {{#record}} parser function.
 42+ * This is a wrapper around handleRecordTag
 43+ */
 44+ static function handleRecordFunction ( $parser ) {
 45+ $params = func_get_args();
 46+ array_shift( $params ); // first is &$parser, strip it
6647
67 - $m = wfMsgExt( $key, $mode, $params );
 48+ // first user-supplied parameter must be category name
 49+ if ( !$params ) {
 50+ return ''; // no category specified, return nothing
 51+ }
6852
69 - return "<span class=\"error\">$m</span>";
70 - }
 53+ // build associative arguments from flat parameter list
 54+ $argv = DataTransclusionHandler::buildAssociativeArguments( $params );
7155
72 - /**
73 - * Entry point for the <record> tag parser hook. Delegates to handleRecordTransclusion.
74 - */
75 - static function handleRecordTag( $key, $argv, $parser ) {
76 - DataTransclusionHandler::handleRecordTransclusion( $key, $argv, $parser, true );
77 - }
 56+ //FIXME: error messages contining special blocks like <nowiki> don't get re-substitutet correctly.
 57+ $text = DataTransclusionHandler::handleRecordTransclusion( null, $argv, $parser, false );
 58+ return array( $text, 'noparse' => false, 'isHTML' => false );
 59+ }
7860
79 - /**
80 - * Fetches a records and renders it, according to the given array of parameters.
81 - * Common implementation for parser tag and parser function.
82 - */
83 - static function handleRecordTransclusion( $key, $argv, $parser, $asHTML ) {
84 - // find out which data source to use...
85 - if ( empty( $argv['source'] ) ) {
86 - if ( empty( $argv[1] ) ) {
87 - return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-source', $asHTML ); // TESTME
88 - } else {
89 - $sourceName = $argv[1];
90 - }
91 - } else {
92 - $sourceName = $argv['source'];
93 - }
 61+ static function errorMessage( $key, $asHTML ) {
 62+ $params = func_get_args();
 63+ array_shift( $params ); // $key
 64+ array_shift( $params ); // $asHTML
9465
95 - $source = DataTransclusionHandler::getDataSource( $sourceName );
96 - if ( empty( $source ) ) {
97 - return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-source', $asHTML, $sourceName ); // TESTME
98 - }
 66+ if ( $asHTML ) $mode = 'parseinline';
 67+ else $mode = 'parsemag';
9968
100 - // find out how to find the desired record
101 - if ( empty( $argv['by'] ) ) {
102 - $by = $source->getDefaultKey();
103 - } else {
104 - $by = $argv['by'];
105 - }
 69+ $m = wfMsgExt( $key, $mode, $params );
 70+ return "<span class=\"error\">$m</span>";
 71+ }
10672
107 - $keyFields = $source->getKeyFields();
108 - if ( ! in_array( $by, $keyFields ) ) {
109 - return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-argument-by', $asHTML, $sourceName, $by, join( ', ', $keyFields ) ); // TESTME
110 - }
 73+ /**
 74+ * Entry point for the <record> tag parser hook. Delegates to handleRecordTransclusion.
 75+ */
 76+ static function handleRecordTag( $key, $argv, $parser ) {
 77+ DataTransclusionHandler::handleRecordTransclusion( $key, $argv, $parser, true );
 78+ }
11179
112 - if ( !empty( $argv['key'] ) ) {
113 - $key = $argv['key'];
114 - } else if ( $key === null || $key === false ) {
115 - if ( empty( $argv[2] ) ) {
116 - return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-key', $asHTML ); // TESTME
117 - } else {
118 - $key = $argv[2];
119 - }
120 - }
 80+ /**
 81+ * Fetches a records and renders it, according to the given array of parameters.
 82+ * Common implementation for parser tag and parser function.
 83+ */
 84+ static function handleRecordTransclusion( $key, $argv, $parser, $asHTML ) {
 85+ //find out which data source to use...
 86+ if ( empty( $argv['source'] ) ) {
 87+ if ( empty( $argv[1] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-source', $asHTML ); //TESTME
 88+ else $sourceName = $argv[1];
 89+ } else {
 90+ $sourceName = $argv['source'];
 91+ }
12192
122 - // find out how to render the record
123 - if ( empty( $argv['template'] ) ) {
124 - if ( empty( $argv[3] ) ) {
125 - return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML ); // TESTME
126 - } else {
127 - $template = $argv[3];
128 - }
129 - } else {
130 - $template = $argv['template'];
131 - }
 93+ $source = DataTransclusionHandler::getDataSource( $sourceName );
 94+ if ( empty( $source ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-source', $asHTML, $sourceName ); //TESTME
13295
133 - // load the record
134 - $record = $source->fetchRecord( $by, $key );
135 - if ( empty( $record ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-record-not-found', $asHTML, $sourceName, $by, $key ); // TESTME
 96+ //find out how to find the desired record
 97+ if ( empty( $argv['by'] ) ) $by = $source->getDefaultKey();
 98+ else $by = $argv['by'];
13699
137 - // render the record into wiki text
138 - $t = Title::newFromText( $template, NS_TEMPLATE );
139 - if ( empty( $t ) ) {
140 - return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-template-name', $asHTML, $template ); // TESTME
141 - }
 100+ $keyFields = $source->getKeyFields();
 101+ if ( ! in_array( $by, $keyFields ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-argument-by', $asHTML, $sourceName, $by, join(', ', $keyFields) ); //TESTME
142102
143 - // FIXME: log the template we used into the parser output, like regular template use
144 - // (including templates used by the template, etc)
 103+ if ( !empty( $argv['key'] ) ) $key = $argv['key'];
 104+ else if ( $key === null || $key === false ) {
 105+ if ( empty( $argv[2] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-key', $asHTML ); //TESTME
 106+ else $key = $argv[2];
 107+ }
145108
146 - $handler = new DataTransclusionHandler( $parser, $source, $t );
 109+ //find out how to render the record
 110+ if ( empty( $argv['template'] ) ) {
 111+ if ( empty( $argv[3] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML ); //TESTME
 112+ else $template = $argv[3];
 113+ } else {
 114+ $template = $argv['template'];
 115+ }
147116
148 - $record = $handler->normalizeRecord( $record );
149 - $text = $handler->render( $record );
 117+ //load the record
 118+ $record = $source->fetchRecord( $by, $key );
 119+ if ( empty( $record ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-record-not-found', $asHTML, $sourceName, $by, $key ); //TESTME
150120
151 - if ( $text === false ) {
152 - return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-template', $asHTML, $template ); // TESTME
153 - }
 121+ //render the record into wiki text
 122+ $t = Title::newFromText( $template, NS_TEMPLATE );
 123+ if ( empty( $t ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-template-name', $asHTML, $template ); //TESTME
154124
155 - // set parser output expiry
156 - $expire = $source->getCacheDuration();
157 - if ( $expire !== false && $expire !== null ) {
158 - $parser->getOutput()->updateCacheExpiry( $expire ); // NOTE: this works only since r67185 //TESTME
159 - }
 125+ //FIXME: log the template we used into the parser output, like regular template use
 126+ // (including templates used by the template, etc)
160127
161 - if ( $asHTML && $parser ) { // render into HTML if desired
162 - $html = $parser->recursiveTagParse( $text );
163 - return $html; // TESTME
164 - } else {
165 - return $text; // TESTME
166 - }
167 - }
 128+ $handler = new DataTransclusionHandler( $parser, $source, $t );
168129
169 - function __construct( $parser, $source, $template, $templateText = null ) {
170 - $this->template = $template;
171 - $this->source = $source;
172 - $this->parser = $parser;
173 - $this->templateText = $templateText;
174 - }
 130+ $record = $handler->normalizeRecord( $record );
 131+ $text = $handler->render( $record );
175132
176 - function render( $record ) {
177 - // XXX: use cached & preparsed template. $template doesn't have the right type, it seems
178 - /*
179 - list( $text, $this->template ) = $this->parser->getTemplateDom( $this->template );
180 - $frame = $this->parser->getPreprocessor()->newCustomFrame( $record );
181 - $text = $frame->expand( $template );
182 - */
 133+ if ( $text === false ) return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-template', $asHTML, $template ); //TESTME
183134
184 - // XXX: trying another way. but $piece['parts'] needs to be a PPNode. how to do that?
185 - /*
186 - $frame = $this->parser->getPreprocessor()->newCustomFrame( $record );
 135+ //set parser output expiry
 136+ $expire = $source->getCacheDuration();
 137+ if ( $expire !== false && $expire !== null ) {
 138+ $parser->getOutput()->updateCacheExpiry( $expire ); //NOTE: this works only since r67185 //TESTME
 139+ }
187140
188 - $piece = array();
 141+ if ( $asHTML && $parser ) { //render into HTML if desired
 142+ $html = $parser->recursiveTagParse( $text );
 143+ return $html; //TESTME
 144+ } else {
 145+ return $text; //TESTME
 146+ }
 147+ }
189148
190 - if ( $this->template->getNamespace() == NS_TEMPLATE ) $n = "";
191 - else $n = $this->template->getNsText() . ":";
 149+ function __construct( $parser, $source, $template, $templateText = null ) {
 150+ $this->template = $template;
 151+ $this->source = $source;
 152+ $this->parser = $parser;
 153+ $this->templateText = $templateText;
 154+ }
192155
193 - $piece ['title'] = $n . $this->template->getText();
194 - $piece['parts'] = $record;
195 - $piece['lineStart'] = false; //XXX: ugly. can't know here whether the brace was at the start of a line
 156+ function render( $record ) {
 157+ //XXX: use cached & preparsed template. $template doesn't have the right type, it seems
 158+ /*
 159+ list( $text, $this->template ) = $this->parser->getTemplateDom( $this->template );
 160+ $frame = $this->parser->getPreprocessor()->newCustomFrame( $record );
 161+ $text = $frame->expand( $template );
 162+ */
196163
197 - $ret = $this->parser->braceSubstitution( $piece, $frame );
198 - $text = $ret[ 'text' ];
199 - */
 164+ //XXX: trying another way. but $piece['parts'] needs to be a PPNode. how to do that?
 165+ /*
 166+ $frame = $this->parser->getPreprocessor()->newCustomFrame( $record );
200167
201 - // dumb and slow, but works
202 - if ( $this->templateText ) {
203 - if ( is_string( $this->templateText ) ) {
204 - $text = $this->templateText;
205 - } else {
206 - $text = $this->templateText->getContent();
207 - }
208 - } else {
209 - $article = new Article( $this->template );
210 - if ( !$article->exists() ) {
211 - return false; // TESTME
212 - }
 168+ $piece = array();
213169
214 - $text = $article->getContent();
215 - }
 170+ if ( $this->template->getNamespace() == NS_TEMPLATE ) $n = "";
 171+ else $n = $this->template->getNsText() . ":";
216172
217 - $text = $this->parser->replaceVariables( $text, $record, true );
 173+ $piece ['title'] = $n . $this->template->getText();
 174+ $piece['parts'] = $record;
 175+ $piece['lineStart'] = false; //XXX: ugly. can't know here whether the brace was at the start of a line
218176
219 - return $text;
220 - }
 177+ $ret = $this->parser->braceSubstitution( $piece, $frame );
 178+ $text = $ret[ 'text' ];
 179+ */
221180
222 - function normalizeRecord( $record ) {
223 - $rec = array();
 181+ //dumb and slow, but works
 182+ if ( $this->templateText ) {
 183+ if ( is_string( $this->templateText ) ) $text = $this->templateText;
 184+ else $text = $this->templateText->getContent();
 185+ } else {
 186+ $article = new Article( $this->template );
 187+ if ( !$article->exists() ) return false; //TESTME
224188
225 - // keep record fields, add missing values
226 - $fields = $this->source->getFieldNames();
227 - foreach ( $fields as $f ) {
228 - if ( isset( $record[ $f ] ) ) {
229 - $v = $record[ $f ];
230 - } else {
231 - $v = '';
232 - }
 189+ $text = $article->getContent();
 190+ }
233191
234 - $rec[ $f ] = $this->sanitizeValue( $v ); // TESTME
235 - }
 192+ $text = $this->parser->replaceVariables( $text, $record, true );
236193
237 - // add source meta info, so we can render links back to the source,
238 - // provide license info, etc
239 - $info = $this->source->getSourceInfo(); // TESTME
240 - foreach ( $info as $f => $v ) {
241 - if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) {
242 - continue;
243 - }
 194+ return $text;
 195+ }
244196
245 - $rec[ "source.$f" ] = $this->sanitizeValue( $v );
246 - }
 197+ function normalizeRecord( $record ) {
 198+ $rec = array();
247199
248 - return $rec;
249 - }
 200+ //keep record fields, add missing values
 201+ $fields = $this->source->getFieldNames();
 202+ foreach ( $fields as $f ) {
 203+ if ( isset( $record[ $f ] ) ) $v = $record[ $f ];
 204+ else $v = '';
250205
251 - protected static $sanitizerSubstitution = array(
252 - # '!&!' => '&amp;', #breaks URLs. not really needed when parsed as wiki-text...
253 - '!&(#?x?[\w\d]+);!' => '&amp;$1;',
254 - '!<!' => '&lt;',
255 - '!>!' => '&gt;',
256 - '!\[!' => '&#91;',
257 - '!\]!' => '&#93;',
258 - '!\{!' => '&#123;',
259 - '!\}!' => '&#125;',
260 - '!\'!' => '&apos;',
261 - '!\|!' => '&#124;',
262 - '!^\*!m' => '&#42;',
263 - '!^#!m' => '&#35;',
264 - '!^:!m' => '&#58;',
265 - '!^;!m' => '&#59;',
266 - '![\r\n]!' => ' ',
267 - '!^ !m' => '&#32;',
268 - );
 206+ $rec[ $f ] = $this->sanitizeValue( $v ); //TESTME
 207+ }
269208
270 - static function sanitizeValue( $v ) {
271 - $find = array_keys( self::$sanitizerSubstitution );
272 - $subst = array_values( self::$sanitizerSubstitution );
 209+ //add source meta info, so we can render links back to the source,
 210+ //provide license info, etc
 211+ $info = $this->source->getSourceInfo(); //TESTME
 212+ foreach ( $info as $f => $v ) {
 213+ if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) continue;
 214+ $rec[ "source.$f" ] = $this->sanitizeValue( $v );
 215+ }
273216
274 - $v = preg_replace( $find, $subst, $v );
 217+ return $rec;
 218+ }
275219
276 - return $v;
277 - }
 220+ protected static $sanitizerSubstitution = array(
 221+ # '!&!' => '&amp;', #breaks URLs. not really needed when parsed as wiki-text...
 222+ '!&(#?x?[\w\d]+);!' => '&amp;$1;',
 223+ '!<!' => '&lt;',
 224+ '!>!' => '&gt;',
 225+ '!\[!' => '&#91;',
 226+ '!\]!' => '&#93;',
 227+ '!\{!' => '&#123;',
 228+ '!\}!' => '&#125;',
 229+ '!\'!' => '&apos;',
 230+ '!\|!' => '&#124;',
 231+ '!^\*!m' => '&#42;',
 232+ '!^#!m' => '&#35;',
 233+ '!^:!m' => '&#58;',
 234+ '!^;!m' => '&#59;',
 235+ '![\r\n]!' => ' ',
 236+ '!^ !m' => '&#32;',
 237+ );
278238
279 - static function getDataSource( $name ) {
280 - global $wgDataTransclusionSources;
281 - if ( empty( $wgDataTransclusionSources[ $name ] ) ) {
282 - return false;
283 - }
 239+ static function sanitizeValue( $v ) {
 240+ $find = array_keys( self::$sanitizerSubstitution );
 241+ $subst = array_values( self::$sanitizerSubstitution );
284242
285 - $source = $wgDataTransclusionSources[ $name ];
 243+ $v = preg_replace( $find, $subst, $v );
 244+ return $v;
 245+ }
286246
287 - if ( is_array( $source ) ) { // if the source is an array, use it to instantiate the sourece object
288 - $spec = $source;
289 - $spec[ 'name' ] = $name;
 247+ static function getDataSource( $name ) {
 248+ global $wgDataTransclusionSources;
 249+ if ( empty( $wgDataTransclusionSources[ $name ] ) ) return false;
290250
291 - if ( !isset( $spec[ 'class' ] ) ) {
292 - throw new MWException( "\$wgDataTransclusionSources['$name'] must specifying a class name in the 'class' field." );
293 - }
 251+ $source = $wgDataTransclusionSources[ $name ];
294252
295 - $c = $spec[ 'class' ];
296 - $obj = new $c( $spec ); // pass spec array as constructor argument
297 - if ( !$obj ) {
298 - throw new MWException( "failed to instantiate \$wgDataTransclusionSources['$name'] as new $c." );
299 - }
 253+ if ( is_array( $source ) ) { //if the source is an array, use it to instantiate the sourece object
 254+ $spec = $source;
 255+ $spec[ 'name' ] = $name;
300256
301 - $source = $obj;
 257+ if ( !isset( $spec[ 'class' ] ) ) throw new MWException( "\$wgDataTransclusionSources['$name'] must specifying a class name in the 'class' field." );
302258
303 - if ( isset( $spec[ 'cache' ] ) ) { // check if a cache should be used
304 - $c = $spec[ 'cache' ];
305 - if ( !is_object( $c ) ) { // cache may be specified as a string
306 - $c = wfGetCache( $c ); // $c should be one of the CACHE_* constants
307 - }
 259+ $c = $spec[ 'class' ];
 260+ $obj = new $c( $spec ); //pass spec array as constructor argument
 261+ if ( !$obj ) throw new MWException( "failed to instantiate \$wgDataTransclusionSources['$name'] as new $c." );
308262
309 - $source = new CachingDataTransclusionSource( $obj, $c, @$spec['cache-duration'] ); // apply caching wrapper
310 - }
 263+ $source = $obj;
311264
312 - $wgDataTransclusionSources[ $name ] = $source; // replace spec array by actual object, for later re-use
313 - }
 265+ if ( isset( $spec[ 'cache' ] ) ) { //check if a cache should be used
 266+ $c = $spec[ 'cache' ];
 267+ if ( !is_object( $c ) ) { //cache may be specified as a string
 268+ $c = wfGetCache( $c ); // $c should be one of the CACHE_* constants
 269+ }
314270
315 - if ( !is_object( $source ) ) {
316 - if ( !isset( $source[ 'class' ] ) ) {
317 - throw new MWException( "\$wgDataTransclusionSources['$name'] must be an array or an object." );
318 - }
 271+ $source = new CachingDataTransclusionSource( $obj, $c, @$spec['cache-duration'] ); //apply caching wrapper
319272 }
320273
321 - return $source;
322 - }
 274+ $wgDataTransclusionSources[ $name ] = $source; //replace spec array by actual object, for later re-use
 275+ }
 276+
 277+ if ( !is_object( $source ) ) {
 278+ if ( !isset( $source[ 'class' ] ) ) throw new MWException( "\$wgDataTransclusionSources['$name'] must be an array or an object." );
 279+ }
 280+
 281+ return $source;
 282+ }
 283+
323284 }
Index: trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php
@@ -11,7 +11,7 @@
1212 else $IP = $dir;
1313 }
1414
15 -if ( isset( $GET_ ) ) {
 15+if( isset( $GET_ ) ) {
1616 echo( "This file cannot be run from the web.\n" );
1717 die( 1 );
1818 }
@@ -21,16 +21,19 @@
2222 // requires PHPUnit 3.4
2323 require_once 'PHPUnit/Framework.php';
2424
25 -error_reporting( E_ALL );
 25+error_reporting(E_ALL);
2626
2727 class DataTransclusionTest extends PHPUnit_Framework_TestCase {
28 - function setUp() {
 28+
 29+ function setUp()
 30+ {
2931 global $wgTitle;
3032
3133 $wgTitle = Title::newFromText( "Test" );
3234 }
33 -
34 - function runTest() {
 35+
 36+ function runTest()
 37+ {
3538 $this->testErrorMessage();
3639 $this->testSanitizeValue();
3740 $this->testNormalizeRecord();
@@ -43,23 +46,23 @@
4447 }
4548
4649 function testErrorMessage() {
47 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-wikitext', false );
48 - $this->assertEquals( $m, '<span class="error">some <span class="test">html</span> and \'\'markup\'\'.</span>' );
 50+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-wikitext', false);
 51+ $this->assertEquals( $m, '<span class="error">some <span class="test">html</span> and \'\'markup\'\'.</span>' );
4952
50 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-evil-html', false );
51 - $this->assertEquals( $m, '<span class="error">some <object>evil</object> html.</span>' );
 53+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-evil-html', false);
 54+ $this->assertEquals( $m, '<span class="error">some <object>evil</object> html.</span>' );
5255
53 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-nowiki', false );
54 - $this->assertEquals( $m, '<span class="error">some <nowiki>{{nowiki}}</nowiki> code.</span>' );
 56+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-nowiki', false);
 57+ $this->assertEquals( $m, '<span class="error">some <nowiki>{{nowiki}}</nowiki> code.</span>' );
5558
56 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-wikitext', true );
57 - $this->assertEquals( $m, '<span class="error">some <span class="test">html</span> and <i>markup</i>.</span>' );
 59+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-wikitext', true);
 60+ $this->assertEquals( $m, '<span class="error">some <span class="test">html</span> and <i>markup</i>.</span>' );
5861
59 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-evil-html', true );
60 - $this->assertEquals( $m, '<span class="error">some &lt;object&gt;evil&lt;/object&gt; html.</span>' );
 62+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-evil-html', true);
 63+ $this->assertEquals( $m, '<span class="error">some &lt;object&gt;evil&lt;/object&gt; html.</span>' );
6164
62 - $m = DataTransclusionHandler::errorMessage( 'datatransclusion-test-nowiki', true );
63 - $this->assertEquals( $m, '<span class="error">some {{nowiki}} code.</span>' );
 65+ $m = DataTransclusionHandler::errorMessage('datatransclusion-test-nowiki', true);
 66+ $this->assertEquals( $m, '<span class="error">some {{nowiki}} code.</span>' );
6467 }
6568
6669 function testSanitizeValue() {
@@ -84,17 +87,17 @@
8588 }
8689
8790 function testNormalizeRecord() {
88 - // TODO...
 91+ //TODO...
8992 }
9093
9194 function testBuildAssociativeArguments() {
9295 $args = array( "foo bar", "x=y", " ah = \"be\" ", "blubber bla" );
9396 $assoc = DataTransclusionhandler::buildAssociativeArguments( $args );
9497
95 - $this->asserttrue( !isset( $assoc[0] ) );
96 - $this->asserttrue( !isset( $assoc[3] ) );
97 - $this->asserttrue( !isset( $assoc['foo'] ) );
98 - $this->asserttrue( !isset( $assoc['foo bar'] ) );
 98+ $this->asserttrue( !isset($assoc[0]) );
 99+ $this->asserttrue( !isset($assoc[3]) );
 100+ $this->asserttrue( !isset($assoc['foo']) );
 101+ $this->asserttrue( !isset($assoc['foo bar']) );
99102 $this->assertEquals( $assoc[1], 'foo bar' );
100103 $this->assertEquals( $assoc[2], 'blubber bla' );
101104 $this->assertEquals( $assoc['x'], 'y' );
@@ -105,24 +108,24 @@
106109 global $wgDataTransclusionSources;
107110
108111 $spec = array( 'name' => 'FOO', 'keyFields' => 'name,id', 'fieldNames' => 'id,name,info' );
109 - $data[] = array( "name" => "foo", "id" => 3, "info" => 'test 1' );
110 - $data[] = array( "name" => "bar", "id" => 5, "info" => 'test 2' );
 112+ $data[] = array( "name" => "foo", "id" => 3, "info" => 'test 1');
 113+ $data[] = array( "name" => "bar", "id" => 5, "info" => 'test 2');
111114 $wgDataTransclusionSources[ 'FOO' ] = new FakeDataTransclusionSource( $spec, $data );
112115
113116 $src = DataTransclusionHandler::getDataSource( 'FOO' );
114117 $this->assertTrue( $src instanceof FakeDataTransclusionSource );
115 -
 118+
116119 $rec = $src->fetchRecord( 'id', 3 );
117120 $this->assertEquals( $rec['id'], 3 );
118121 $this->assertEquals( $rec['name'], 'foo' );
119122 $this->assertEquals( $rec['info'], 'test 1' );
120 -
 123+
121124 $rec = $src->fetchRecord( 'name', 'bar' );
122125 $this->assertEquals( $rec['id'], 5 );
123126 $this->assertEquals( $rec['name'], 'bar' );
124127 $this->assertEquals( $rec['info'], 'test 2' );
125128
126 - // /////////////////////////////////////////////////////////////////////////////
 129+ ///////////////////////////////////////////////////////////////////////////////
127130 $spec[ 'class' ] = 'FakeDataTransclusionSource';
128131 $spec[ 'data' ] = $data;
129132
@@ -131,12 +134,12 @@
132135 $src = DataTransclusionHandler::getdataSource( 'BAR' );
133136 $this->assertTrue( $src instanceof FakeDataTransclusionSource );
134137 $this->assertEquals( $src->getName(), 'BAR' );
135 -
 138+
136139 $rec = $src->fetchRecord( 'id', 3 );
137140 $this->assertEquals( $rec['id'], 3 );
138141 $this->assertEquals( $rec['name'], 'foo' );
139142 $this->assertEquals( $rec['info'], 'test 1' );
140 -
 143+
141144 $rec = $src->fetchRecord( 'name', 'bar' );
142145 $this->assertEquals( $rec['id'], 5 );
143146 $this->assertEquals( $rec['name'], 'bar' );
@@ -157,7 +160,7 @@
158161
159162 $source = null;
160163 $title = Title::newFromText( "Template:Thing" );
161 - $rec = array( "name" => "foo", "id" => 3, "info" => 'test X' );
 164+ $rec = array( "name" => "foo", "id" => 3, "info" => 'test X');
162165 $template = "{{{id}}}|{{{name}}}|{{{info}}}";
163166
164167 $handler = new DataTransclusionHandler( $wgParser, $source, $title, $template );
@@ -169,39 +172,39 @@
170173 function testCachedFetchRecord() {
171174 global $wgDataTransclusionSources;
172175
173 - $data[] = array( "name" => "foo", "id" => 3, "info" => 'test 1' );
174 - $data[] = array( "name" => "bar", "id" => 5, "info" => 'test 2' );
175 - $spec = array(
176 - 'class' => 'FakeDataTransclusionSource',
 176+ $data[] = array( "name" => "foo", "id" => 3, "info" => 'test 1');
 177+ $data[] = array( "name" => "bar", "id" => 5, "info" => 'test 2');
 178+ $spec = array(
 179+ 'class' => 'FakeDataTransclusionSource',
177180 'data' => $data,
178 - 'keyFields' => 'name,id',
 181+ 'keyFields' => 'name,id',
179182 'fieldNames' => 'id,name,info',
180 - 'cacheDuration' => 2,
181 - 'cache' => new HashBagOStuff(),
 183+ 'cacheDuration' => 2,
 184+ 'cache' => new HashBagOStuff(),
182185 );
183 -
 186+
184187 $wgDataTransclusionSources[ 'FOO' ] = $spec;
185188
186189 $src = DataTransclusionHandler::getDataSource( 'FOO' );
187190 $this->assertTrue( $src instanceof CachingDataTransclusionSource );
188191
189 - // get original version
 192+ //get original version
190193 $rec = $src->fetchRecord( 'id', 3 );
191194 $this->assertEquals( $rec['id'], 3 );
192195 $this->assertEquals( $rec['name'], 'foo' );
193196 $this->assertEquals( $rec['info'], 'test 1' );
194197
195 - // change record
196 - $rec = array( "name" => "foo", "id" => 3, "info" => 'test X' );
 198+ //change record
 199+ $rec = array( "name" => "foo", "id" => 3, "info" => 'test X');
197200 $src->source->putRecord( $rec );
198201
199 - // fetch record - should be the cached version
 202+ //fetch record - should be the cached version
200203 $rec = $src->fetchRecord( 'id', 3 );
201204 $this->assertEquals( $rec['info'], 'test 1' );
202205
203 - sleep( 3 );
 206+ sleep(3);
204207
205 - // fetch record - cached version should have expired
 208+ //fetch record - cached version should have expired
206209 $rec = $src->fetchRecord( 'id', 3 );
207210 $this->assertEquals( $rec['info'], 'test X' );
208211 }
@@ -224,3 +227,4 @@
225228 $t->runTest();
226229
227230 echo "OK.\n";
 231+?>
\ No newline at end of file
Index: trunk/extensions/DataTransclusion/WebDataTransclusionSource.php
@@ -9,170 +9,133 @@
1010 * @licence GNU General Public Licence 2.0 or later
1111 */
1212
13 -if ( !defined( 'MEDIAWIKI' ) ) {
 13+if( !defined( 'MEDIAWIKI' ) ) {
1414 echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
1515 die( 1 );
1616 }
1717
1818 /**
19 - * Implementations of DataTransclusionSource, fetching data records via HTTP,
20 - * usually from an web API.
21 - *
22 - * In addition to the options supported by the DataTransclusionSource base class,
23 - * WebDataTransclusionSource accepts some additional options
24 - *
25 - * * $spec['url']: base URL for building urls for retrieving individual records.
26 - * The key/value pair is appended to the URL as a regular URL
27 - * parameter (preceeded by ? or &, as appropriate). For more
28 - * complex rules for building the url, override getRecordURL(). REQUIRED.
29 - * * $spec['dataFormat']: Serialization format returned from the web service.
30 - * Supported values are 'php' for PHP serialization format, 'json'
31 - * for JavaScript syntax, and 'wddx' for XML-based list/dicts.
32 - * To support more formats, override decodeData(). Default is 'php'.
33 - * * $spec['dataPath']: "path" to the actual data in the structure returned from the
34 - * HTTP request. The response data is assumed to consit of nested arrays. Each entry
35 - * In the path navigates one step in this structure. Each entry can be either a
36 - * string (for a lookup in an associative array), and int (an index in a list), or
37 - * a "meta-key" of the form @@N, where N is an integer. A meta-key refers to the
38 - * Nth entry in an associative array: @1 would be "bar" in array( 'x' => "foo", 'y' => "bar" ).
39 - * For more complex retrieval of the record, override extractRecord(). REQUIRED.
40 - * * $spec['errorPath']: "path" to error messages in the structure returned from the
41 - * HTTP request. The path is evaluated as deswcribed for $spec['dataPath']. If an
42 - * entry is found at the given position in the response structure, the request
43 - * is assumed to have failed. For more complex detection of errors, override
44 - * extractError(). REQUIRED.
45 - * * $spec['httpOptions']: array of options to pass to Http::get. For details, see Http::request.
46 - * * $spec['timeout']: seconds before the request times out. If not given,
47 - * $spec['httpOptions']['timeout'] is used. If both are not givern, 5 seconds are assumed.
48 - *
49 - * For more information on options supported by DataTransclusionSource, see the class-level
50 - * documentation there.
51 - */
 19+* Implementations of DataTransclusionSource, fetching data records via HTTP,
 20+* usually from an web API.
 21+*
 22+* In addition to the options supported by the DataTransclusionSource base class,
 23+* WebDataTransclusionSource accepts some additional options
 24+*
 25+* * $spec['url']: base URL for building urls for retrieving individual records.
 26+* The key/value pair is appended to the URL as a regular URL
 27+* parameter (preceeded by ? or &, as appropriate). For more
 28+* complex rules for building the url, override getRecordURL(). REQUIRED.
 29+* * $spec['dataFormat']: Serialization format returned from the web service.
 30+* Supported values are 'php' for PHP serialization format, 'json'
 31+* for JavaScript syntax, and 'wddx' for XML-based list/dicts.
 32+* To support more formats, override decodeData(). Default is 'php'.
 33+* * $spec['dataPath']: "path" to the actual data in the structure returned from the
 34+* HTTP request. The response data is assumed to consit of nested arrays. Each entry
 35+* In the path navigates one step in this structure. Each entry can be either a
 36+* string (for a lookup in an associative array), and int (an index in a list), or
 37+* a "meta-key" of the form @@N, where N is an integer. A meta-key refers to the
 38+* Nth entry in an associative array: @1 would be "bar" in array( 'x' => "foo", 'y' => "bar" ).
 39+* For more complex retrieval of the record, override extractRecord(). REQUIRED.
 40+* * $spec['errorPath']: "path" to error messages in the structure returned from the
 41+* HTTP request. The path is evaluated as deswcribed for $spec['dataPath']. If an
 42+* entry is found at the given position in the response structure, the request
 43+* is assumed to have failed. For more complex detection of errors, override
 44+* extractError(). REQUIRED.
 45+* * $spec['httpOptions']: array of options to pass to Http::get. For details, see Http::request.
 46+* * $spec['timeout']: seconds before the request times out. If not given,
 47+* $spec['httpOptions']['timeout'] is used. If both are not givern, 5 seconds are assumed.
 48+*
 49+* For more information on options supported by DataTransclusionSource, see the class-level
 50+* documentation there.
 51+*/
5252 class WebDataTransclusionSource extends DataTransclusionSource {
53 - function __construct( $spec ) {
54 - DataTransclusionSource::__construct( $spec );
5553
56 - $this->url = $spec[ 'url' ];
57 - $this->dataFormat = @$spec[ 'dataFormat' ];
58 - $this->dataPath = DataTransclusionSource::splitList( @$spec[ 'dataPath' ] );
59 - $this->errorPath = DataTransclusionSource::splitList( @$spec[ 'errorPath' ] );
60 - $this->httpOptions = @$spec[ 'httpOptions' ];
61 - $this->timeout = @$spec[ 'timeout' ];
 54+ function __construct( $spec ) {
 55+ DataTransclusionSource::__construct( $spec );
6256
63 - if ( !$this->dataFormat ) {
64 - $this->dataFormat = 'php';
65 - }
 57+ $this->url = $spec[ 'url' ];
 58+ $this->dataFormat = @$spec[ 'dataFormat' ];
 59+ $this->dataPath = DataTransclusionSource::splitList( @$spec[ 'dataPath' ] );
 60+ $this->errorPath = DataTransclusionSource::splitList( @$spec[ 'errorPath' ] );
 61+ $this->httpOptions = @$spec[ 'httpOptions' ];
 62+ $this->timeout = @$spec[ 'timeout' ];
6663
67 - if ( !$this->timeout ) {
68 - $this->timeout = &$this->httpOptions[ 'timeout' ];
69 - }
 64+ if ( !$this->dataFormat ) $this->dataFormat = 'php';
 65+ if ( !$this->timeout ) $this->timeout = &$this->httpOptions[ 'timeout' ];
 66+ if ( !$this->timeout ) $this->timeout = 5;
 67+ }
7068
71 - if ( !$this->timeout ) {
72 - $this->timeout = 5;
73 - }
74 - }
 69+ public function fetchRecord( $field, $value ) {
 70+ $raw = $this->loadRecordData( $field, $value ); //TESTME
 71+ if ( !$raw ) return false; //TODO: log error?
7572
76 - public function fetchRecord( $field, $value ) {
77 - $raw = $this->loadRecordData( $field, $value ); // TESTME
78 - if ( !$raw ) {
79 - return false; // TODO: log error?
80 - }
 73+ $data = $this->decodeData( $raw, $this->dataFormat ); //TESTME
 74+ if ( !$data ) return false; //TODO: log error?
8175
82 - $data = $this->decodeData( $raw, $this->dataFormat ); // TESTME
83 - if ( !$data ) {
84 - return false; // TODO: log error?
85 - }
 76+ $err = $this->extractError( $data ); //TESTME
 77+ if ( $err ) return false; //TODO: log error?
 78+
 79+ $rec = $this->extractRecord( $data ); //TESTME
 80+ if ( !$rec ) return false; //TODO: log error?
8681
87 - $err = $this->extractError( $data ); // TESTME
88 - if ( $err ) {
89 - return false; // TODO: log error?
90 - }
 82+ return $rec;
 83+ }
9184
92 - $rec = $this->extractRecord( $data ); // TESTME
93 - if ( !$rec ) {
94 - return false; // TODO: log error?
95 - }
 85+ protected function getRecordURL( $field, $value ) {
 86+ $u = $this->url;
9687
97 - return $rec;
98 - }
 88+ if ( strpos( $u, '?' ) === false ) $u .= '?';
 89+ else $u .= '&';
9990
100 - protected function getRecordURL( $field, $value ) {
101 - $u = $this->url;
 91+ $u .= $field;
 92+ $u .= '=';
 93+ $u .= urlencode( $value );
10294
103 - if ( strpos( $u, '?' ) === false ) {
104 - $u .= '?';
105 - } else {
106 - $u .= '&';
107 - }
 95+ return $u;
 96+ }
10897
109 - $u .= $field;
110 - $u .= '=';
111 - $u .= urlencode( $value );
 98+ protected function loadRecordData( $field, $value ) {
 99+ $u = $this->getRecordURL( $field, $value );
112100
113 - return $u;
114 - }
 101+ $raw = Http::get( $u, $this->timeout, $this->httpOptions );
 102+ return $raw;
 103+ }
115104
116 - protected function loadRecordData( $field, $value ) {
117 - $u = $this->getRecordURL( $field, $value );
 105+ protected function decodeData( $raw, $format = 'php' ) {
 106+ if ( $format == 'json' ) return FormatJson::decode( $raw, true ); //TESTME
 107+ if ( $format == 'wddx' ) return wddx_unserialize( $raw ); //TESTME
 108+ if ( $format == 'php' ) return unserialize( $raw ); //TESTME
118109
119 - $raw = Http::get( $u, $this->timeout, $this->httpOptions );
 110+ return false;
 111+ }
120112
121 - return $raw;
122 - }
 113+ protected function extractError( $data ) {
 114+ return $this->extractField( $data, $this->errorPath );
 115+ }
123116
124 - protected function decodeData( $raw, $format = 'php' ) {
125 - if ( $format == 'json' ) {
126 - return FormatJson::decode( $raw, true ); // TESTME
127 - }
 117+ protected function extractRecord( $data ) {
 118+ return $this->extractField( $data, $this->dataPath );
 119+ }
128120
129 - if ( $format == 'wddx' ) {
130 - return wddx_unserialize( $raw ); // TESTME
131 - }
 121+ protected function extractField( $data, $path ) {
 122+ if ( $path == null ) return $data;
 123+ if ( is_string( $path ) ) return @$data[ $path ];
132124
133 - if ( $format == 'php' ) {
134 - return unserialize( $raw ); // TESTME
135 - }
 125+ foreach ( $path as $p ) {
 126+ if ( is_object( $data ) ) $data = wfObjectToArray( $data );
136127
137 - return false;
138 - }
 128+ // meta-key: index in the list of array-keys.
 129+ // e.g. use @0 to grab the first value from an assoc array.
 130+ if ( is_string( $p ) && preg_match( '/^@(\d+)$/', $p, $m ) ) {
 131+ $i = (int)$m[1];
 132+ $k = array_keys( $data );
 133+ $p = $k[ $i ];
 134+ }
139135
140 - protected function extractError( $data ) {
141 - return $this->extractField( $data, $this->errorPath );
142 - }
 136+ if ( !isset( $data[ $p ] ) ) return false;
 137+ $data = $data[ $p ];
 138+ }
143139
144 - protected function extractRecord( $data ) {
145 - return $this->extractField( $data, $this->dataPath );
146 - }
147 -
148 - protected function extractField( $data, $path ) {
149 - if ( $path == null ) {
150 - return $data;
151 - }
152 -
153 - if ( is_string( $path ) ) {
154 - return @$data[ $path ];
155 - }
156 -
157 - foreach ( $path as $p ) {
158 - if ( is_object( $data ) ) {
159 - $data = wfObjectToArray( $data );
160 - }
161 -
162 - // meta-key: index in the list of array-keys.
163 - // e.g. use @0 to grab the first value from an assoc array.
164 - if ( is_string( $p ) && preg_match( '/^@(\d+)$/', $p, $m ) ) {
165 - $i = (int)$m[1];
166 - $k = array_keys( $data );
167 - $p = $k[ $i ];
168 - }
169 -
170 - if ( !isset( $data[ $p ] ) ) {
171 - return false;
172 - }
173 -
174 - $data = $data[ $p ];
175 - }
176 -
177 - return $data;
178 - }
 140+ return $data;
 141+ }
179142 }
Index: trunk/extensions/DataTransclusion/DataTransclusion.php
@@ -9,7 +9,7 @@
1010 * @licence GNU General Public Licence 2.0 or later
1111 */
1212
13 -if ( !defined( 'MEDIAWIKI' ) ) {
 13+if( !defined( 'MEDIAWIKI' ) ) {
1414 echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
1515 die( 1 );
1616 }
@@ -22,26 +22,26 @@
2323 'descriptionmsg' => 'datatransclusion-desc',
2424 );
2525
26 -$dir = dirname( __FILE__ ) . '/';
 26+$dir = dirname(__FILE__) . '/';
2727 $wgExtensionMessagesFiles['DataTransclusion'] = $dir . 'DataTransclusion.i18n.php';
2828 $wgExtensionMessagesFiles['DataTransclusionMagic'] = $dir . 'DataTransclusion.i18n.magic.php';
2929
30 -$wgAutoloadClasses['DataTransclusionRenderer'] = $dir . 'DataTransclusionRenderer.php';
31 -$wgAutoloadClasses['DataTransclusionHandler'] = $dir . 'DataTransclusionHandler.php';
32 -$wgAutoloadClasses['DataTransclusionSource'] = $dir . 'DataTransclusionSource.php';
33 -$wgAutoloadClasses['CachingDataTransclusionSource'] = $dir . 'DataTransclusionSource.php';
34 -$wgAutoloadClasses['FakeDataTransclusionSource'] = $dir . 'DataTransclusionSource.php';
35 -$wgAutoloadClasses['DBDataTransclusionSource'] = $dir . 'DBDataTransclusionSource.php';
36 -$wgAutoloadClasses['WebDataTransclusionSource'] = $dir . 'WebDataTransclusionSource.php';
 30+$wgAutoloadClasses['DataTransclusionRenderer'] = $dir. 'DataTransclusionRenderer.php';
 31+$wgAutoloadClasses['DataTransclusionHandler'] = $dir. 'DataTransclusionHandler.php';
 32+$wgAutoloadClasses['DataTransclusionSource'] = $dir. 'DataTransclusionSource.php';
 33+$wgAutoloadClasses['CachingDataTransclusionSource'] = $dir. 'DataTransclusionSource.php';
 34+$wgAutoloadClasses['FakeDataTransclusionSource'] = $dir. 'DataTransclusionSource.php';
 35+$wgAutoloadClasses['DBDataTransclusionSource'] = $dir. 'DBDataTransclusionSource.php';
 36+$wgAutoloadClasses['WebDataTransclusionSource'] = $dir. 'WebDataTransclusionSource.php';
3737
3838 $wgHooks['ParserFirstCallInit'][] = 'efDataTransclusionSetHooks';
3939
40 -// TODO: Special Page for displaying all configured data sources
 40+//TODO: Special Page for displaying all configured data sources
4141
4242 $wgDataTransclusionSources = array();
4343
4444 function efDataTransclusionSetHooks( $parser ) {
4545 $parser->setHook( 'record' , 'DataTransclusionHandler::handleRecordTag' );
46 - $parser->setFunctionHook( 'record' , 'DataTransclusionHandler::handleRecordFunction' );
 46+ $parser->setFunctionHook( 'record' , 'DataTransclusionHandler::handleRecordFunction' );
4747 return true;
4848 }
Index: trunk/extensions/DataTransclusion/DataTransclusionSource.php
@@ -9,232 +9,215 @@
1010 * @licence GNU General Public Licence 2.0 or later
1111 */
1212
13 -if ( !defined( 'MEDIAWIKI' ) ) {
 13+if( !defined( 'MEDIAWIKI' ) ) {
1414 echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
1515 die( 1 );
1616 }
1717
1818 /**
19 - * Baseclass representing a source of data transclusion. All logic for addressing, fetching, decoding and filtering
20 - * data is encapsulated by a subclass of DataTransclusionSource. Instances of DataTransclusionSource are instantiated
21 - * by DataTransclusionHandler, and initialized by passing an associative array of options to the constructor. This array
22 - * is taken from the $wgDataTransclusionSources configuration variable.
23 - *
24 - * Below is a list of options for the $spec array, as handled by the DataTransclusionSource
25 - * base class (sublcasses may handle additional options):
26 - *
27 - * * $spec['name']: the source's name, used to specify it in wiki text.
28 - * Set automatically by DataTransclusionHandler. REQUIRED.
29 - * * $spec['keyFields']: list of fields that can be used as the key
30 - * for fetching a record. REQUIRED.
31 - * * $spec['fieldNames']: names of all fields present in each record.
32 - * Fields not listed here will not be available on the wiki,
33 - * even if they are returned by the data source. REQUIRED.
34 - * * $spec['defaultKey']: default key to select records. If not specified,
35 - * the first entry in $spec['keyFields'] is used.
36 - * * $spec['cacheDuration']: the number of seconds a result from this source
37 - * may be cached for. If not set, results are assumed to be cacheable
38 - * indefinitely. This setting determines the expiry time of the parser
39 - * cache entry for pages that show data from this source. If $spec['cache'],
40 - * i.e. if this DataTransclusionSource is wrapped by an instance of
41 - * CachingDataTransclusionSource, $spec['cacheDuration'] also determines
42 - * the expiry time of ObjectCache entries for records from this source.
43 - * * $spec['sourceInfo']: associative array of information about the data source
44 - * that should be made available on the wiki. This information will be
45 - * present in the record arrays, with they keys prefixed by "source.".
46 - * This is intended to allow information about source, license, etc to be
47 - * shown on the wiki. Note that DataTransclusionSource implementations may
48 - * provide extra information in the source info on their own: This base
49 - * class forces $spec['sourceInfo']['name'] = $spec['name'] and
50 - * $spec['sourceInfo']['defaultKey'] = $spec['defaultKey'].
51 - *
52 - * Options used by DataTransclusionHandler but ignored by DataTransclusionSource:
53 - * * $spec['class']: see documentation if $wgDataTransclusionSources in DataTransclusion.
54 - * * $spec['cache']: see documentation if $wgDataTransclusionSources in DataTransclusion.
55 - *
56 - * Lists may be given as arrays or strings with items separated by [,;|].
57 - */
 19+* Baseclass representing a source of data transclusion. All logic for addressing, fetching, decoding and filtering
 20+* data is encapsulated by a subclass of DataTransclusionSource. Instances of DataTransclusionSource are instantiated
 21+* by DataTransclusionHandler, and initialized by passing an associative array of options to the constructor. This array
 22+* is taken from the $wgDataTransclusionSources configuration variable.
 23+*
 24+* Below is a list of options for the $spec array, as handled by the DataTransclusionSource
 25+* base class (sublcasses may handle additional options):
 26+*
 27+* * $spec['name']: the source's name, used to specify it in wiki text.
 28+* Set automatically by DataTransclusionHandler. REQUIRED.
 29+* * $spec['keyFields']: list of fields that can be used as the key
 30+* for fetching a record. REQUIRED.
 31+* * $spec['fieldNames']: names of all fields present in each record.
 32+* Fields not listed here will not be available on the wiki,
 33+* even if they are returned by the data source. REQUIRED.
 34+* * $spec['defaultKey']: default key to select records. If not specified,
 35+* the first entry in $spec['keyFields'] is used.
 36+* * $spec['cacheDuration']: the number of seconds a result from this source
 37+* may be cached for. If not set, results are assumed to be cacheable
 38+* indefinitely. This setting determines the expiry time of the parser
 39+* cache entry for pages that show data from this source. If $spec['cache'],
 40+* i.e. if this DataTransclusionSource is wrapped by an instance of
 41+* CachingDataTransclusionSource, $spec['cacheDuration'] also determines
 42+* the expiry time of ObjectCache entries for records from this source.
 43+* * $spec['sourceInfo']: associative array of information about the data source
 44+* that should be made available on the wiki. This information will be
 45+* present in the record arrays, with they keys prefixed by "source.".
 46+* This is intended to allow information about source, license, etc to be
 47+* shown on the wiki. Note that DataTransclusionSource implementations may
 48+* provide extra information in the source info on their own: This base
 49+* class forces $spec['sourceInfo']['name'] = $spec['name'] and
 50+* $spec['sourceInfo']['defaultKey'] = $spec['defaultKey'].
 51+*
 52+* Options used by DataTransclusionHandler but ignored by DataTransclusionSource:
 53+* * $spec['class']: see documentation if $wgDataTransclusionSources in DataTransclusion.
 54+* * $spec['cache']: see documentation if $wgDataTransclusionSources in DataTransclusion.
 55+*
 56+* Lists may be given as arrays or strings with items separated by [,;|].
 57+*/
5858 class DataTransclusionSource {
59 - static function splitList( $s ) {
60 - if ( $s === null || $s === false ) {
61 - return $s;
62 - }
 59+ static function splitList( $s ) {
 60+ if ( $s === null || $s === false ) return $s;
 61+ if ( !is_string( $s ) ) return $s;
 62+
 63+ $list = preg_split( '!\s*[,;|]\s*!', $s );
 64+ return $list;
 65+ }
6366
64 - if ( !is_string( $s ) ) {
65 - return $s;
66 - }
 67+ /**
 68+ * Initializes the DataTransclusionSource from the given parameter array.
 69+ * @param $spec associative array of options. See class-level documentation for details.
 70+ */
 71+ function __construct( $spec ) {
 72+ $this->name = $spec[ 'name' ];
6773
68 - $list = preg_split( '!\s*[,;|]\s*!', $s );
 74+ $this->keyFields = self::splitList( $spec[ 'keyFields' ] );
 75+ $this->fieldNames = self::splitList( $spec[ 'fieldNames' ] );
6976
70 - return $list;
71 - }
 77+ if ( !empty( $spec[ 'defaultKey' ] ) ) $this->defaultKey = $spec[ 'defaultKey' ];
 78+ else $this->defaultKey = $this->keyFields[ 0 ];
7279
73 - /**
74 - * Initializes the DataTransclusionSource from the given parameter array.
75 - * @param $spec associative array of options. See class-level documentation for details.
76 - */
77 - function __construct( $spec ) {
78 - $this->name = $spec[ 'name' ];
 80+ if ( !empty( $spec[ 'cacheDuration' ] ) ) $this->cacheDuration = (int)$spec[ 'cacheDuration' ];
 81+ else $this->cacheDuration = null;
7982
80 - $this->keyFields = self::splitList( $spec[ 'keyFields' ] );
81 - $this->fieldNames = self::splitList( $spec[ 'fieldNames' ] );
 83+ $this->sourceInfo = array();
8284
83 - if ( !empty( $spec[ 'defaultKey' ] ) ) {
84 - $this->defaultKey = $spec[ 'defaultKey' ];
85 - } else {
86 - $this->defaultKey = $this->keyFields[ 0 ];
87 - }
88 -
89 - if ( !empty( $spec[ 'cacheDuration' ] ) ) {
90 - $this->cacheDuration = (int)$spec[ 'cacheDuration' ];
91 - } else {
92 - $this->cacheDuration = null;
93 - }
94 -
95 - $this->sourceInfo = array();
96 -
97 - if ( !empty( $spec[ 'sourceInfo' ] ) ) {
98 - foreach ( $spec[ 'sourceInfo' ] as $k => $v ) {
99 - $this->sourceInfo[ $k ] = $v;
100 - }
101 - }
102 -
103 - $this->sourceInfo[ 'name' ] = $this->name; // force this one
104 - $this->sourceInfo[ 'defaultKey' ] = $this->name; // force this one
 85+ if ( !empty( $spec[ 'sourceInfo' ] ) ) {
 86+ foreach ( $spec[ 'sourceInfo' ] as $k => $v ) {
 87+ $this->sourceInfo[ $k ] = $v;
10588 }
 89+ }
10690
107 - public function getName() {
108 - return $this->name;
109 - }
 91+ $this->sourceInfo[ 'name' ] = $this->name; //force this one
 92+ $this->sourceInfo[ 'defaultKey' ] = $this->name; //force this one
 93+ }
11094
111 - public function getDefaultKey() {
112 - return $this->defaultKey;
113 - }
 95+ public function getName() {
 96+ return $this->name;
 97+ }
11498
115 - public function getSourceInfo() {
116 - return $this->sourceInfo;
117 - }
 99+ public function getDefaultKey() {
 100+ return $this->defaultKey;
 101+ }
118102
119 - public function getKeyFields() {
120 - return $this->keyFields;
121 - }
 103+ public function getSourceInfo() {
 104+ return $this->sourceInfo;
 105+ }
122106
123 - public function getFieldNames() {
124 - return $this->fieldNames;
125 - }
 107+ public function getKeyFields() {
 108+ return $this->keyFields;
 109+ }
126110
127 - public function getCacheDuration() {
128 - return $this->cacheDuration;
129 - }
 111+ public function getFieldNames() {
 112+ return $this->fieldNames;
 113+ }
130114
131 - public function fetchRecord( $key, $value ) {
132 - throw new MWException( "override fetchRecord()" );
133 - }
 115+ public function getCacheDuration() {
 116+ return $this->cacheDuration;
 117+ }
 118+
 119+ public function fetchRecord( $key, $value ) {
 120+ throw new MWException( "override fetchRecord()" );
 121+ }
134122 }
135123
136124 /**
137 - * Implementation of DataTransclusionSource that wraps another DataTransclusionSource and applies caching in an
138 - * ObjectCache. All methods delegate to the underlieing data source, fetchRecord adds logic for caching.
139 - */
 125+* Implementation of DataTransclusionSource that wraps another DataTransclusionSource and applies caching in an
 126+* ObjectCache. All methods delegate to the underlieing data source, fetchRecord adds logic for caching.
 127+*/
140128 class CachingDataTransclusionSource extends DataTransclusionSource {
141 - /**
142 - * Initializes the CachingDataTransclusionSource
143 - *
144 - * @param $source a DataTransclusionSource instance for fetching data records.
145 - * @param $cache an ObjectCache instance
146 - * @param $duration number of seconds for which records may be cached
147 - */
148 - function __construct( $source, $cache, $duration ) {
149 - $this->source = $source;
150 - $this->cache = $cache;
151 - $this->duration = $duration;
152 - }
153129
154 - public function getName() {
155 - return $this->source->getName();
156 - }
 130+ /**
 131+ * Initializes the CachingDataTransclusionSource
 132+ *
 133+ * @param $source a DataTransclusionSource instance for fetching data records.
 134+ * @param $cache an ObjectCache instance
 135+ * @param $duration number of seconds for which records may be cached
 136+ */
 137+ function __construct( $source, $cache, $duration ) {
 138+ $this->source = $source;
 139+ $this->cache = $cache;
 140+ $this->duration = $duration;
 141+ }
157142
158 - public function getDefaultTemplate() {
159 - return $this->source->getDefaultTemplate();
160 - }
 143+ public function getName() {
 144+ return $this->source->getName();
 145+ }
161146
162 - public function getSourceInfo() {
163 - return $this->source->getSourceInfo();
164 - }
 147+ public function getDefaultTemplate() {
 148+ return $this->source->getDefaultTemplate();
 149+ }
165150
166 - public function getKeyFields() {
167 - return $this->source->getKeyFields();
168 - }
 151+ public function getSourceInfo() {
 152+ return $this->source->getSourceInfo();
 153+ }
169154
170 - public function getFieldNames() {
171 - return $this->source->getFieldNames();
172 - }
 155+ public function getKeyFields() {
 156+ return $this->source->getKeyFields();
 157+ }
173158
174 - public function getCacheDuration() {
175 - return $this->source->getCacheDuration();
176 - }
 159+ public function getFieldNames() {
 160+ return $this->source->getFieldNames();
 161+ }
177162
178 - public function fetchRecord( $key, $value ) {
179 - global $wgDBname, $wgUser;
 163+ public function getCacheDuration() {
 164+ return $this->source->getCacheDuration();
 165+ }
180166
181 - $cacheKey = "$wgDBname:DataTransclusion(" . $this->getName() . ":$key=$value)";
 167+ public function fetchRecord( $key, $value ) {
 168+ global $wgDBname, $wgUser;
182169
183 - $rec = $this->cache->get( $cacheKey );
 170+ $cacheKey = "$wgDBname:DataTransclusion(" . $this->getName() . ":$key=$value)";
 171+
 172+ $rec = $this->cache->get( $cacheKey );
184173
185 - if ( !$rec ) {
186 - $rec = $this->source->fetchRecord( $key, $value );
187 - if ( $rec ) {
188 - $this->cache->set( $cacheKey, $rec, $this->getCacheDuration() ) ; // XXX: also cache negatives??
189 - }
190 - }
 174+ if ( !$rec ) {
 175+ $rec = $this->source->fetchRecord( $key, $value );
 176+ if ( $rec ) $this->cache->set( $cacheKey, $rec, $this->getCacheDuration() ) ; //XXX: also cache negatives??
 177+ }
191178
192 - return $rec;
193 - }
 179+ return $rec;
 180+ }
194181 }
195182
196183 /**
197 - * Implementations of DataTransclusionSource which simply fetches data from an array. This is
198 - * intended mainly for testing and debugging.
199 - */
 184+* Implementations of DataTransclusionSource which simply fetches data from an array. This is
 185+* intended mainly for testing and debugging.
 186+*/
200187 class FakeDataTransclusionSource extends DataTransclusionSource {
201 - /**
202 - * Initializes the CachingDataTransclusionSource
203 - *
204 - * @param $spec an associative array of options. See class-level
205 - * documentation of DataTransclusionSource for details.
206 - *
207 - * @param $data an array containing a list of records. Records from
208 - * this list can be accessed via fetchRecord() using the key fields specified
209 - * by $spec['keyFields']. If $data is not given, $spec['data'] must contain the data array.
210 - */
211 - function __construct( $spec, $data = null ) {
212 - DataTransclusionSource::__construct( $spec );
213188
214 - if ( $data === null ) {
215 - $data = $spec[ 'data' ];
216 - }
 189+ /**
 190+ * Initializes the CachingDataTransclusionSource
 191+ *
 192+ * @param $spec an associative array of options. See class-level
 193+ * documentation of DataTransclusionSource for details.
 194+ *
 195+ * @param $data an array containing a list of records. Records from
 196+ * this list can be accessed via fetchRecord() using the key fields specified
 197+ * by $spec['keyFields']. If $data is not given, $spec['data'] must contain the data array.
 198+ */
 199+ function __construct( $spec, $data = null ) {
 200+ DataTransclusionSource::__construct( $spec );
217201
218 - $this->lookup = array();
 202+ if ( $data === null ) $data = $spec[ 'data' ];
219203
220 - foreach ( $data as $rec ) {
221 - $this->putRecord( $rec );
222 - }
223 - }
 204+ $this->lookup = array();
224205
225 - public function putRecord( $record ) {
226 - $fields = $this->getKeyFields();
227 - foreach ( $fields as $f ) {
228 - $k = $record[ $f ];
229 -
230 - if ( !isset( $this->lookup[ $f ] ) ) {
231 - $this->lookup[ $f ] = array();
232 - }
233 -
234 - $this->lookup[ $f ][ $k ] = $record;
235 - }
 206+ foreach ( $data as $rec ) {
 207+ $this->putRecord( $rec );
236208 }
 209+ }
237210
238 - public function fetchRecord( $key, $value ) {
239 - return @$this->lookup[ $key ][ $value ];
 211+ public function putRecord( $record ) {
 212+ $fields = $this->getKeyFields();
 213+ foreach ( $fields as $f ) {
 214+ $k = $record[ $f ];
 215+
 216+ if ( !isset( $this->lookup[ $f ] ) ) $this->lookup[ $f ] = array();
 217+ $this->lookup[ $f ][ $k ] = $record;
240218 }
 219+ }
 220+
 221+ public function fetchRecord( $key, $value ) {
 222+ return @$this->lookup[ $key ][ $value ];
 223+ }
241224 }
Index: trunk/extensions/DataTransclusion/DBDataTransclusionSource.php
@@ -9,110 +9,88 @@
1010 * @licence GNU General Public Licence 2.0 or later
1111 */
1212
13 -if ( !defined( 'MEDIAWIKI' ) ) {
 13+if( !defined( 'MEDIAWIKI' ) ) {
1414 echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
1515 die( 1 );
1616 }
1717
1818 /**
19 -  Implementations of DataTransclusionSource, fetching data records from an SQL database.
20 - *
21 - * In addition to the options supported by the DataTransclusionSource base class,
22 - * DBDataTransclusionSource accepts some additional options
23 - *
24 - * * $spec['query']: the SQL query for fetching records. May not contain a
25 - * GROUP or LIMIT clause (use $spec['querySuffix'] for that). The
26 - * WHERE clause is automatically generated from the requested key/value pair.
27 - * If $spec['query'] already contains a WHERE clause, the condition for
28 - * the desired key/value pair is appended using AND. Note that subqueries are
29 - * not supported reliably. REQUIRED.
30 - * * $spec['querySuffix']: additional clauses to be added after the WHERE clause.
31 - * Useful mostly to specify GROUP BY (or ORDER BY or LIMIT).
32 - * * $spec['keyTypes']: associative arrays specifying the data types for the key fields.
33 - * Array keys are the field names, the associated values specify the type
34 - * as 'int' for integers, 'float' or 'decimal' for decimals, or 'string'
35 - * for string fields.
36 - * * $spec['keyFields']: like for DataTransclusionSource, this is list of fields
37 - * that can be used as the key for fetching a record. However, it's not required
38 - * for DBDataTransclusionSource: if not provided, array_keys( $spec['keyTypes'] )
39 - * will be used. REQUIRED.
40 - *
41 - * For more information on options supported by DataTransclusionSource, see the class-level
42 - * documentation there.
43 - */
 19+* Implementations of DataTransclusionSource, fetching data records from an SQL database.
 20+*
 21+* In addition to the options supported by the DataTransclusionSource base class,
 22+* DBDataTransclusionSource accepts some additional options
 23+*
 24+* * $spec['query']: the SQL query for fetching records. May not contain a
 25+* GROUP or LIMIT clause (use $spec['querySuffix'] for that). The
 26+* WHERE clause is automatically generated from the requested key/value pair.
 27+* If $spec['query'] already contains a WHERE clause, the condition for
 28+* the desired key/value pair is appended using AND. Note that subqueries are
 29+* not supported reliably. REQUIRED.
 30+* * $spec['querySuffix']: additional clauses to be added after the WHERE clause.
 31+* Useful mostly to specify GROUP BY (or ORDER BY or LIMIT).
 32+* * $spec['keyTypes']: associative arrays specifying the data types for the key fields.
 33+* Array keys are the field names, the associated values specify the type
 34+* as 'int' for integers, 'float' or 'decimal' for decimals, or 'string'
 35+* for string fields.
 36+* * $spec['keyFields']: like for DataTransclusionSource, this is list of fields
 37+* that can be used as the key for fetching a record. However, it's not required
 38+* for DBDataTransclusionSource: if not provided, array_keys( $spec['keyTypes'] )
 39+* will be used. REQUIRED.
 40+*
 41+* For more information on options supported by DataTransclusionSource, see the class-level
 42+* documentation there.
 43+*/
4444 class DBDataTransclusionSource extends DataTransclusionSource {
45 - /**
46 - * Initializes the DBDataTransclusionSource from the given parameter array.
47 - * @param $spec associative array of options. See class-level documentation for details.
48 - */
49 - function __construct( $spec ) {
50 - if ( !isset( $spec[ 'keyFields' ] ) && isset( $spec[ 'keyTypes' ] ) ) {
51 - $spec[ 'keyFields' ] = array_keys( $spec[ 'keyTypes' ] );
52 - }
5345
54 - DataTransclusionSource::__construct( $spec );
 46+ /**
 47+ * Initializes the DBDataTransclusionSource from the given parameter array.
 48+ * @param $spec associative array of options. See class-level documentation for details.
 49+ */
 50+ function __construct( $spec ) {
 51+ if ( !isset( $spec[ 'keyFields' ] ) && isset( $spec[ 'keyTypes' ] ) ) $spec[ 'keyFields' ] = array_keys( $spec[ 'keyTypes' ] );
5552
56 - $this->query = $spec[ 'query' ];
57 - $this->querySuffix = @$spec[ 'querySuffix' ];
 53+ DataTransclusionSource::__construct( $spec );
5854
59 - if ( isset( $spec[ 'keyTypes' ] ) ) {
60 - $this->keyTypes = $spec[ 'keyTypes' ];
61 - } else {
62 - $this->keyTypes = null;
63 - }
64 - }
 55+ $this->query = $spec[ 'query' ];
 56+ $this->querySuffix = @$spec[ 'querySuffix' ];
6557
66 - public function convertKey( $key, $value ) {
67 - if ( !isset( $this->keyTypes[ $key ] ) ) {
68 - return (string)$value;
69 - }
 58+ if ( isset( $spec[ 'keyTypes' ] ) ) $this->keyTypes = $spec[ 'keyTypes' ];
 59+ else $this->keyTypes = null;
 60+ }
7061
71 - $t = strtolower( trim( $this->keyTypes[ $key ] ) );
 62+ public function convertKey( $key, $value ) {
 63+ if ( !isset( $this->keyTypes[ $key ] ) ) return (string)$value;
7264
73 - if ( $t == 'int' ) {
74 - return (int)$value;
75 - } else if ( $t == 'decimal' || $t == 'float' ) {
76 - return (float)$value;
77 - } else {
78 - return (string)$value;
79 - }
80 - }
 65+ $t = strtolower( trim( $this->keyTypes[ $key ] ) );
 66+
 67+ if ( $t == 'int' ) return (int)$value;
 68+ else if ( $t == 'decimal' || $t == 'float' ) return (float)$value;
 69+ else return (string)$value;
 70+ }
8171
82 - public function fetchRecord( $field, $value ) {
83 - $db = wfGetDB( DB_SLAVE );
 72+ public function fetchRecord( $field, $value ) {
 73+ $db = wfGetDB( DB_SLAVE );
8474
85 - if ( !preg_match( '/\w+[\w\d]+/', $field ) ) {
86 - return false; // redundant, but make extra sure we don't get anythign evil here //TESTME
87 - }
 75+ if ( !preg_match( '/\w+[\w\d]+/', $field ) ) return false; // redundant, but make extra sure we don't get anythign evil here //TESTME
8876
89 - $value = $this->convertKey( $field, $value ); // TESTME
 77+ $value = $this->convertKey( $field, $value ); //TESTME
9078
91 - if ( is_string( $value ) ) {
92 - $v = $db->addQuotes( $value ); // TESTME
93 - } else {
94 - $v = $value;
95 - }
 79+ if ( is_string( $value ) ) $v = $db->addQuotes( $value ); //TESTME
 80+ else $v = $value;
9681
97 - $where = "( " . $field . " = " . $v . " )";
 82+ $where = "( " . $field . " = " . $v . " )";
9883
99 - if ( preg_match( '/[)\s]WHERE[\s(]/is', $this->query ) ) {
100 - $sql = $this->query . " AND " . $where;
101 - } else {
102 - $sql = $this->query . " WHERE " . $where;
103 - }
 84+ if ( preg_match('/[)\s]WHERE[\s(]/is', $this->query ) ) $sql = $this->query . " AND " . $where;
 85+ else $sql = $this->query . " WHERE " . $where;
10486
105 - if ( $this->querySuffix ) {
106 - $sql = $sql . ' ' . $this->querySuffix;
107 - }
 87+ if ( $this->querySuffix ) $sql = $sql . ' ' . $this->querySuffix;
10888
109 - $rs = $db->query( $sql, "DBDataTransclusionSource(" . $this->getName() . ")::fetchRecord" );
110 - if ( !$rs ) {
111 - return false;
112 - }
 89+ $rs = $db->query( $sql, "DBDataTransclusionSource(" . $this->getName() . ")::fetchRecord" );
 90+ if ( !$rs ) return false;
11391
114 - $rec = $db->fetchRow( $rs );
 92+ $rec = $db->fetchRow( $rs );
11593
116 - $db->freeResult( $rs );
117 - return $rec;
118 - }
 94+ $db->freeResult( $rs );
 95+ return $rec;
 96+ }
11997 }

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r67480several test cases, more to comecddaniel20:25, 6 June 2010

Status & tagging log