Completed
Push — master ( e00767...142210 )
by
unknown
09:09
created

formats/array/SRF_Array.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Query format for arrays with features for Extensions 'Arrays' and 'HashTables'
4
 * @file
5
 * @ingroup SemanticResultFormats
6
 * @author Daniel Werner < [email protected] >
7
 * 
8
 * Doesn't require 'Arrays' nor 'HashTables' exytensions but has additional features
9
 * ('name' parameter in either result format) if they are available.
10
 * 
11
 * Arrays 2.0+ and HashTables 1.0+ are recommended but not necessary.
12
 */
13
14
/**
15
 * Array format
16
 */
17
class SRFArray extends SMWResultPrinter {
18
	
19
	protected static $mDefaultSeps = [];
20
	protected $mSep;
21
	protected $mPropSep;
22
	protected $mManySep;
23
	protected $mRecordSep;
24
	protected $mHeaderSep;
25
	protected $mArrayName = null;
26
	protected $mShowPageTitles;
27
	
28
	protected $mHideRecordGaps;
29
	protected $mHidePropertyGaps;
30
	
31
	/**
32
	 * @var Boolean true if 'mainlabel' parameter is set to '-'
33
	 */
34
	protected $mMainLabelHack = false;
35
	
36 2
	public function __construct( $format, $inline = true, $useValidator = true ) {
37 2
		parent::__construct( $format, $inline, $useValidator );
38
		//overwrite parent default behavior for linking:
39 2
		$this->mLinkFirst = false;
40 2
		$this->mLinkOthers = false;
41 2
	}
42
43
	public function getQueryMode($context) {
44
		return SMWQuery::MODE_INSTANCES;
45
	}
46
47
	public function getName() {
48
		// Give grep a chance to find the usages:
49
		// srf_printername_array, srf_printername_hash
50
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
51
	}
52
	
53
	/*
54
	// By overwriting this function, we disable default searchlabel handling?
55
	public function getResult( SMWQueryResult $results, array $params, $outputmode ) {
56
		$this->handleParameters( $params, $outputmode );
57
		return $this->getResultText( $results, $outputmode );
58
	}
59
	*/
60
61
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
62
		/*
63
		 * @todo
64
		 * labels of requested properties could define default values. Seems not possible at the moment because
65
		 * SMWPrintRequest::getLable() always returns the property name even if no specific label is defined.
66
		 */
67
		 
68
		$perPage_items = [];
69
		
70
		//for each page:
71
		while( $row = $res->getNext() ) {
72
			$perProperty_items = [];
73
			
74
			/**
75
			 * first field is always the page title, except, mainlabel is set to '-'
76
			 * @todo Is there some other way to check the data value directly for being the
77
			 *        page title or not? SMWs behavior could change on mainlabel handling...
78
			 */
79
			$isPageTitle = !$this->mMainLabelHack;
80
			
81
			//for each property on that page:
82
			foreach( $row as $field ) { // $row is array(), $field of type SMWResultArray
83
				$manyValue_items = [];
84
				$isMissingProperty = false;
85
				
86
				$manyValues = $field->getContent();
87
				
88
				//If property is not set (has no value) on a page:
89
				if( empty( $manyValues ) ) {
90
					$delivery = $this->deliverMissingProperty( $field );
91
					$manyValue_items = $this->fillDeliveryArray( $manyValue_items, $delivery );
92
					$isMissingProperty = true;
93
				} else
94
				//otherwise collect property value (potentially many values):
95
				while( $obj = $field->getNextDataValue() ) {
96
					
97
					$value_items = [];					
98
					$isRecord = false;
99
					
100
					// handle page Title:
101
					if( $isPageTitle ) {						
102
						if( ! $this->mShowPageTitles ) {
103
							$isPageTitle = false;
104
							continue 2; //next property
105
						}						
106
						$value_items = $this->fillDeliveryArray( $value_items, $this->deliverPageTitle( $obj, $this->mLinkFirst ) );
107
					}
108
					// handle record values:
109
					elseif( $obj instanceof SMWRecordValue ) {												
110
						$recordItems = $obj->getDataItems();
111
						// walk all single values of the record set:
112
						foreach( $recordItems as $dataItem ) {							
113
							$recordField = $dataItem !== null ? SMWDataValueFactory::newDataItemValue( $dataItem, null ) : null;
114
							$value_items = $this->fillDeliveryArray( $value_items, $this->deliverRecordField( $recordField, $this->mLinkOthers ) );
115
						}
116
						$isRecord = true;
117
					}
118
					// handle normal data values:
119
					else {						
120
						$value_items = $this->fillDeliveryArray( $value_items, $this->deliverSingleValue( $obj, $this->mLinkOthers ) );
121
					}
122
					$delivery = $this->deliverSingleManyValuesData( $value_items, $isRecord, $isPageTitle );
123
					$manyValue_items = $this->fillDeliveryArray( $manyValue_items, $delivery );
124
				} // foreach...
125
				$delivery = $this->deliverPropertiesManyValues( $manyValue_items, $isMissingProperty, $isPageTitle, $field );
126
				$perProperty_items = $this->fillDeliveryArray( $perProperty_items, $delivery );
127
				$isPageTitle = false; // next one could be record or normal value
128
			} // foreach...			
129
			$delivery = $this->deliverPageProperties( $perProperty_items );
130
			$perPage_items = $this->fillDeliveryArray( $perPage_items, $delivery );
131
		} // while...
132
133
		$output = $this->deliverQueryResultPages( $perPage_items );
134
		
135
		return $output;
136
	}
