r68001 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68000‎ | r68001 | r68002 >
Date:16:19, 14 June 2010
Author:daniel
Status:deferred
Tags:
Comment:
rewrote field value extraction for complex records
Modified paths:
  • /trunk/extensions/DataTransclusion/DataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/WebDataTransclusionSource.php (modified) (history)
  • /trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php (modified) (history)
  • /trunk/extensions/DataTransclusion/tests/fetchRecord.php (added) (history)

Diff [purge]

Index: trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php
@@ -403,7 +403,7 @@
404404 'url' => 'http://acme.com/{name}',
405405 'dataFormat' => 'php',
406406 'dataPath' => 'response/content/@0',
407 - 'valuePath' => 'value',
 407+ 'fieldPathes' => array( 'id' => 'id/value', 'name' => 'name/value', 'info' => 'info/value', ),
408408 'errorPath' => 'response/error',
409409 );
410410
@@ -420,7 +420,7 @@
421421
422422 $rec = array(
423423 "name" => array( 'type' => 'string', 'value' => "foo" ),
424 - "id" => array( 'type' => 'int', 'value' => 3 ),
 424+ "id" => 3,
425425 "info" => array( 'type' => 'string', 'value' => "test X" ),
426426 );
427427
@@ -438,6 +438,9 @@
439439 $this->assertEquals( $err, 'test error' );
440440 $this->assertEquals( $rec['id'], 3 );
441441
 442+ //TODO: test extractField, with fancy snytax!
 443+ //TODO: test flattenRecord
 444+
442445 ////////////////////////
443446 $spec['url'] = 'file://' . dirname( realpath( __FILE__ ) ) . '/test-data-name-{name}.pser';
444447 $spec['dataFormat'] = 'php';
Index: trunk/extensions/DataTransclusion/tests/fetchRecord.php
@@ -0,0 +1,31 @@
 2+<?php
 3+if ( isset( $GET_ ) ) {
 4+ echo( "This file cannot be run from the web.\n" );
 5+ die( 1 );
 6+}
 7+
 8+if ( getenv( 'MW_INSTALL_PATH' ) ) {
 9+ $IP = getenv( 'MW_INSTALL_PATH' );
 10+} else {
 11+ $dir = dirname( __FILE__ );
 12+
 13+ if ( file_exists( "$dir/../../LocalSettings.php" ) ) $IP = "$dir/../..";
 14+ else if ( file_exists( "$dir/../../../LocalSettings.php" ) ) $IP = "$dir/../../..";
 15+ else if ( file_exists( "$dir/../../phase3/LocalSettings.php" ) ) $IP = "$dir/../../phase3";
 16+ else if ( file_exists( "$dir/../../../phase3/LocalSettings.php" ) ) $IP = "$dir/../../../phase3";
 17+ else $IP = $dir;
 18+}
 19+
 20+require_once( "$IP/maintenance/commandLine.inc" );
 21+
 22+$dir = dirname( __FILE__ );
 23+$dtbase = dirname( realpath( $dir ) );
 24+
 25+$src = $args[0];
 26+$field = $args[1];
 27+$value = $args[2];
 28+
 29+$source = DataTransclusionHandler::getDataSource( $src );
 30+$data = $source->fetchRecord( $field, $value, null );
 31+
 32+print_r( $data );
