r67990 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r67989‎ | r67990 | r67991 >
Date:11:49, 14 June 2010
Author:daniel
Status:deferred
Tags:
Comment:
reworked parameter passing mechanisms. more flexible and intuitive now. i18n NOTE: two messages fuzzed, one replaced, one removed
Modified paths:
  • /trunk/extensions/DataTransclusion/DBDataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/DataTransclusion.i18n.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.php
@@ -21,16 +21,18 @@
2222 'datatransclusion-test-nowiki' => 'some <nowiki>{{nowiki}}</nowiki> code.', // Do not translate.
2323
2424 'datatransclusion-missing-source' => 'No data source specified.
25 -First argument is required.',
 25+Second or "source" argument is required.', #FUZZ!
2626 'datatransclusion-unknown-source' => 'Bad data source specified.
2727 "$1" is not known.',
 28+ 'datatransclusion-missing-key' => 'No key specified.
 29+$2 are valid keys in data source $1.',
2830 'datatransclusion-bad-argument-by' => 'Bad key field specified.
2931 "$2" is not a key field in data source "$1".
3032 {{PLURAL:$4|Valid key|Valid keys are}}: $3.',
3133 'datatransclusion-missing-argument-key' => 'No key value specified.
3234 Second or "key" argument is required.',
3335 'datatransclusion-missing-argument-template' => 'No template specified.
34 -Third or "template" argument is required.',
 36+First or "template" argument is required.', #FUZZ!