137
	
138
	protected function fillDeliveryArray( $array = [], $value = null ) {
139
		if( ! is_null( $value ) ) { //don't create any empty entries
140
			$array[] = $value;
141
		}
142
		return $array;
143
	}
144
145
	protected function deliverPageTitle( $value, $link = false ) {
146
		return $this->deliverSingleValue( $value, $link );
147
	}
148
	protected function deliverRecordField( $value, $link = false ) {
149
		if( $value !== null ) // contains value
150
			return $this->deliverSingleValue( $value, $link );
151
		elseif( $this->mHideRecordGaps )
152
			return null; // hide gap
153
		else
154
			return ''; // empty string will make sure that record value separators are generated
155
	}
156
	protected function deliverSingleValue( $value, $link = false ) {
157
		//return trim( $value->getShortWikiText( $link ) );
158
		return trim( Sanitizer::decodeCharReferences( $value->getShortWikiText( $link ) ) ); // decode: better for further processing with array extension
159
	}
160
	// Property not declared on a page:
161
	protected function deliverMissingProperty( SMWResultArray $field ) {
162
		if( $this->mHidePropertyGaps )
163
			return null;
164
		else
165
			return ''; //empty string will make sure that array separator will be generated
166
			/** @ToDo: System for Default values?... **/
167
	}
168
	//represented by an array of record fields or just a single array value:
169
	protected function deliverSingleManyValuesData( $value_items, $containsRecord, $isPageTitle ) {
170
		if( empty( $value_items ) ) //happens when one of the higher functions delivers null
171
			return null;
172
		return implode( $this->mRecordSep, $value_items );
173
	}
174
	protected function deliverPropertiesManyValues( $manyValue_items, $isMissingProperty, $isPageTitle, SMWResultArray $data ) {
175
		if( empty( $manyValue_items ) )
176
			return null;
177
		
178
		$text = implode( $this->mManySep, $manyValue_items );
179
		
180
		// if property names should be displayed and this is not the page titles value:
181
		if(  $this->mShowHeaders != SMW_HEADERS_HIDE && ! $isPageTitle ) {
182
			$linker = $this->mShowHeaders == SMW_HEADERS_PLAIN ? null : $this->mLinker;
183
			$text = $data->getPrintRequest()->getText( SMW_OUTPUT_WIKI, $linker ) . $this->mHeaderSep . $text;
184
		}
185
		return $text;
186
	}
187
	protected function deliverPageProperties( $perProperty_items ) {
188
		if( empty( $perProperty_items ) )
189
			return null;
190
		return implode( $this->mPropSep, $perProperty_items );
191
	}
192
	protected function deliverQueryResultPages( $perPage_items ) {
193
		if( $this->mArrayName !== null ) {
194
			$this->createArray( $perPage_items ); //create Array
195
			return '';
196
		} else {
197
			return implode( $this->mSep, $perPage_items );
198
		}
199
	}
200
	
201
	/**
202
	 * Helper function to create a new Array within 'Arrays' extension. Takes care of different versions
203
	 * as well as the old 'ArrayExtension'.
204
	 */