\ No newline at end of file
Property changes on: trunk/extensions/DataTransclusion/tests/fetchRecord.php
___________________________________________________________________
Name: svn:mergeinfo
133 +
Name: svn:eol-style
234 + native
Index: trunk/extensions/DataTransclusion/WebDataTransclusionSource.php
@@ -38,10 +38,14 @@
3939 * a "meta-key" of the form @@N, where N is an integer. A meta-key refers to the
4040 * Nth entry in an associative array: @1 would be "bar" in array( 'x' => "foo", 'y' => "bar" ).
4141 * For more complex retrieval of the record, override extractRecord(). REQUIRED.
42 - * * $spec['valuePath']: "path" to the actual field values inside the record associated
43 - * with each field. Optional, should only be specified if field values are returned
44 - * as complex records instead of simple values. For more complex processing, override
45 - * the method sanitizeRecord().
 42+ * * $spec['fieldPathes']: an associative array giving a "path" for each fied which points
 43+ * to the actual field values inside the record, that is, the structure that
 44+ * $spec['dataPath'] resolved to. Useful when field values are returned as complex
 45+ * records. For more complex processing, override the method flattenRecord().
 46+ * If given, $spec['fieldNames'] defaults to array_keys( $spec['fieldPathes'] ).
 47+ * * $spec['fieldNames']: names of all fields present in each record.
 48+ * Fields not listed here will not be available on the wiki,
 49+ * even if they are returned by the data source. Required if fieldPathes is not given.