3537 'datatransclusion-record-not-found' => 'No record matching $2 = $3 was found in data source $1.',
3638 'datatransclusion-bad-template-name' => 'Bad template name: $1.',
3739 'datatransclusion-unknown-template' => '<nowiki>{{</nowiki>[[{{ns:template}}:$1|$1]]<nowiki>}}</nowiki> does not exist.',
@@ -41,16 +43,14 @@
4244 */
4345 $messages['qqq'] = array(
4446 'datatransclusion-desc' => '{{desc}}',
45 - 'datatransclusion-missing-source' => 'Issued if no data source was specified.',
 47+ 'datatransclusion-missing-source' => 'Issued if no data "source" or second positional argument was specified.',
4648 'datatransclusion-unknown-source' => 'Issued if an unknown data source was specified. Parameters:
4749 * $1 is the name of the data source.',
48 - 'datatransclusion-bad-argument-by' => 'Issued if a bad value was specified for the "by" argument, that is, an unknown key field was selected. Parameters:
 50+ 'datatransclusion-missing-key' => 'Issued if no argument matches an entry in the list of key field. Parameters:
4951 * $1 is the name of the data source
50 -* $2 is the value of the by argument
51 -* $3 is a list of all valid keys for this data source
52 -* $4 is the number of valid keys for this data source.',
53 - 'datatransclusion-missing-argument-key' => 'Issued if no "key" or second positional argument was given provided. A key value is always required.',
54 - 'datatransclusion-missing-argument-template' => 'Issued if no "template" or third positional argument was given provided. A target template is always required.',
 52+* $2 is a list of all valid keys for this data source
 53+* $3 is the number of valid keys for this data source.',
 54+ 'datatransclusion-missing-argument-template' => 'Issued if no "template" or first positional argument was given provided. A target template is always required.',
5555 'datatransclusion-record-not-found' => 'issued if the record specified using the "by" and "key" arguments was nout found in the data source. Parameters:
5656 * $1 is the name of the data source
5757 * $2 is the key filed used
@@ -71,10 +71,6 @@
7272 Першы парамэтар — абавязковы.',
7373 'datatransclusion-unknown-source' => 'Няслушная крыніца зьвестак.
7474 $1 — невядомая.',
75 - 'datatransclusion-bad-argument-by' => 'Пазначана няслушнае ключавое поле.
76 -$2 не зьяўляецца ключавым полем ў крыніцы зьвестак $1, слушныя ключы: $3.',
77 - 'datatransclusion-missing-argument-key' => 'Ключавое значэньне не пазначана.
78 -Неабходны другі ці «ключавы» аргумэнт.',
7975 'datatransclusion-missing-argument-template' => 'Шаблён не пазначаны.
8076 Неабходны трэці ці «шаблённы» аргумэнт.',
8177 'datatransclusion-record-not-found' => 'Ня знойдзеныя супадаючыя запісы $2 = $3 ў крыніцы зьвестак $1.',
@@ -99,10 +95,6 @@
10096 Das erste Argument ist erforderlich.',
10197 'datatransclusion-unknown-source' => 'Es wurde eine mangelhafte Datenquelle angegeben.
10298 $1 ist nicht bekannt.',
103 - 'datatransclusion-bad-argument-by' => 'Es wurde ein mangelhaftes Schlüsselfeld angegeben.
104 -$2 ist kein Schlüsselfeld in der Datenquelle $1. Gültige Schlüssel sind: $3.',
105 - 'datatransclusion-missing-argument-key' => 'Es wurde kein Schlüssel-Wert angegeben.
106 -Ein zweites oder ein Schlüssel-Argument ist erforderlich.',
10799 'datatransclusion-missing-argument-template' => 'Es wurde keine Vorlage angegeben.
108100 Ein drittes oder ein Vorlagen-Argument ist erforderlich.',
109101 'datatransclusion-record-not-found' => 'Es wurde kein passender Datensatz $2 = $3 in der Datenquelle $1 gefunden.',
@@ -119,9 +111,6 @@
120112 Prědny argument jo trěbny.',
121113 'datatransclusion-unknown-source' => 'Wopacne datowe žrědło pódane.
122114 $1 jo njeznaty.',
123 - 'datatransclusion-bad-argument-by' => '$2 njejo klucowe pólo w datowem žrědle $1, płaśiwe kluce su: $3.',
124 - 'datatransclusion-missing-argument-key' => 'Žedna datowa gódnota pódana.
125 -Drugi abo "klucowy" argument je trěbny.',
126115 'datatransclusion-missing-argument-template' => 'Žedna pśedłoga pódana.
127116 Tśeśi abo "pśedłogowy" argument jo trěbny.',
128117 'datatransclusion-record-not-found' => 'W datowem žrědle $1 njejo se žedna sajźba namakała, kótaraž $2=$3 wótpowědujo.',
@@ -138,11 +127,6 @@
139128 Primer argumento es obligatorio.',
140129 'datatransclusion-unknown-source' => 'Fuente de datos mal especificado.
141130 $1 es desconocido.',
142 - 'datatransclusion-bad-argument-by' => 'Campo clave mal especificado.
143 -"$2" no es un campo clave en la fuente de datos "$1".
144 -{{PLURAL:$4|Clave válida|Claves válidas son}}: $3.',
145 - 'datatransclusion-missing-argument-key' => 'Ningún valor clave especificado.
146 -Argumento segundo o "clave" es obligatorio.',
147131 'datatransclusion-missing-argument-template' => 'Ninguna plantilla especificada.
148132 Argumento tercero o "plantilla" es obligatorio.',
149133 'datatransclusion-record-not-found' => 'Ningún registro coincidente $2 = $3 fue encontrado en la fuente de datos $1.',
@@ -159,10 +143,6 @@
160144 Le premier argument est obligatoire.',
161145 'datatransclusion-unknown-source' => 'Mauvaise source de données spécifiée.
162146 $1 est inconnu.',
163 - 'datatransclusion-bad-argument-by' => 'Mauvaise clé de champ spécifiée.
164 -$2 n’est pas une clé de champ dans la source de données $1 ; les clés valides sont : $3.',
165 - 'datatransclusion-missing-argument-key' => 'Aucune valeur de clé spécifiée.
166 -Le deuxième argument ou « clé » est obligatoire.',
167147 'datatransclusion-missing-argument-template' => 'Aucun modèle spécifié.
168148 Le troisième argument ou « modèle » est obligatoire.',
169149 'datatransclusion-record-not-found' => 'Aucun enregistrement vérifiant $2 = $3 n’a été trouvé dans la source de données $1.',
@@ -199,10 +179,6 @@
200180 Prěni argument je trěbny.',
201181 'datatransclusion-unknown-source' => 'Wopačne datowe žórło podate.
202182 $1 je njeznaty.',
203 - 'datatransclusion-bad-argument-by' => 'Wopačne klučowe polo podate.
204 -$2 njeje klučowe polo w datowym žórle $1, płaćiwe kluče su: $3',
205 - 'datatransclusion-missing-argument-key' => 'Žana klučowa hódnota podata.
206 -Druhi abo "klučowy" argument je trěbny.',
207183 'datatransclusion-missing-argument-template' => 'Žana předłoha podata.
208184 Třeći abo "předłohowy" argument je trěbny.',
209185 'datatransclusion-record-not-found' => 'W datowym žórle $1 njeje so žana datowa sadźba namakała, kotraž $2=$3 wotpowěduje.',
@@ -219,10 +195,6 @@
220196 Le prime parametro es obligatori.',
221197 'datatransclusion-unknown-source' => 'Un fonte de datos invalide ha essite specificate.
222198 $1 non es cognoscite.',
223 - 'datatransclusion-bad-argument-by' => 'Un campo de clave invalide ha essite specificate.
224 -$2 non es un campo de clave in le fonte de datos $1. Le claves valide es: $3.',
225 - 'datatransclusion-missing-argument-key' => 'Nulle valor de clave specificate.
226 -Un secunde parametro "key" es obligatori.',
227199 'datatransclusion-missing-argument-template' => 'Nulle patrono specificate.
228200 Un tertie parametro "template" es obligatori.',
229201 'datatransclusion-record-not-found' => 'Nulle dato correspondente a $2 = $3 ha essite trovate in le fonte de datos $1.',
@@ -245,8 +217,6 @@
246218 'datatransclusion-desc' => 'Увоз и обликување на податотечни записи од надворешни податотечни извори',
247219 'datatransclusion-missing-source' => 'не е укажан податотечен извор (се бара првиот аргумент)',
248220 'datatransclusion-unknown-source' => 'укажан е лош податотечен извор ($1 е непознат)',
249 - 'datatransclusion-bad-argument-by' => 'укажано е лошо поле за клуч ($2 не претставува поле за клуч во податочниот извор $1. Важечки клучеви се: $3)',
250 - 'datatransclusion-missing-argument-key' => 'нема укажано вредност за клучот (се бара вториот аргумент или „клуч“)',
251221 'datatransclusion-missing-argument-template' => 'нема укажано шаблон (се бара третиот аргумент или „шаблон“)',
252222 'datatransclusion-record-not-found' => 'во податочниот извор $1 нема пронајдено запис што одговара на $2 = $3',
253223 'datatransclusion-bad-template-name' => 'лошо име на шаблон: $1',
@@ -262,11 +232,6 @@
263233 Het eerste argument is verplicht.',
264234 'datatransclusion-unknown-source' => 'Er is een ongeldige gegevensbron aangegeven.
265235 $1 is niet bekend.',
266 - 'datatransclusion-bad-argument-by' => 'Ongeldig sleutelveld aangegeven.
267 -$2 is geen sleutelveld in gegevensbron $1.
268 -Geldige {{PLUARAL:$4|sleutel is|sleutels zijn}}: $3.',
269 - 'datatransclusion-missing-argument-key' => 'Er is geen sleutelwaarde aangegeven.
270 -Een tweede argument of "sleutel" is verplicht.',
271236 'datatransclusion-missing-argument-template' => 'Geen sjabloon aangegeven.
272237 Een derde argument of "template" is verplicht.',
273238 'datatransclusion-record-not-found' => 'Er is geen overeenkomstig gegeven $2 = $3 gevonden in de gegevensbron $1.',
@@ -283,10 +248,6 @@
284249 O primeiro argumento é obrigatório.',
285250 'datatransclusion-unknown-source' => 'A fonte de dados especificada é incorrecta.
286251 $1 não é conhecido.',
287 - 'datatransclusion-bad-argument-by' => 'Foi especificado um campo chave incorrecto.
288 -$2 não é um campo chave na fonte de dados $1; as chaves válidas são: $3.',
289 - 'datatransclusion-missing-argument-key' => 'Não foi especificado um campo chave.
290 -O segundo argumento, ou argumento "chave", é obrigatório.',
291252 'datatransclusion-missing-argument-template' => 'Não foi especificada uma predefinição.
292253 O terceiro argumento, ou argumento "predefinição", é obrigatório.',
293254 'datatransclusion-record-not-found' => 'Não foi encontrado nenhum registo $2 = $3 na fonte de dados $1.',
@@ -303,10 +264,6 @@
304265 Первый аргумент является обязательным.',
305266 'datatransclusion-unknown-source' => 'Указан неправильный источник данных.
306267 $1 — неизвестен.',
307 - 'datatransclusion-bad-argument-by' => 'Указано неправильное ключевое поле.
308 -$2 не является ключевым полем в источнике данных $1. Действительными ключами являются: $3.',
309 - 'datatransclusion-missing-argument-key' => 'Не указано значение ключа.
310 -Второй или «ключевой» аргумент является обязательным.',
311268 'datatransclusion-missing-argument-template' => 'Не указан шаблон.
312269 Третий или «шаблонный» аргумент является обязательным.',
313270 'datatransclusion-record-not-found' => 'В источнике данных $1 не найдено записи, соответствующей $2 = $3',
@@ -323,10 +280,6 @@
324281 Kailangan ang unang argumento.',
325282 'datatransclusion-unknown-source' => 'Natukoy ang masamang pinagmulan ng dato.
326283 Hindi alam ang $1.',
327 - 'datatransclusion-bad-argument-by' => 'Natukoy ang isang larangan ng masamang susi.
328 -Ang $2 ay hindi isang susing larangan sa loob ng pinagmulan ng dato na $1, ang tanggap na mga susi ay: $3.',
329 - 'datatransclusion-missing-argument-key' => 'Walang tinukoy na halaga ng susi.
330 -Kailangan ang pangalawa o "susi" na argumento.',
331284 'datatransclusion-missing-argument-template' => 'Walang tinukoy na suleras.
332285 Kailangan ang pangatlo o argumentong "suleras".',
333286 'datatransclusion-record-not-found' => 'Walang natagpuang rekord na tumutugma sa $2 = $3 na nasa loob ng pinagmulan ng dato na $1.',
Index: trunk/extensions/DataTransclusion/DataTransclusionHandler.php
@@ -14,6 +14,12 @@
1515 die( 1 );
1616 }
1717
 18+/** DataTransclusionHandler implements handlers for a parser tag and a parser function,
 19+* both called record, for fetching a data record from some external source. They are used
 20+* as follows: <record source="SourceName" key="value">SomeTemplate</record> where
 21+* "key" may be any field name defined of a key field for that data source. Similarly:
 22+* {{#record:SomeTemplate|SourceName|key=value}}.
 23+*/