205
	protected function createArray( $array ) {
206
		global $wgArrayExtension;
207
		
208
		$arrayId = $this->mArrayName;
209
		
210
		if( defined( 'ExtArrays::VERSION' ) ) {
211
			// 'Arrays' extension 2+
212
			global $wgParser; /** ToDo: is there a way to get the actual parser which has started the query? */
213
			ExtArrays::get( $wgParser )->createArray( $arrayId, $array );
214
			return true;
215
		}
216
		
217
		// compatbility to 'ArrayExtension' extension before 2.0:
218
		
219
		if( ! isset( $wgArrayExtension ) ) {
220
			//Hash extension is not installed in this wiki
221
			return false;
222
		}
223
		$version = null;		
224
		if( defined( 'ArrayExtension::VERSION' ) ) {
225
			$version = ArrayExtension::VERSION;
226
		} elseif( defined( 'ExtArrayExtension::VERSION' ) ) {
227
			$version = ExtArrayExtension::VERSION;
228
		}
229
		if( $version !== null && version_compare( $version, '1.3.2', '>=' ) ) {
230
			// ArrayExtension 1.3.2+
231
			$wgArrayExtension->createArray( $arrayId, $array );
232
		} else {
233
			// dirty way
234
			$wgArrayExtension->mArrays[ trim( $arrayId ) ] = $array;
235
		}
236
		return true;
237
	}
238
	
239
	protected function initializeCfgValue( $dfltVal, $dfltCacheKey ) {		
240
		$cache = &self::$mDefaultSeps[ $dfltCacheKey ];
241
		if( ! isset( $cache ) ) {
242
			$cache = $this->getCfgSepText( $dfltVal );			
243
			if( $cache === null ) {
244
				// cache can't be initialized, propably function-reference in userconfig
245
				// but format is not used in inline context, use fallback in this case:
246
				global $srfgArraySepTextualFallbacks;
247
				$cache = $srfgArraySepTextualFallbacks[ $dfltCacheKey ];
248
			}
249
		}
250
		return $cache;
251
	}
252
	protected function getCfgSepText( $obj ) {		
253
		if( is_array( $obj ) ) {
254
			// invalid definition:
255
			if( ! array_key_exists( 0, $obj ) )
256
				return null;
257
258
			// check for config-defined arguments to pass to the page before processing it:			
259
			if( array_key_exists( 'args', $obj ) && is_array( $obj['args'] ) )
260
				$params = $obj['args'];
261
			else
262
				$params = []; // no arguments
263
			
264
			// create title of page whose text should be used as separator:
265
			$obj = Title::newFromText( $obj[0], ( array_key_exists( 1, $obj ) ? $obj[1] : NS_MAIN ) );
266
		}
267
		if( $obj instanceof Title ) {
268
			$article = new Article( $obj );
269
		} elseif( $obj instanceof Article ) {
270
			$article = $obj;
271
		} else {
272
			return $obj; //only text
273
		}
274
		
275
		global $wgParser;		
276
		/*
277
		 * Feature to use page value as separator only works if Parser::parse() is running!
278
		 * That's not the case on semantic search special page for example!
279
		 */
280
		// can't use $this->mInline here since SMW 1.6.2 had a bug setting it to false in most cases!		
281
		if( ! isset( $wgParser->mOptions ) ) {
282
		//if( ! $this->mInline ) {
283
			return null;
284
		}
285
		
286
		/*
287
		 * parse page as if it were included like a template. Never use Parser::recursiveTagParse() or similar 
288
		 * for this since it would call hooks we don't want to call and won't return wiki text for inclusion!
289
		 */
290
		$frame = $wgParser->getPreprocessor()->newCustomFrame( $params );
291
		// compatibility for 1.19, getContent() was implemented in 1.21.
292
		// FIXME: Remove when support for MediaWiki 1.19 is dropped
293
		if ( method_exists( $article, 'getContent' ) ) {
294
			$content = $article->getContent( Revision::RAW )->getNativeData();
295
		} else {
296
			$content = $article->getRawText();
297
		}
298
		$text = $wgParser->preprocessToDom( $content, Parser::PTD_FOR_INCLUSION );
299
		$text = trim( $frame->expand( $text ) );
300
		
301
		return $text;
302
	}
303
	
