Index: trunk/extensions/DataTransclusion/DataTransclusionHandler.php |
— | — | @@ -23,8 +23,7 @@ |
24 | 24 | if ( preg_match( '/^\s*(\S.*?)\s*=\s*(.*?)\s*$/', $p, $m ) ) { |
25 | 25 | $k = $m[1]; |
26 | 26 | $v = preg_replace( '/^"\s*(.*?)\s*"$/', '$1', $m[2] ); // strip any quotes enclosing the value |
27 | | - } |
28 | | - else { |
| 27 | + } else { |
29 | 28 | $v = trim( $p ); |
30 | 29 | $k = $i; |
31 | 30 | $i += 1; |
— | — | @@ -62,8 +61,11 @@ |
63 | 62 | array_shift( $params ); // $key |
64 | 63 | array_shift( $params ); // $asHTML |
65 | 64 | |
66 | | - if ( $asHTML ) $mode = 'parseinline'; |
67 | | - else $mode = 'parsemag'; |
| 65 | + if ( $asHTML ) { |
| 66 | + $mode = 'parseinline'; |
| 67 | + } else { |
| 68 | + $mode = 'parsemag'; |
| 69 | + } |
68 | 70 | |
69 | 71 | $m = wfMsgExt( $key, $mode, $params ); |
70 | 72 | |
— | — | @@ -85,32 +87,49 @@ |
86 | 88 | static function handleRecordTransclusion( $key, $argv, $parser, $asHTML, $templateText = null ) { |
87 | 89 | // find out which data source to use... |
88 | 90 | if ( empty( $argv['source'] ) ) { |
89 | | - if ( empty( $argv[1] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-source', $asHTML ); // TESTME |
90 | | - else $sourceName = $argv[1]; |
| 91 | + if ( empty( $argv[1] ) ) { |
| 92 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-source', $asHTML ); // TESTME |
| 93 | + } else { |
| 94 | + $sourceName = $argv[1]; |
| 95 | + } |
91 | 96 | } else { |
92 | 97 | $sourceName = $argv['source']; |
93 | 98 | } |
94 | 99 | |
95 | 100 | $source = DataTransclusionHandler::getDataSource( $sourceName ); |
96 | | - if ( empty( $source ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-source', $asHTML, $sourceName ); // TESTME |
| 101 | + if ( empty( $source ) ) { |
| 102 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-source', $asHTML, $sourceName ); // TESTME |
| 103 | + } |
97 | 104 | |
98 | 105 | // find out how to find the desired record |
99 | | - if ( empty( $argv['by'] ) ) $by = $source->getDefaultKey(); |
100 | | - else $by = $argv['by']; |
| 106 | + if ( empty( $argv['by'] ) ) { |
| 107 | + $by = $source->getDefaultKey(); |
| 108 | + } else { |
| 109 | + $by = $argv['by']; |
| 110 | + } |
101 | 111 | |
102 | 112 | $keyFields = $source->getKeyFields(); |
103 | | - if ( ! in_array( $by, $keyFields ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-argument-by', $asHTML, $sourceName, $by, join( ', ', $keyFields ) ); // TESTME |
| 113 | + if ( ! in_array( $by, $keyFields ) ) { |
| 114 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-argument-by', $asHTML, $sourceName, $by, join( ', ', $keyFields ) ); // TESTME |
| 115 | + } |
104 | 116 | |
105 | | - if ( !empty( $argv['key'] ) ) $key = $argv['key']; |
106 | | - else if ( $key === null || $key === false ) { |
107 | | - if ( empty( $argv[2] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-key', $asHTML ); // TESTME |
108 | | - else $key = $argv[2]; |
| 117 | + if ( !empty( $argv['key'] ) ) { |
| 118 | + $key = $argv['key']; |
| 119 | + } else if ( $key === null || $key === false ) { |
| 120 | + if ( empty( $argv[2] ) ) { |
| 121 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-key', $asHTML ); // TESTME |
| 122 | + } else { |
| 123 | + $key = $argv[2]; |
| 124 | + } |
109 | 125 | } |
110 | 126 | |
111 | 127 | // find out how to render the record |
112 | 128 | if ( empty( $argv['template'] ) ) { |
113 | | - if ( empty( $argv[3] ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML ); // TESTME |
114 | | - else $template = $argv[3]; |
| 129 | + if ( empty( $argv[3] ) ) { |
| 130 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-missing-argument-template', $asHTML ); // TESTME |
| 131 | + } else { |
| 132 | + $template = $argv[3]; |
| 133 | + } |
115 | 134 | } else { |
116 | 135 | $template = $argv['template']; |
117 | 136 | } |
— | — | @@ -121,7 +140,9 @@ |
122 | 141 | |
123 | 142 | // render the record into wiki text |
124 | 143 | $t = Title::newFromText( $template, NS_TEMPLATE ); |
125 | | - if ( empty( $t ) ) return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-template-name', $asHTML, $template ); // TESTME |
| 144 | + if ( empty( $t ) ) { |
| 145 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-bad-template-name', $asHTML, $template ); // TESTME |
| 146 | + } |
126 | 147 | |
127 | 148 | // FIXME: log the template we used into the parser output, like regular template use |
128 | 149 | // (including templates used by the template, etc) |
— | — | @@ -131,7 +152,9 @@ |
132 | 153 | $record = $handler->normalizeRecord( $record ); |
133 | 154 | $text = $handler->render( $record ); |
134 | 155 | |
135 | | - if ( $text === false ) return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-template', $asHTML, $template ); // TESTME |
| 156 | + if ( $text === false ) { |
| 157 | + return DataTransclusionHandler::errorMessage( 'datatransclusion-unknown-template', $asHTML, $template ); // TESTME |
| 158 | + } |
136 | 159 | |
137 | 160 | // set parser output expiry |
138 | 161 | $expire = $source->getCacheDuration(); |
— | — | @@ -181,15 +204,17 @@ |
182 | 205 | |
183 | 206 | // dumb and slow, but works |
184 | 207 | if ( $this->templateText ) { |
185 | | - if ( is_string( $this->templateText ) ) |
| 208 | + if ( is_string( $this->templateText ) ) { |
186 | 209 | $text = $this->templateText; |
187 | | - else |
| 210 | + } else { |
188 | 211 | $text = $this->templateText->getContent(); |
| 212 | + } |
189 | 213 | } else { |
190 | 214 | $article = new Article( $this->template ); |
191 | 215 | |
192 | | - if ( !$article->exists() ) |
| 216 | + if ( !$article->exists() ) { |
193 | 217 | return false; // TESTME |
| 218 | + } |
194 | 219 | |
195 | 220 | $text = $article->getContent(); |
196 | 221 | } |
— | — | @@ -205,8 +230,11 @@ |
206 | 231 | // keep record fields, add missing values |
207 | 232 | $fields = $this->source->getFieldNames(); |
208 | 233 | foreach ( $fields as $f ) { |
209 | | - if ( isset( $record[ $f ] ) ) $v = $record[ $f ]; |
210 | | - else $v = ''; |
| 234 | + if ( isset( $record[ $f ] ) ) { |
| 235 | + $v = $record[ $f ]; |
| 236 | + } else { |
| 237 | + $v = ''; |
| 238 | + } |
211 | 239 | |
212 | 240 | $rec[ $f ] = $this->sanitizeValue( $v ); // TESTME |
213 | 241 | } |
— | — | @@ -215,7 +243,10 @@ |
216 | 244 | // provide license info, etc |
217 | 245 | $info = $this->source->getSourceInfo(); // TESTME |
218 | 246 | foreach ( $info as $f => $v ) { |
219 | | - if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) continue; |
| 247 | + if ( is_array( $v ) || is_object( $v ) || is_resource( $v ) ) { |
| 248 | + continue; |
| 249 | + } |
| 250 | + |
220 | 251 | $rec[ "source.$f" ] = $this->sanitizeValue( $v ); |
221 | 252 | } |
222 | 253 | |
— | — | @@ -255,7 +286,9 @@ |
256 | 287 | |
257 | 288 | static function getDataSource( $name ) { |
258 | 289 | global $wgDataTransclusionSources; |
259 | | - if ( empty( $wgDataTransclusionSources[ $name ] ) ) return false; |
| 290 | + if ( empty( $wgDataTransclusionSources[ $name ] ) ) { |
| 291 | + return false; |
| 292 | + } |
260 | 293 | |
261 | 294 | $source = $wgDataTransclusionSources[ $name ]; |
262 | 295 | |
— | — | @@ -263,11 +296,15 @@ |
264 | 297 | $spec = $source; |
265 | 298 | $spec[ 'name' ] = $name; |
266 | 299 | |
267 | | - if ( !isset( $spec[ 'class' ] ) ) throw new MWException( "\$wgDataTransclusionSources['$name'] must specifying a class name in the 'class' field." ); |
| 300 | + if ( !isset( $spec[ 'class' ] ) ) { |
| 301 | + throw new MWException( "\$wgDataTransclusionSources['$name'] must specifying a class name in the 'class' field." ); |
| 302 | + } |
268 | 303 | |
269 | 304 | $c = $spec[ 'class' ]; |
270 | 305 | $obj = new $c( $spec ); // pass spec array as constructor argument |
271 | | - if ( !$obj ) throw new MWException( "failed to instantiate \$wgDataTransclusionSources['$name'] as new $c." ); |
| 306 | + if ( !$obj ) { |
| 307 | + throw new MWException( "failed to instantiate \$wgDataTransclusionSources['$name'] as new $c." ); |
| 308 | + } |
272 | 309 | |
273 | 310 | $source = $obj; |
274 | 311 | |
— | — | @@ -284,7 +321,9 @@ |
285 | 322 | } |
286 | 323 | |
287 | 324 | if ( !is_object( $source ) ) { |
288 | | - if ( !isset( $source[ 'class' ] ) ) throw new MWException( "\$wgDataTransclusionSources['$name'] must be an array or an object." ); |
| 325 | + if ( !isset( $source[ 'class' ] ) ) { |
| 326 | + throw new MWException( "\$wgDataTransclusionSources['$name'] must be an array or an object." ); |
| 327 | + } |
289 | 328 | } |
290 | 329 | |
291 | 330 | return $source; |
Index: trunk/extensions/DataTransclusion/tests/DataTransclusionTest.php |
— | — | @@ -25,18 +25,16 @@ |
26 | 26 | |
27 | 27 | class DataTransclusionTest extends PHPUnit_Framework_TestCase { |
28 | 28 | |
29 | | - function setUp() |
30 | | - { |
| 29 | + function setUp() { |
31 | 30 | global $wgTitle; |
32 | 31 | |
33 | 32 | $wgTitle = Title::newFromText( "Test" ); |
34 | 33 | } |
35 | 34 | |
36 | | - function runTest() |
37 | | - { |
38 | | - $this->testNormalizeRecord(); |
| 35 | + function runTest() { |
39 | 36 | $this->testErrorMessage(); |
40 | 37 | $this->testSanitizeValue(); |
| 38 | + $this->testNormalizeRecord(); |
41 | 39 | $this->testBuildAssociativeArguments(); |
42 | 40 | $this->testGetDataSource(); |
43 | 41 | $this->testCachedFetchRecord(); |
— | — | @@ -352,4 +350,4 @@ |
353 | 351 | $t->runTest(); |
354 | 352 | |
355 | 353 | echo "OK.\n"; |
356 | | -?> |
\ No newline at end of file |
| 354 | +?> |
Index: trunk/extensions/DataTransclusion/WebDataTransclusionSource.php |
— | — | @@ -15,39 +15,39 @@ |
16 | 16 | } |
17 | 17 | |
18 | 18 | /** |
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 | + */ |
52 | 52 | class WebDataTransclusionSource extends DataTransclusionSource { |
53 | 53 | |
54 | 54 | function __construct( $spec ) { |
— | — | @@ -60,23 +60,39 @@ |
61 | 61 | $this->httpOptions = @$spec[ 'httpOptions' ]; |
62 | 62 | $this->timeout = @$spec[ 'timeout' ]; |
63 | 63 | |
64 | | - if ( !$this->dataFormat ) $this->dataFormat = 'php'; |
65 | | - if ( !$this->timeout ) $this->timeout = &$this->httpOptions[ 'timeout' ]; |
66 | | - if ( !$this->timeout ) $this->timeout = 5; |
| 64 | + if ( !$this->dataFormat ) { |
| 65 | + $this->dataFormat = 'php'; |
| 66 | + } |
| 67 | + |
| 68 | + if ( !$this->timeout ) { |
| 69 | + $this->timeout = &$this->httpOptions[ 'timeout' ]; |
| 70 | + } |
| 71 | + |
| 72 | + if ( !$this->timeout ) { |
| 73 | + $this->timeout = 5; |
| 74 | + } |
67 | 75 | } |
68 | 76 | |
69 | 77 | public function fetchRecord( $field, $value ) { |
70 | 78 | $raw = $this->loadRecordData( $field, $value ); // TESTME |
71 | | - if ( !$raw ) return false; // TODO: log error? |
| 79 | + if ( !$raw ) { |
| 80 | + return false; // TODO: log error? |
| 81 | + } |
72 | 82 | |
73 | 83 | $data = $this->decodeData( $raw, $this->dataFormat ); // TESTME |
74 | | - if ( !$data ) return false; // TODO: log error? |
| 84 | + if ( !$data ) { |
| 85 | + return false; // TODO: log error? |
| 86 | + } |
75 | 87 | |
76 | 88 | $err = $this->extractError( $data ); // TESTME |
77 | | - if ( $err ) return false; // TODO: log error? |
| 89 | + if ( $err ) { |
| 90 | + return false; // TODO: log error? |
| 91 | + } |
78 | 92 | |
79 | 93 | $rec = $this->extractRecord( $data ); // TESTME |
80 | | - if ( !$rec ) return false; // TODO: log error? |
| 94 | + if ( !$rec ) { |
| 95 | + return false; // TODO: log error? |
| 96 | + } |
81 | 97 | |
82 | 98 | return $rec; |
83 | 99 | } |
— | — | @@ -84,8 +100,11 @@ |
85 | 101 | public function getRecordURL( $field, $value ) { |
86 | 102 | $u = $this->url; |
87 | 103 | |
88 | | - if ( strpos( $u, '?' ) === false ) $u .= '?'; |
89 | | - else $u .= '&'; |
| 104 | + if ( strpos( $u, '?' ) === false ) { |
| 105 | + $u .= '?'; |
| 106 | + } else { |
| 107 | + $u .= '&'; |
| 108 | + } |
90 | 109 | |
91 | 110 | $u .= $field; |
92 | 111 | $u .= '='; |
— | — | @@ -102,10 +121,18 @@ |
103 | 122 | } |
104 | 123 | |
105 | 124 | public 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 |
| 125 | + if ( $format == 'json' ) { |
| 126 | + return FormatJson::decode( $raw, true ); // TESTME |
| 127 | + } |
109 | 128 | |
| 129 | + if ( $format == 'wddx' ) { |
| 130 | + return wddx_unserialize( $raw ); // TESTME |
| 131 | + } |
| 132 | + |
| 133 | + if ( $format == 'php' ) { |
| 134 | + return unserialize( $raw ); // TESTME |
| 135 | + } |
| 136 | + |
110 | 137 | return false; |
111 | 138 | } |
112 | 139 | |
— | — | @@ -118,13 +145,20 @@ |
119 | 146 | } |
120 | 147 | |
121 | 148 | public function extractField( $data, $path ) { |
122 | | - if ( $path == null ) return $data; |
123 | | - if ( is_string( $path ) ) return @$data[ $path ]; |
| 149 | + if ( $path == null ) { |
| 150 | + return $data; |
| 151 | + } |
124 | 152 | |
| 153 | + if ( is_string( $path ) ) { |
| 154 | + return @$data[ $path ]; |
| 155 | + } |
| 156 | + |
125 | 157 | foreach ( $path as $p ) { |
126 | | - if ( is_object( $data ) ) $data = wfObjectToArray( $data ); |
| 158 | + if ( is_object( $data ) ) { |
| 159 | + $data = wfObjectToArray( $data ); |
| 160 | + } |
127 | 161 | |
128 | | - // meta-key: index in the list of array-keys. |
| 162 | + // meta-key: index in the list of array-keys. |
129 | 163 | // e.g. use @0 to grab the first value from an assoc array. |
130 | 164 | if ( is_string( $p ) && preg_match( '/^@(\d+)$/', $p, $m ) ) { |
131 | 165 | $i = (int)$m[1]; |
— | — | @@ -132,7 +166,10 @@ |
133 | 167 | $p = $k[ $i ]; |
134 | 168 | } |
135 | 169 | |
136 | | - if ( !isset( $data[ $p ] ) ) return false; |
| 170 | + if ( !isset( $data[ $p ] ) ) { |
| 171 | + return false; |
| 172 | + } |
| 173 | + |
137 | 174 | $data = $data[ $p ]; |
138 | 175 | } |
139 | 176 | |
Index: trunk/extensions/DataTransclusion/DataTransclusionSource.php |
— | — | @@ -15,73 +15,86 @@ |
16 | 16 | } |
17 | 17 | |
18 | 18 | /** |
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 | + */ |
58 | 58 | class DataTransclusionSource { |
59 | 59 | static function splitList( $s ) { |
60 | | - if ( $s === null || $s === false ) return $s; |
61 | | - if ( !is_string( $s ) ) return $s; |
62 | | - |
| 60 | + if ( $s === null || $s === false ) { |
| 61 | + return $s; |
| 62 | + } |
| 63 | + |
| 64 | + if ( !is_string( $s ) ) { |
| 65 | + return $s; |
| 66 | + } |
| 67 | + |
63 | 68 | $list = preg_split( '!\s*[,;|/]\s*!', $s ); |
| 69 | + |
64 | 70 | return $list; |
65 | 71 | } |
66 | 72 | |
67 | 73 | /** |
68 | | - * Initializes the DataTransclusionSource from the given parameter array. |
69 | | - * @param $spec associative array of options. See class-level documentation for details. |
70 | | - */ |
| 74 | + * Initializes the DataTransclusionSource from the given parameter array. |
| 75 | + * @param $spec associative array of options. See class-level documentation for details. |
| 76 | + */ |
71 | 77 | function __construct( $spec ) { |
72 | 78 | $this->name = $spec[ 'name' ]; |
73 | 79 | |
74 | 80 | $this->keyFields = self::splitList( $spec[ 'keyFields' ] ); |
75 | 81 | |
76 | | - if ( isset( $spec[ 'fieldNames' ] ) ) |
| 82 | + if ( isset( $spec[ 'fieldNames' ] ) ) { |
77 | 83 | $this->fieldNames = self::splitList( $spec[ 'fieldNames' ] ); |
78 | | - else |
| 84 | + } else { |
79 | 85 | $this->fieldNames = $this->keyFields; |
| 86 | + } |
80 | 87 | |
81 | | - if ( !empty( $spec[ 'defaultKey' ] ) ) $this->defaultKey = $spec[ 'defaultKey' ]; |
82 | | - else $this->defaultKey = $this->keyFields[ 0 ]; |
| 88 | + if ( !empty( $spec[ 'defaultKey' ] ) ) { |
| 89 | + $this->defaultKey = $spec[ 'defaultKey' ]; |
| 90 | + } else { |
| 91 | + $this->defaultKey = $this->keyFields[ 0 ]; |
| 92 | + } |
83 | 93 | |
84 | | - if ( !empty( $spec[ 'cacheDuration' ] ) ) $this->cacheDuration = (int)$spec[ 'cacheDuration' ]; |
85 | | - else $this->cacheDuration = null; |
| 94 | + if ( !empty( $spec[ 'cacheDuration' ] ) ) { |
| 95 | + $this->cacheDuration = (int)$spec[ 'cacheDuration' ]; |
| 96 | + } else { |
| 97 | + $this->cacheDuration = null; |
| 98 | + } |
86 | 99 | |
87 | 100 | $this->sourceInfo = array(); |
88 | 101 | |
— | — | @@ -104,7 +117,7 @@ |
105 | 118 | } |
106 | 119 | |
107 | 120 | public function getSourceInfo() { |
108 | | - return $this->sourceInfo; |
| 121 | + return $this->sourceInfo; |
109 | 122 | } |
110 | 123 | |
111 | 124 | public function getKeyFields() { |
— | — | @@ -125,18 +138,18 @@ |
126 | 139 | } |
127 | 140 | |
128 | 141 | /** |
129 | | -* Implementation of DataTransclusionSource that wraps another DataTransclusionSource and applies caching in an |
130 | | -* ObjectCache. All methods delegate to the underlieing data source, fetchRecord adds logic for caching. |
131 | | -*/ |
| 142 | + * Implementation of DataTransclusionSource that wraps another DataTransclusionSource and applies caching in an |
| 143 | + * ObjectCache. All methods delegate to the underlieing data source, fetchRecord adds logic for caching. |
| 144 | + */ |
132 | 145 | class CachingDataTransclusionSource extends DataTransclusionSource { |
133 | 146 | |
134 | 147 | /** |
135 | | - * Initializes the CachingDataTransclusionSource |
136 | | - * |
137 | | - * @param $source a DataTransclusionSource instance for fetching data records. |
138 | | - * @param $cache an ObjectCache instance |
139 | | - * @param $duration number of seconds for which records may be cached |
140 | | - */ |
| 148 | + * Initializes the CachingDataTransclusionSource |
| 149 | + * |
| 150 | + * @param $source a DataTransclusionSource instance for fetching data records. |
| 151 | + * @param $cache an ObjectCache instance |
| 152 | + * @param $duration number of seconds for which records may be cached |
| 153 | + */ |
141 | 154 | function __construct( $source, $cache, $duration ) { |
142 | 155 | $this->source = $source; |
143 | 156 | $this->cache = $cache; |
— | — | @@ -176,7 +189,9 @@ |
177 | 190 | |
178 | 191 | if ( !$rec ) { |
179 | 192 | $rec = $this->source->fetchRecord( $key, $value ); |
180 | | - if ( $rec ) $this->cache->set( $cacheKey, $rec, $this->getCacheDuration() ) ; // XXX: also cache negatives?? |
| 193 | + if ( $rec ) { |
| 194 | + $this->cache->set( $cacheKey, $rec, $this->getCacheDuration() ) ; // XXX: also cache negatives?? |
| 195 | + } |
181 | 196 | } |
182 | 197 | |
183 | 198 | return $rec; |
— | — | @@ -184,25 +199,27 @@ |
185 | 200 | } |
186 | 201 | |
187 | 202 | /** |
188 | | -* Implementations of DataTransclusionSource which simply fetches data from an array. This is |
189 | | -* intended mainly for testing and debugging. |
190 | | -*/ |
| 203 | + * Implementations of DataTransclusionSource which simply fetches data from an array. This is |
| 204 | + * intended mainly for testing and debugging. |
| 205 | + */ |
191 | 206 | class FakeDataTransclusionSource extends DataTransclusionSource { |
192 | 207 | |
193 | 208 | /** |
194 | | - * Initializes the CachingDataTransclusionSource |
195 | | - * |
196 | | - * @param $spec an associative array of options. See class-level |
197 | | - * documentation of DataTransclusionSource for details. |
198 | | - * |
199 | | - * @param $data an array containing a list of records. Records from |
200 | | - * this list can be accessed via fetchRecord() using the key fields specified |
201 | | - * by $spec['keyFields']. If $data is not given, $spec['data'] must contain the data array. |
202 | | - */ |
| 209 | + * Initializes the CachingDataTransclusionSource |
| 210 | + * |
| 211 | + * @param $spec an associative array of options. See class-level |
| 212 | + * documentation of DataTransclusionSource for details. |
| 213 | + * |
| 214 | + * @param $data an array containing a list of records. Records from |
| 215 | + * this list can be accessed via fetchRecord() using the key fields specified |
| 216 | + * by $spec['keyFields']. If $data is not given, $spec['data'] must contain the data array. |
| 217 | + */ |
203 | 218 | function __construct( $spec, $data = null ) { |
204 | 219 | DataTransclusionSource::__construct( $spec ); |
205 | 220 | |
206 | | - if ( $data === null ) $data = $spec[ 'data' ]; |
| 221 | + if ( $data === null ) { |
| 222 | + $data = $spec[ 'data' ]; |
| 223 | + } |
207 | 224 | |
208 | 225 | $this->lookup = array(); |
209 | 226 | |
— | — | @@ -215,8 +232,10 @@ |
216 | 233 | $fields = $this->getKeyFields(); |
217 | 234 | foreach ( $fields as $f ) { |
218 | 235 | $k = $record[ $f ]; |
219 | | - |
220 | | - if ( !isset( $this->lookup[ $f ] ) ) $this->lookup[ $f ] = array(); |
| 236 | + if ( !isset( $this->lookup[ $f ] ) ) { |
| 237 | + $this->lookup[ $f ] = array(); |
| 238 | + } |
| 239 | + |
221 | 240 | $this->lookup[ $f ][ $k ] = $record; |
222 | 241 | } |
223 | 242 | } |
Index: trunk/extensions/DataTransclusion/DBDataTransclusionSource.php |
— | — | @@ -15,75 +15,100 @@ |
16 | 16 | } |
17 | 17 | |
18 | 18 | /** |
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 | + */ |
44 | 44 | class DBDataTransclusionSource extends DataTransclusionSource { |
45 | 45 | |
46 | 46 | /** |
47 | | - * Initializes the DBDataTransclusionSource from the given parameter array. |
48 | | - * @param $spec associative array of options. See class-level documentation for details. |
49 | | - */ |
| 47 | + * Initializes the DBDataTransclusionSource from the given parameter array. |
| 48 | + * @param $spec associative array of options. See class-level documentation for details. |
| 49 | + */ |
50 | 50 | function __construct( $spec ) { |
51 | | - if ( !isset( $spec[ 'keyFields' ] ) && isset( $spec[ 'keyTypes' ] ) ) $spec[ 'keyFields' ] = array_keys( $spec[ 'keyTypes' ] ); |
| 51 | + if ( !isset( $spec[ 'keyFields' ] ) && isset( $spec[ 'keyTypes' ] ) ) { |
| 52 | + $spec[ 'keyFields' ] = array_keys( $spec[ 'keyTypes' ] ); |
| 53 | + } |
52 | 54 | |
53 | 55 | DataTransclusionSource::__construct( $spec ); |
54 | 56 | |
55 | 57 | $this->query = $spec[ 'query' ]; |
56 | 58 | $this->querySuffix = @$spec[ 'querySuffix' ]; |
57 | 59 | |
58 | | - if ( isset( $spec[ 'keyTypes' ] ) ) $this->keyTypes = $spec[ 'keyTypes' ]; |
59 | | - else $this->keyTypes = null; |
| 60 | + if ( isset( $spec[ 'keyTypes' ] ) ) { |
| 61 | + $this->keyTypes = $spec[ 'keyTypes' ]; |
| 62 | + } else { |
| 63 | + $this->keyTypes = null; |
| 64 | + } |
60 | 65 | } |
61 | 66 | |
62 | 67 | public function convertKey( $key, $value ) { |
63 | | - if ( !isset( $this->keyTypes[ $key ] ) ) return (string)$value; |
| 68 | + if ( !isset( $this->keyTypes[ $key ] ) ) { |
| 69 | + return (string)$value; |
| 70 | + } |
64 | 71 | |
65 | 72 | $t = strtolower( trim( $this->keyTypes[ $key ] ) ); |
66 | 73 | |
67 | | - if ( $t == 'int' ) return (int)$value; |
68 | | - else if ( $t == 'decimal' || $t == 'float' ) return (float)$value; |
69 | | - else return (string)$value; |
| 74 | + if ( $t == 'int' ) { |
| 75 | + return (int)$value; |
| 76 | + } else if ( $t == 'decimal' || $t == 'float' ) { |
| 77 | + return (float)$value; |
| 78 | + } else { |
| 79 | + return (string)$value; |
| 80 | + } |
70 | 81 | } |
71 | 82 | |
72 | 83 | public function getQuery( $field, $value, $db = null ) { |
73 | | - if ( !$db ) $db = wfGetDB( DB_SLAVE ); |
74 | | - if ( !preg_match( '/\w+[\w\d]+/', $field ) ) return false; // redundant, but make extra sure we don't get anythign evil here //TESTME |
| 84 | + if ( !$db ) { |
| 85 | + $db = wfGetDB( DB_SLAVE ); |
| 86 | + } |
75 | 87 | |
| 88 | + if ( !preg_match( '/\w+[\w\d]+/', $field ) ) { |
| 89 | + return false; // redundant, but make extra sure we don't get anythign evil here //TESTME |
| 90 | + } |
| 91 | + |
76 | 92 | $value = $this->convertKey( $field, $value ); // TESTME |
77 | 93 | |
78 | | - if ( is_string( $value ) ) $v = $db->addQuotes( $value ); // TESTME |
79 | | - else $v = $value; |
| 94 | + if ( is_string( $value ) ) { |
| 95 | + $v = $db->addQuotes( $value ); // TESTME |
| 96 | + } else { |
| 97 | + $v = $value; |
| 98 | + } |
80 | 99 | |
81 | 100 | $where = "( " . $field . " = " . $v . " )"; |
82 | 101 | |
83 | | - if ( preg_match( '/[)\s]WHERE[\s(]/is', $this->query ) ) $sql = $this->query . " AND " . $where; |
84 | | - else $sql = $this->query . " WHERE " . $where; |
| 102 | + if ( preg_match( '/[)\s]WHERE[\s(]/is', $this->query ) ) { |
| 103 | + $sql = $this->query . " AND " . $where; |
| 104 | + } else { |
| 105 | + $sql = $this->query . " WHERE " . $where; |
| 106 | + } |
85 | 107 | |
86 | | - if ( $this->querySuffix ) $sql = $sql . ' ' . $this->querySuffix; |
87 | 108 | |
| 109 | + if ( $this->querySuffix ) { |
| 110 | + $sql = $sql . ' ' . $this->querySuffix; |
| 111 | + } |
| 112 | + |
88 | 113 | return $sql; |
89 | 114 | } |
90 | 115 | |
— | — | @@ -93,7 +118,9 @@ |
94 | 119 | $sql = $this->getQuery( $field, $value, $db ); |
95 | 120 | |
96 | 121 | $rs = $db->query( $sql, "DBDataTransclusionSource(" . $this->getName() . ")::fetchRecord" ); |
97 | | - if ( !$rs ) return false; |
| 122 | + if ( !$rs ) { |
| 123 | + return false; |
| 124 | + } |
98 | 125 | |
99 | 126 | $rec = $db->fetchRow( $rs ); |
100 | 127 | |