1824 class DataTransclusionHandler {
1925 static function buildAssociativeArguments ( $params ) {
2026 // build associative arguments from flat parameter list
@@ -48,11 +54,15 @@
4955 return ''; // no category specified, return nothing
5056 }
5157
 58+ //first parameter is the template name
 59+ $template = array_shift( $params );
 60+
5261 // build associative arguments from flat parameter list
5362 $argv = DataTransclusionHandler::buildAssociativeArguments( $params );
 63+ $argv[ 0 ] = $template;
5464
5565 // FIXME: error messages contining special blocks like <nowiki> don't get re-substitutet correctly.
56 - $text = DataTransclusionHandler::handleRecordTransclusion( null, $argv, $parser, false );
 66+ $text = DataTransclusionHandler::handleRecordTransclusion( $template, $argv, $parser, false );
5767 return array( $text, 'noparse' => false, 'isHTML' => false );
5868 }
5969
@@ -76,15 +86,15 @@
7787 /**
7888 * Entry point for the <record> tag parser hook. Delegates to handleRecordTransclusion.
7989 */
80 - static function handleRecordTag( $key, $argv, $parser ) {
81 - return DataTransclusionHandler::handleRecordTransclusion( $key, $argv, $parser, true );
 90+ static function handleRecordTag( $text, $argv, $parser ) {
 91+ return DataTransclusionHandler::handleRecordTransclusion( $text, $argv, $parser, true );
8292 }
8393
8494 /**
8595 * Fetches a records and renders it, according to the given array of parameters.
8696 * Common implementation for parser tag and parser function.
8797 */
88 - static function handleRecordTransclusion( $key, $argv, $parser, $asHTML, $templateText = null ) {
 98+ static function handleRecordTransclusion( $template, $argv, $parser, $asHTML, $templateText = null ) {
8999 // find out which data source to use...
90100 if ( empty( $argv['source'] ) ) {
91101 if ( empty( $argv[1] ) ) {
@@ -99,50 +109,54 @@
100110
101111 $source = DataTransclusionHandler::getDataSource( $sourceName );
102112 if ( empty( $source ) ) {
103 - wfDebugLog( 'DataTransclusion', "unknown data-source: $sourceName\n" );
 113+ wfDebugLog( 'DataTransclusion', "unknown source: $sourceName\n" );
104114 return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-source', $asHTML, $sourceName );
105115 }
106116
107 - // find out how to find the desired record
108 - if ( empty( $argv['by'] ) ) {
109 - $by = $source->getDefaultKey();
110 - } else {
111 - $by = $argv['by'];
 117+ // find out how to render the record
 118+ if ( !empty( $argv['template'] ) ) {
 119+ $template = $argv['template'];
 120+ } else if ( $template === null || $template === false ) {
 121+ if ( empty( $argv[0] ) ) {
 122+ wfDebugLog( 'DataTransclusion', "missing 'template' argument\n" );
 123+ return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML );
 124+ } else {
 125+ $template = $argv[0];
 126+ }
 127+ }
 128+
 129+ // find key
 130+ $by = false;
 131+ $key = false;
 132+ $keyFields = $source->getKeyFields();
 133+ foreach ( $keyFields as $k ) {
 134+ if ( isset( $argv[ $k ] ) ) {
 135+ $by = $k;
 136+ $key = $argv[ $k ];
 137+ break; //XXX: could keep running and complain about multiple keys
 138+ }
112139 }
113140
114 - $keyFields = $source->getKeyFields();
115 - if ( ! in_array( $by, $keyFields ) ) {
 141+ if ( !$by ) {
116142 global $wgContLang;
117 - wfDebugLog( 'DataTransclusion', "bad 'by' argument: $by (not a known key field)\n" );
118 - return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-argument-by', $asHTML, $sourceName, $by,
 143+ wfDebugLog( 'DataTransclusion', "no key specified\n" );
 144+ return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-key', $asHTML, $sourceName,
119145 $wgContLang->commaList( $keyFields ), count( $keyFields ) );
120146 }
121147
122 - if ( !empty( $argv['key'] ) ) {
123 - $key = $argv['key'];
124 - } else if ( $key === null || $key === false ) {
125 - if ( empty( $argv[2] ) ) {
126 - wfDebugLog( 'DataTransclusion', "missing 'key' argument\n" );
127 - return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-key', $asHTML );
128 - } else {
129 - $key = $argv[2];
 148+ // collect options
 149+ $options = array();
 150+ $optionNames = $source->getOptionNames();
 151+ if ( $optionNames ) {
 152+ foreach ( $optionNames as $n ) {
 153+ if ( isset( $argv[ $n ] ) ) {
 154+ $options[ $n ] = $argv[ $n ];
 155+ }
130156 }
131157 }
132158
133 - // find out how to render the record
134 - if ( empty( $argv['template'] ) ) {
135 - if ( empty( $argv[3] ) ) {
136 - wfDebugLog( 'DataTransclusion', "missing 'template' argument\n" );
137 - return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML );
138 - } else {
139 - $template = $argv[3];
140 - }
141 - } else {
142 - $template = $argv['template'];
143 - }
144 -
145159 // load the record
146 - $record = $source->fetchRecord( $by, $key );
 160+ $record = $source->fetchRecord( $by, $key, $options );
147161 if ( empty( $record ) ) {
148162 wfDebugLog( 'DataTransclusion', "no record found matching $by=$key in $sourceName\n" );
149163 return DataTransclusionHandler::errorMessage( 'datatransclusion-record-not-found', $asHTML, $sourceName, $by, $key );
@@ -157,7 +171,7 @@
158172
159173 $handler = new DataTransclusionHandler( $parser, $source, $t, $templateText );
160174
161 - $record = $handler->normalizeRecord( $record );
 175+ $record = $handler->normalizeRecord( $record, $argv );
162176 $text = $handler->render( $record );
163177
164178 if ( $text === false ) {
@@ -233,10 +247,32 @@
234248 return $text;
235249 }
236250
237 - function normalizeRecord( $record ) {
 251+ function normalizeRecord( $record, $args ) {
238252 $rec = array();
239253
240 - // keep record fields, add missing values
 254+ // add source meta info, so we can render links back to the source,
 255+ // provide license info, etc
 256+ $info = $this->source->getSourceInfo();
 257+ foreach ( $info as $f => $v ) {
 258+ if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) {
 259+ continue;
 260+ }
 261+
 262+ $rec[ $f ] = $this->sanitizeValue( $v );
 263+ }
 264+
 265+ if ( $args ) {
 266+ // add arguments
 267+ foreach ( $args as $f => $v ) {
 268+ if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) {
 269+ continue;
 270+ }
 271+
 272+ $rec[ $f ] = $this->sanitizeValue( $v );
 273+ }
 274+ }
 275+
 276+ // copy record fields, add missing values
241277 $fields = $this->source->getFieldNames();
242278 foreach ( $fields as $f ) {
243279 if ( isset( $record[ $f ] ) ) {
@@ -248,17 +284,6 @@
249285 $rec[ $f ] = $this->sanitizeValue( $v );
250286 }
251287
252 - // add source meta info, so we can render links back to the source,
253 - // provide license info, etc
254 - $info = $this->source->getSourceInfo();
255 - foreach ( $info as $f => $v ) {
256 - if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) {
257 - continue;
258 - }
259 -
260 - $rec[ "source.$f" ] = $this->sanitizeValue( $v );
261 - }
262 -
263288 return $rec;
264289 }
265290
@@ -315,7 +340,7 @@
316341 throw new MWException( "failed to instantiate \$wgDataTransclusionSources['$name'] as new $c." );
317342 }
318343
319 - wfDebugLog( 'DataTransclusion', "created instance of $c as data-source \"$name\"\n" );
 344+ wfDebugLog( 'DataTransclusion', "created instance of $c as source \"$name\"\n" );
320345 $source = $obj;
321346
322347 if ( isset( $spec[ 'cache' ] ) ) { // check if a cache should be used
@@ -326,7 +351,7 @@
327352
328353 $source = new CachingDataTransclusionSource( $obj, $c, @$spec['cache-duration'] ); // apply caching wrapper
329354
330 - wfDebugLog( 'DataTransclusion', "wrapped data-source \"$name\" in an instance of CachingDataTransclusionSource\n" );
 355+ wfDebugLog( 'DataTransclusion', "wrapped source \"$name\" in an instance of CachingDataTransclusionSource\n" );
331356 }
332357
333358 $wgDataTransclusionSources[ $name ] = $source; // replace spec array by actual object, for later re-use
Index: trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php
@@ -25,7 +25,7 @@
2626
2727 class DataTransclusionTest extends PHPUnit_Framework_TestCase {
2828 protected static $templates = array(
29 - 'Test' => "'''{{{id}}}'''|{{{name}}}|{{{info}}}|[{{{url}}} link]|[{{{evil}}} click me]",
 29+ 'Test' => "{{{source-name}}}:'''{{{id}}}'''|{{{name}}}|{{{extra}}}|{{{info}}}|[{{{url}}} link]|[{{{evil}}} click me]",
3030 );
3131
3232 static function getTemplate( $title, $parser ) {
@@ -186,35 +186,31 @@
187187 $wgDataTransclusionSources[ 'FOO' ] = $spec;
188188
189189 # failure mode: no source given
190 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'foo' => 'bar' ), $wgParser, false );
 190+ $s = DataTransclusionHandler::handleRecordTransclusion( "Dummy", array( 'foo' => 'bar', 'id' => 3 ), $wgParser, false );
191191 $this->assertTrue( preg_match( '/class="error datatransclusion-missing-source"/', $s ) === 1 );
192192
193193 # failure mode: bad source given
194 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => '*** nonsense ***', 'template' => 'Dummy' ), $wgParser, false );
 194+ $s = DataTransclusionHandler::handleRecordTransclusion( "Dummy", array( 'source' => '*** nonsense ***', 'id' => 3 ), $wgParser, false );
195195 $this->assertTrue( preg_match( '/class="error datatransclusion-unknown-source"/', $s ) === 1 );
196196
197197 # failure mode: bad source given (alternative)
198 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 1 => '*** nonsense ***', 'template' => 'Dummy' ), $wgParser, false );
 198+ $s = DataTransclusionHandler::handleRecordTransclusion( "Dummy", array( 1 => '*** nonsense ***', 'id' => 3 ), $wgParser, false );
199199 $this->assertTrue( preg_match( '/class="error datatransclusion-unknown-source"/', $s ) === 1 );
200200
201 - # failure mode: illegal value for by= (must be a key field)
202 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => 'FOO', 'by' => 'info', 'template' => 'Dummy' ), $wgParser, false );
203 - $this->assertTrue( preg_match( '/class="error datatransclusion-bad-argument-by"/', $s ) === 1 );
204 -
205201 # failure mode: no key value specified
206 - $s = DataTransclusionHandler::handleRecordTransclusion( null, array( 'source' => 'FOO', 'template' => 'Dummy' ), $wgParser, false );
207 - $this->assertTrue( preg_match( '/class="error datatransclusion-missing-argument-key"/', $s ) === 1 );
 202+ $s = DataTransclusionHandler::handleRecordTransclusion( "Dummy", array( 'source' => 'FOO' ), $wgParser, false );
 203+ $this->assertTrue( preg_match( '/class="error datatransclusion-missing-key"/', $s ) === 1 );