304
	protected function handleParameters( array $params, $outputmode ) {
305
		// does the link parameter:
306
		parent::handleParameters( $params, $outputmode );
307
		
308
		//separators:
309
		$this->mSep       = $params['sep'];
310
		$this->mPropSep   = $params['propsep'];
311
		$this->mManySep   = $params['manysep'];
312
		$this->mRecordSep = $params['recordsep'];
313
		$this->mHeaderSep = $params['headersep'];
314
		
315
		// only use this in inline mode, if text is given. Since SMW 1.6.2 '' is given, so if
316
		// we wouldn't check, we would always end up with an array instead of visible output
317
		if( $params['name'] !== false && ( $this->mInline || trim( $params['name'] ) !== '' ) ) {
318
			$this->mArrayName = trim( $params['name'] );
319
			$this->createArray( [] ); //create empty array in case we get no result so we won't have an undefined array in the end.
320
		}
321
		
322
		// if mainlabel set to '-', this will cause the titles not to appear, so make sure we catch this!
323
		$this->mMainLabelHack = trim( $params['mainlabel'] ) === '-';
324
		
325
		// whether or not to display the page title:
326
		$this->mShowPageTitles = strtolower( $params['titles'] ) != 'hide';
327
		
328
		switch( strtolower( $params['hidegaps'] ) ) {
329
			case 'none':
330
				$this->mHideRecordGaps = false;
331
				$this->mHidePropertyGaps = false;
332
				break;
333
			case 'all':
334
				$this->mHideRecordGaps = true;
335
				$this->mHidePropertyGaps = true;
336
				break;
337
			case 'property': case 'prop': case 'attribute': case 'attr':
338
				$this->mHideRecordGaps = false;
339
				$this->mHidePropertyGaps = true;
340
				break;
341
			case 'record': case 'rec': case 'rcrd': case 'n-ary': case 'nary':
342
				$this->mHideRecordGaps = true;
343
				$this->mHidePropertyGaps = false;
344
				break;
345
		}
346
	}
347
348
	/**
349
	 * @see SMWResultPrinter::getParamDefinitions
350
	 *
351
	 * @since 1.8
352
	 *
353
	 * @param $definitions array of IParamDefinition
354
	 *
355
	 * @return array of IParamDefinition|array
356
	 */
357
	public function getParamDefinitions( array $definitions ) {
0 ignored issues
show
getParamDefinitions uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
358
		$params = parent::getParamDefinitions( $definitions );
359
360
		### adjusted basic SMW params: ###
361
362
		$definitions['limit']->setDefault( $GLOBALS['smwgQMaxInlineLimit'] );
363
		$definitions['link']->setDefault( 'none' );
364
		$definitions['headers']->setDefault( 'hide' );
365
		
366
		### new params: ###
367
		
368
		$params['titles'] = [
369
			'message' => 'srf_paramdesc_pagetitle',
370
			'values' => [ 'show', 'hide' ],
371
			'aliases' => [ 'pagetitle', 'pagetitles' ],
372
			'default' => 'show',
373
		];
374
375
		$params['hidegaps'] = [
376
			'message' => 'srf_paramdesc_hidegaps',
377
			'values' => [ 'none', 'all', 'property', 'record' ],
378
			'default' => 'none',
379
		];
380
381
		$params['name'] = [
382
			'message' => 'srf_paramdesc_arrayname',
383
			'default' => false,
384
			'manipulatedefault' => false,
385
		];
386
387
		// separators (default values are defined in the following globals:)
388
		global $srfgArraySep, $srfgArrayPropSep, $srfgArrayManySep, $srfgArrayRecordSep, $srfgArrayHeaderSep;
389
390
		$params['sep'] = [
391
			'message' => 'smw_paramdesc_sep',
392
			'default' => $this->initializeCfgValue( $srfgArraySep, 'sep' ),
393
		];
394
395
		$params['propsep'] = [
396
			'message' => 'smw_paramdesc_propsep',
397
			'default' => $this->initializeCfgValue( $srfgArrayPropSep, 'propsep' ),
398
		];
399
400
		$params['manysep'] = [
401
			'message' => 'srf_paramdesc_manysep',
402
			'default' => $this->initializeCfgValue( $srfgArrayManySep, 'manysep' ),
403
		];
404
405
		$params['recordsep'] = [
406
			'message' => 'srf_paramdesc_recordsep',
407
			'default' => $this->initializeCfgValue( $srfgArrayRecordSep, 'recordsep' ),
408
			'aliases' => [ 'narysep', 'rcrdsep', 'recsep' ],
409
		];
410
411
		$params['headersep'] = [
412
			'message' => 'srf_paramdesc_headersep',
413
			'default' => $this->initializeCfgValue( $srfgArrayHeaderSep, 'headersep' ),
414
			'aliases' => [ 'narysep', 'rcrdsep', 'recsep' ],
415
		];
416
417
		return $params;
418
	}
419
420
}
421
422
423
424