4650 * * $spec['errorPath']: "path" to error messages in the structure returned from the
4751 * HTTP request. The path is evaluated as deswcribed for $spec['dataPath']. If an
4852 * entry is found at the given position in the response structure, the request
@@ -57,16 +61,26 @@
5862 class WebDataTransclusionSource extends DataTransclusionSource {
5963
6064 function __construct( $spec ) {
 65+ if ( !isset( $spec['fieldNames'] ) && isset( $spec['fieldPathes'] ) ) {
 66+ $spec['fieldNames'] = array_keys( $spec['fieldPathes'] );
 67+ }
 68+
6169 DataTransclusionSource::__construct( $spec );
6270
6371 $this->url = $spec[ 'url' ];
6472 $this->dataFormat = @$spec[ 'dataFormat' ];
65 - $this->dataPath = DataTransclusionSource::splitList( @$spec[ 'dataPath' ] );
66 - $this->valuePath = DataTransclusionSource::splitList( @$spec[ 'valuePath' ] );
67 - $this->errorPath = DataTransclusionSource::splitList( @$spec[ 'errorPath' ] );
 73+ $this->dataPath = DataTransclusionSource::splitList( @$spec[ 'dataPath' ], '/' );
 74+ $this->fieldPathes = @$spec[ 'fieldPathes' ];
 75+ $this->errorPath = DataTransclusionSource::splitList( @$spec[ 'errorPath' ], '/' );
6876 $this->httpOptions = @$spec[ 'httpOptions' ];
6977 $this->timeout = @$spec[ 'timeout' ];
7078
 79+ if ( $this->fieldPathes ) {
 80+ foreach ( $this->fieldPathes as $i => $p ) {
 81+ $this->fieldPathes[ $i ] = DataTransclusionSource::splitList( $p, '/' );
 82+ }
 83+ }
 84+
7185 if ( !$this->dataFormat ) {
7286 $this->dataFormat = 'php';
7387 }
@@ -170,6 +184,7 @@
171185 }
172186
173187 if ( $format == 'json' || $format == 'js' ) {
 188+ $raw = preg_replace( '/^\s*(var\s)?\w([\w\d]*)\s+=\s*|\s*;\s*$/sim', '', $raw);
174189 return FormatJson::decode( $raw, true );
175190 }
176191
@@ -191,23 +206,25 @@
192207 public function extractRecord( $data ) {
193208 $rec = $this->extractField( $data, $this->dataPath );
194209
195 - $rec = $this->sanitizeRecord( $rec );
 210+ $rec = $this->flattenRecord( $rec );
196211 return $rec;
197212 }
198213
199 - public function sanitizeRecord( $rec ) {
200 - if ( $this->valuePath !== null && $this->valuePath !== false ) {
 214+ public function flattenRecord( $rec ) {
 215+ if ( !$rec ) return $rec;
 216+
 217+ if ( $this->fieldPathes ) {
201218 $r = array();
202219
203 - foreach ( $rec as $k => $v ) {
204 - if ( is_array( $v ) || is_object( $v ) ) {
205 - $w = $this->extractField( $v, $this->valuePath );
206 - //XXX: how to hanlde $w === false failures here?
 220+ foreach ( $this->fieldNames as $k ) {
 221+ if ( isset( $this->fieldPathes[$k] ) ) {
 222+ $path = $this->fieldPathes[$k];
 223+ $v = $this->extractField( $rec, $path );
207224 } else {
208 - $w = $v; //XXX: ugly default. fail instead??
 225+ $v = $rec[ $k ];
209226 }
210227
211 - $r[ $k ] = $w;
 228+ $r[ $k ] = $v;
212229 }
213230
214231 return $r;
@@ -217,34 +234,69 @@
218235 }
219236
220237 public function extractField( $data, $path ) {
221 - if ( $path == null ) {
222 - return $data;
 238+ if ( is_object( $data ) ) {
 239+ $data = wfObjectToArray( $data );
223240 }
224241
225 - if ( is_string( $path ) ) {
 242+ if ( !is_array( $data ) || $path === '.' ) {
 243+ return $data;
 244+ }
 245+
 246+ if ( is_string( $path ) || is_int( $path ) ) {
226247 return @$data[ $path ];
227248 }
228249
229 - foreach ( $path as $p ) {
230 - if ( is_object( $data ) ) {
231 - $data = wfObjectToArray( $data );
 250+ if ( !$path ) {
 251+ return $data;
 252+ }
 253+
 254+ $p = array_shift( $path );
 255+
 256+ if ( strpos( $p, '|' ) ) { //alternatives
 257+ $alternatives = explode( '|', $p );
 258+ foreach ( $alternatives as $a ) {
 259+ $ap = array_merge( array( $a ), $path );
 260+ $v = $this->extractField( $data, $ap );
 261+
 262+ if ( $v !== null && $v !== false ) {
 263+ return $v;
 264+ }
232265 }
 266+ } else if ( is_string( $p ) && preg_match( '/^\(([^\w\d])\)$/', $p, $m ) ) { //concat all
 267+ $s = "";
 268+ foreach ( $data as $d ) {
 269+ $v = $this->extractField( $d, $path );
233270
234 - // meta-key: index in the list of array-keys.
235 - // e.g. use @0 to grab the first value from an assoc array.
236 - if ( is_string( $p ) && preg_match( '/^@(\d+)$/', $p, $m ) ) {
237 - $i = (int)$m[1];
238 - $k = array_keys( $data );
239 - $p = $k[ $i ];
 271+ if ( $v !== null && $v !== false ) {
 272+ if ( $s != "" ) $s .= $m[1];
 273+ $s .= $v;
 274+ }
240275 }
241276
 277+ return $s;
 278+ } else {
 279+ if ( is_string( $p ) && preg_match( '/^(@)?(\d+)$/', $p, $m ) ) { //numberic index
 280+ $i = (int)$m[2];
 281+
 282+ if ( $m[1] ) { //meta-index
 283+ $k = array_keys( $data );
 284+ $p = $k[ $i ];
 285+ }
 286+ }
 287+
242288 if ( !isset( $data[ $p ] ) ) {
243289 return false;
244290 }
245291
246 - $data = $data[ $p ];
 292+ $next = $data[ $p ];
 293+
 294+ if ( $next && $path ) {
 295+ return $this->extractField( $next, $path );
 296+ } else {
 297+ return $next;
 298+ }
247299 }
248300
249 - return $data;
 301+ //TODO: named components. separator??
250302 }
251303 }
Index: trunk/extensions/DataTransclusion/DataTransclusionSource.php
@@ -54,7 +54,7 @@
5555 * Lists may be given as arrays or strings with items separated by [,;|].
5656 */
5757 class DataTransclusionSource {
58 - static function splitList( $s ) {
 58+ static function splitList( $s, $chars = ',;|' ) {
5959 if ( $s === null || $s === false ) {
6060 return $s;
6161 }
@@ -63,7 +63,7 @@
6464 return $s;
6565 }
6666
67 - $list = preg_split( '!\s*[,;|/]\s*!', $s );
 67+ $list = preg_split( '!\s*[' . $chars . ']\s*!', $s );
6868
6969 return $list;
7070 }

Status & tagging log