208204
209205 # failure mode: no template specified
210 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => 'FOO' ), $wgParser, false );
 206+ $s = DataTransclusionHandler::handleRecordTransclusion( null, array( 'source' => 'FOO', 'id' => 3 ), $wgParser, false );
211207 $this->assertTrue( preg_match( '/class="error datatransclusion-missing-argument-template"/', $s ) === 1 );
212208
213209 # failure mode: illegal template specified
214 - $s = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => 'FOO', 'template' => '#' ), $wgParser, false );
 210+ $s = DataTransclusionHandler::handleRecordTransclusion( "##", array( 'source' => 'FOO', 'id' => 3 ), $wgParser, false );
215211 $this->assertTrue( preg_match( '/class="error datatransclusion-bad-template-name"/', $s ) === 1 );
216212
217213 # failure mode: record can't be found for that key
218 - $s = DataTransclusionHandler::handleRecordTransclusion( "xxxxxxxxxx", array( 'source' => 'FOO', 'template' => 'Dummy' ), $wgParser, false );
 214+ $s = DataTransclusionHandler::handleRecordTransclusion( "Dummy", array( 'source' => 'FOO', 'id' => 'xxxxxxxxxx' ), $wgParser, false );
219215 $this->assertTrue( preg_match( '/class="error datatransclusion-record-not-found"/', $s ) === 1 );
220216
221217 /*
@@ -226,15 +222,15 @@
227223
228224 ////////////////////////////////////////////////////////
229225 # success: render record
230 - $res = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => 'FOO', 'template' => 'Test' ), $wgParser, false, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
 226+ $res = DataTransclusionHandler::handleRecordTransclusion( "Test", array( 'source' => 'FOO', 'id' => 3 ), $wgParser, false, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
231227 $this->assertEquals( $res, '\'\'\'3\'\'\'|foo|test&X' );
232228
233229 # success: render record (find by name)
234 - $res = DataTransclusionHandler::handleRecordTransclusion( "foo", array( 'source' => 'FOO', 'template' => 'Test', 'by' => 'name' ), $wgParser, false, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
 230+ $res = DataTransclusionHandler::handleRecordTransclusion( "Test", array( 'source' => 'FOO', 'name' => 'foo'), $wgParser, false, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
235231 $this->assertEquals( $res, '\'\'\'3\'\'\'|foo|test&X' );
236232
237233 # success: render record (as HTML)
238 - $res = DataTransclusionHandler::handleRecordTransclusion( "3", array( 'source' => 'FOO', 'template' => 'Test' ), $wgParser, true, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
 234+ $res = DataTransclusionHandler::handleRecordTransclusion( "Test", array( 'source' => 'FOO', 'id' => 3 ), $wgParser, true, "'''{{{id}}}'''|{{{name}}}|{{{info}}}" );
239235 $this->assertEquals( $res, '<b>3</b>|foo|test&X' ); // FIXME: & should have been escaped to &amp; here, no? why not?
240236 }
241237
@@ -247,7 +243,7 @@
248244 'data' => $data,
249245 'keyFields' => 'name,id',
250246 'fieldNames' => 'id,name,info,url,evil',
251 - 'defaultKey' => 'id'
 247+ 'defaultKey' => 'id',
252248 );
253249
254250 $wgDataTransclusionSources[ 'FOO' ] = $spec;
@@ -257,12 +253,11 @@
258254 $options = new ParserOptions();
259255 $options->setTemplateCallback( 'DataTransclusionTest::getTemplate' );
260256
261 - $text = 'xx {{#record:FOO|3|Test}} xx';
 257+ $text = 'xx {{#record:Test|FOO|id=3|extra=Hallo}} xx';
262258 $wgParser->parse( $text, $title, $options );
263259
264260 $html = $wgParser->getOutput()->getText();
265 - $this->assertEquals( $html, '<p>xx <b>3</b>|foo|&lt;test&gt;&amp;&#91;&#91;X&#93;&#93;|<a href="http://test.org/" class="external text" rel="nofollow">link</a>|[javascript:alert("evil") click me] xx'."\n".'</p>' ); // XXX: should be more lenient wrt whitespace
266 -
 261+ $this->assertEquals( $html, '<p>xx FOO:<b>3</b>|foo|Hallo|&lt;test&gt;&amp;&#91;&#91;X&#93;&#93;|<a href="http://test.org/" class="external text" rel="nofollow">link</a>|[javascript:alert("evil") click me] xx'."\n".'</p>' ); // XXX: should be more lenient wrt whitespace
267262 $templates = $wgParser->getOutput()->getTemplates();
268263 $this->assertTrue( isset( $templates[ NS_TEMPLATE ]['Test'] ) );
269264 }
@@ -286,11 +281,11 @@
287282 $options = new ParserOptions();
288283 $options->setTemplateCallback( 'DataTransclusionTest::getTemplate' );
289284
290 - $text = 'xx <record source=FOO template="Test">3</record> xx';
 285+ $text = 'xx <record source="FOO" id=3 extra="Hallo">Test</record> xx';
291286 $wgParser->parse( $text, $title, $options );
292287
293288 $html = $wgParser->getOutput()->getText();
294 - $this->assertEquals( $html, '<p>xx <b>3</b>|foo|&lt;test&gt;&amp;&#91;&#91;X&#93;&#93;|<a href="http://test.org/" class="external text" rel="nofollow">link</a>|[javascript:alert("evil") click me] xx'."\n".'</p>' ); // XXX: should be more lenient wrt whitespace
 289+ $this->assertEquals( $html, '<p>xx FOO:<b>3</b>|foo|Hallo|&lt;test&gt;&amp;&#91;&#91;X&#93;&#93;|<a href="http://test.org/" class="external text" rel="nofollow">link</a>|[javascript:alert("evil") click me] xx'."\n".'</p>' ); // XXX: should be more lenient wrt whitespace
295290 $templates = $wgParser->getOutput()->getTemplates();
296291 $this->assertTrue( isset( $templates[ NS_TEMPLATE ]['Test'] ) );
297292 }
@@ -309,11 +304,13 @@
310305
311306 $handler = new DataTransclusionHandler( $wgParser, $source, null );
312307
313 - $rec = $handler->normalizeRecord( $rec );
 308+ $args = array( "name" => "cruft", "more" => "stuff" );
 309+ $rec = $handler->normalizeRecord( $rec, $args );
314310
315 - $this->assertEquals( $rec['source.name'], 'FOO' );
316 - $this->assertEquals( $rec['source.quux'], 'xyzzy' );
317 - $this->assertEquals( $rec['source.x'], 43 );
 311+ $this->assertEquals( $rec['source-name'], 'FOO' );
 312+ $this->assertEquals( $rec['quux'], 'xyzzy' );
 313+ $this->assertEquals( $rec['x'], 43 );
 314+ $this->assertEquals( $rec['more'], 'stuff' );
318315 $this->assertEquals( $rec['name'], 'foo' );
319316 $this->assertEquals( $rec['id'], '3' );
320317 $this->assertEquals( $rec['info'], '&#123;&#123;test&#125;&#125;=&#91;&#91;x&#93;&#93; 1&2 ' );
@@ -402,7 +399,8 @@
403400 $spec = array(
404401 'name' => 'FOO',
405402 'keyFields' => 'id,name',
406 - 'url' => 'http://acme.com/',
 403+ 'optionNames' => 'x,y',
 404+ 'url' => 'http://acme.com/{name}',
407405 'dataFormat' => 'php',
408406 'dataPath' => 'response/content/@0',
409407 'valuePath' => 'value',
@@ -412,8 +410,14 @@
413411 $source = new WebDataTransclusionSource( $spec );
414412
415413 $u = $source->getRecordURL( 'name', 'foo&bar' );
416 - $this->assertEquals( $u, 'http://acme.com/?name=foo%26bar' );
 414+ $this->assertEquals( $u, 'http://acme.com/foo%26bar' );
417415
 416+ $u = $source->getRecordURL( 'id', '23' );
 417+ $this->assertEquals( $u, 'http://acme.com/?id=23' );
 418+
 419+ $u = $source->getRecordURL( 'name', 'foo&bar', array( 'x' => '42', 'y' => 57 ) );
 420+ $this->assertEquals( $u, 'http://acme.com/foo%26bar?x=42&y=57' );
 421+
418422 $rec = array(
419423 "name" => array( 'type' => 'string', 'value' => "foo" ),
420424 "id" => array( 'type' => 'int', 'value' => 3 ),
@@ -435,7 +439,7 @@
436440 $this->assertEquals( $rec['id'], 3 );
437441
438442 ////////////////////////
439 - $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-{field}-{value}.pser';
 443+ $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-name-{name}.pser';
440444 $spec['dataFormat'] = 'php';
441445 $source = new WebDataTransclusionSource( $spec );
442446
@@ -443,7 +447,7 @@
444448 $this->assertEquals( $rec['id'], 3 );
445449
446450 ////////////////////////
447 - $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-{field}-{value}.json';
 451+ $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-name-{name}.json';
448452 $spec['dataFormat'] = 'json';
449453 $source = new WebDataTransclusionSource( $spec );
450454
@@ -452,7 +456,7 @@
453457
454458 ////////////////////////
455459 if ( function_exists( 'wddx_unserialize' ) ) {
456 - $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-{field}-{value}.wddx';
 460+ $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-name-{name}.wddx';
457461 $spec['dataFormat'] = 'wddx';
458462 $source = new WebDataTransclusionSource( $spec );
459463
Index: trunk/extensions/DataTransclusion/WebDataTransclusionSource.php
@@ -22,10 +22,10 @@
2323 * WebDataTransclusionSource accepts some additional options
2424 *
2525 * * $spec['url']: base URL for building urls for retrieving individual records.
26 - * If the URL contains the placeholder {field} and/or {value}, these
27 - * get replaced by the field name resp. the field value.
28 - * Otherwise, the key/value pair is appended to the URL as a regular URL
29 - * parameter (preceeded by ? or &, as appropriate). For more
 26+ * If the URL contains placeholders of the form {xxx}, these get replaced
 27+ * by the respective key or option values.
 28+ * Otherwise, the key/value pair and options get appended to the URL as a
 29+ * regular URL parameter (preceeded by ? or &, as appropriate). For more
3030 * complex rules for building the url, override getRecordURL(). REQUIRED.
3131 * * $spec['dataFormat']: Serialization format returned from the web service.
3232 * Supported values are 'php' for PHP serialization format, 'json'
@@ -80,8 +80,8 @@
8181 }
8282 }
8383
84 - public function fetchRecord( $field, $value ) {
85 - $raw = $this->loadRecordData( $field, $value );
 84+ public function fetchRecord( $field, $value, $options = null ) {
 85+ $raw = $this->loadRecordData( $field, $value, $options );
8686 if ( !$raw ) {
8787 wfDebugLog( 'DataTransclusion', "failed to fetch data for $field=$value\n" );
8888 return false;
@@ -109,29 +109,42 @@
110110 return $rec;
111111 }
112112
113 - public function getRecordURL( $field, $value ) {
 113+ public function getRecordURL( $field, $value, $options = null ) {
114114 $u = $this->url;
115115
116 - if ( strpos( $u, '{field}' ) !== false || strpos( $u, '{value}' ) !== false ) {
117 - $u = str_replace( '{field}', urlencode( $field ), $u );
118 - $u = str_replace( '{value}', urlencode( $value ), $u );
119 - } else {
 116+ $args = array( $field => $value );
 117+
 118+ if ( $options ) {
 119+ $args = array_merge( $options, $args );
 120+ }
 121+
 122+ foreach ( $args as $k => $v ) {
 123+ $u = str_replace( '{'.$k.'}', urlencode( $v ), $u, $n );
 124+
 125+ if ( $n ) { //was found and replaced
 126+ unset( $args[ $k ] );
 127+ }
 128+ }
 129+
 130+ $u = preg_replace( '/\{.*?\}/', '', $u ); //strip remaining placeholders
 131+
 132+ foreach ( $args as $k => $v ) {
120133 if ( strpos( $u, '?' ) === false ) {
121134 $u .= '?';
122135 } else {
123136 $u .= '&';
124137 }
125138
126 - $u .= urlencode( $field );
 139+ $u .= urlencode( $k );
127140 $u .= '=';
128 - $u .= urlencode( $value );
 141+ $u .= urlencode( $v );
129142 }
130143
131144 return $u;
132145 }
133146
134 - public function loadRecordData( $field, $value ) {
135 - $u = $this->getRecordURL( $field, $value );
 147+ public function loadRecordData( $field, $value, $options ) {
 148+ $u = $this->getRecordURL( $field, $value, $options );
136149 return $this->loadRecordDataFromURL( $u );
137150 }
138151
Index: trunk/extensions/DataTransclusion/DataTransclusionSource.php
@@ -27,11 +27,11 @@
2828 * Set automatically by DataTransclusionHandler. REQUIRED.
2929 * * $spec['keyFields']: list of fields that can be used as the key
3030 * for fetching a record. REQUIRED.
 31+ * * $spec['optionNames']: names of option that can be specified in addition
 32+ * to a key, to refine the output. Optional.
3133 * * $spec['fieldNames']: names of all fields present in each record.
3234 * Fields not listed here will not be available on the wiki,
3335 * 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.
3636 * * $spec['cacheDuration']: the number of seconds a result from this source
3737 * may be cached for. If not set, results are assumed to be cacheable
3838 * indefinitely. This setting determines the expiry time of the parser
@@ -41,12 +41,11 @@
4242 * the expiry time of ObjectCache entries for records from this source.
4343 * * $spec['sourceInfo']: associative array of information about the data source
4444 * that should be made available on the wiki. This information will be
45 - * present in the record arrays, with they keys prefixed by "source.".
 45+ * present in the record arrays as passed to the template.
4646 * This is intended to allow information about source, license, etc to be
4747 * shown on the wiki. Note that DataTransclusionSource implementations may
4848 * 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'].
 49+ * class forces $spec['sourceInfo']['source-name'] = $spec['name'].
5150 *
5251 * Options used by DataTransclusionHandler but ignored by DataTransclusionSource:
5352 * * $spec['class']: see documentation if $wgDataTransclusionSources in DataTransclusion.
@@ -79,6 +78,7 @@
8079 wfDebugLog( 'DataTransclusion', "constructing " . get_class( $this ) . " \"{$this->name}\"\n" );
8180
8281 $this->keyFields = self::splitList( $spec[ 'keyFields' ] );
 82+ $this->optionNames = self::splitList( @$spec[ 'optionNames' ] );
8383
8484 if ( isset( $spec[ 'fieldNames' ] ) ) {
8585 $this->fieldNames = self::splitList( $spec[ 'fieldNames' ] );
@@ -86,12 +86,6 @@
8787 $this->fieldNames = $this->keyFields;
8888 }
8989
90 - if ( !empty( $spec[ 'defaultKey' ] ) ) {
91 - $this->defaultKey = $spec[ 'defaultKey' ];
92 - } else {
93 - $this->defaultKey = $this->keyFields[ 0 ];
94 - }
95 -
9690 if ( !empty( $spec[ 'cacheDuration' ] ) ) {
9791 $this->cacheDuration = (int)$spec[ 'cacheDuration' ];
9892 } else {
@@ -106,18 +100,13 @@
107101 }
108102 }
109103
110 - $this->sourceInfo[ 'name' ] = $this->name; // force this one
111 - $this->sourceInfo[ 'defaultKey' ] = $this->name; // force this one
 104+ $this->sourceInfo[ 'source-name' ] = $this->name; // force this one
112105 }
113106
114107 public function getName() {
115108 return $this->name;
116109 }
117110
118 - public function getDefaultKey() {
119 - return $this->defaultKey;
120 - }
121 -
122111 public function getSourceInfo() {
123112 return $this->sourceInfo;
124113 }
@@ -126,6 +115,10 @@
127116 return $this->keyFields;
128117 }
129118
 119+ public function getOptionNames() {
 120+ return $this->optionNames;
 121+ }
 122+
130123 public function getFieldNames() {
131124 return $this->fieldNames;
132125 }
@@ -134,7 +127,7 @@
135128 return $this->cacheDuration;
136129 }
137130
138 - public function fetchRecord( $field, $value ) {
 131+ public function fetchRecord( $field, $value, $options = null ) {
139132 throw new MWException( "override fetchRecord()" );
140133 }
141134 }
@@ -162,10 +155,6 @@
163156 return $this->source->getName();
164157 }
165158
166 - public function getDefaultTemplate() {
167 - return $this->source->getDefaultTemplate();
168 - }
169 -
170159 public function getSourceInfo() {
171160 return $this->source->getSourceInfo();
172161 }
@@ -174,6 +163,10 @@
175164 return $this->source->getKeyFields();
176165 }
177166
 167+ public function getOptionNames() {
 168+ return $this->source->getOptionNames();
 169+ }
 170+
178171 public function getFieldNames() {
179172 return $this->source->getFieldNames();
180173 }
@@ -182,16 +175,21 @@
183176 return $this->source->getCacheDuration();
184177 }
185178
186 - public function fetchRecord( $field, $value ) {
 179+ public function fetchRecord( $field, $value, $options = null ) {
187180 global $wgDBname, $wgUser;
188181
189 - $cacheKey = "$wgDBname:DataTransclusion(" . $this->getName() . ":$field=$value)";
 182+ $k = "$field=$value";
 183+ if ( $options ) {
 184+ $k .= "&" . sha1( var_export( $options, false ) );
 185+ }
 186+
 187+ $cacheKey = "$wgDBname:DataTransclusion(" . $this->getName() . ":$k)";
190188
191189 $rec = $this->cache->get( $cacheKey );
192190
193191 if ( !$rec ) {
194192 wfDebugLog( 'DataTransclusion', "fetching fresh record for $field=$value\n" );
195 - $rec = $this->source->fetchRecord( $field, $value );
 193+ $rec = $this->source->fetchRecord( $field, $value, $options );
196194
197195 if ( $rec ) { // XXX: also cache negatives??
198196 $duration = $this->getCacheDuration();
@@ -249,7 +247,7 @@
250248 }
251249 }
252250
253 - public function fetchRecord( $field, $value ) {
 251+ public function fetchRecord( $field, $value, $options = null ) {
254252 return @$this->lookup[ $field ][ $value ];
255253 }
256254 }
Index: trunk/extensions/DataTransclusion/DBDataTransclusionSource.php
@@ -35,7 +35,7 @@
3636 * * $spec['keyFields']: like for DataTransclusionSource, this is list of fields
3737 * that can be used as the key for fetching a record. However, it's not required
3838 * for DBDataTransclusionSource: if not provided, array_keys( $spec['keyTypes'] )
39 - * will be used. REQUIRED.
 39+ * will be used.
4040 *
4141 * For more information on options supported by DataTransclusionSource, see the class-level
4242 * documentation there.
@@ -112,7 +112,7 @@
113113 return $sql;
114114 }
115115
116 - public function fetchRecord( $field, $value ) {
 116+ public function fetchRecord( $field, $value, $options = null ) {
117117 $db = wfGetDB( DB_SLAVE );
118118
119119 $sql = $this->getQuery( $field, $value, $db );

Status & tagging log