Completed
Push — master ( b59e84...23e09f )
by mw
08:47
created

doPostProcessParserFunctionCallResult()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 8
cts 9
cp 0.8889
rs 9.7
c 0
b 0
f 0
cc 4
nc 6
nop 1
crap 4.0218
1
<?php
2
3
namespace SMW\Scribunto;
4
5
use Scribunto_LuaLibraryBase;
6
use SMW\DIProperty;
7
use SMW\ApplicationFactory;
8
use SMWQueryResult as QueryResult;
9
use SMWOutputs;
10
11
/**
12
 * @license GNU GPL v2+
13
 * @since 1.0
14
 *
15
 * @author mwjames
16
 */
17
class ScribuntoLuaLibrary extends Scribunto_LuaLibraryBase {
18
19
	/**
20
	 * @var LibraryFactory
21
	 */
22
	private $libraryFactory;
23
24
	/**
25
	 * This is the name of the key for error messages
26
	 *
27
	 * @var string
28
	 * @since 1.0
29
	 */
30
	const SMW_ERROR_FIELD = 'error';
31
32
	/**
33
	 * @since 1.0
34
	 */
35 49
	public function register() {
36
37
		$lib = [
38 49
			'ask'             => [ $this, 'ask' ],
39 49
			'getPropertyType' => [ $this, 'getPropertyType' ],
40 49
			'getQueryResult'  => [ $this, 'getQueryResult' ],
41 49
			'info'            => [ $this, 'info' ],
42 49
			'set'             => [ $this, 'set' ],
43 49
			'subobject'       => [ $this, 'subobject' ],
44
		];
45
46 49
		$this->getEngine()->registerInterface( __DIR__ . '/' . 'mw.smw.lua', $lib, [] );
47 49
	}
48
49
	/**
50
	 * This mirrors the functionality of the parser function #ask and makes it
51
	 * available in lua.
52
	 *
53
	 * @since 1.0
54
	 *
55
	 * @param string|array $arguments parameters passed from lua, string or array depending on call
56
	 *
57
	 * @return array    array( null ) or array[]
58
	 */
59 10
	public function ask( $arguments = null ) {
60
61 10
		$queryResult = $this->getLibraryFactory()->newQueryResultFrom(
62 10
			$this->processLuaArguments( $arguments )
63
		);
64
65 10
		if ( !$this->isAQueryResult( $queryResult ) ) {
66 1
			return [ $queryResult ];
67
		}
68
69 9
		$luaResultProcessor = $this->getLibraryFactory()->newLuaAskResultProcessor(
70 9
			$queryResult
71
		);
72
73 9
		$result = $luaResultProcessor->getProcessedResult();
74
75 9
		return [ $this->convertArrayToLuaTable( $result ) ];
76
	}
77
78
	/**
79
	 * Returns property type
80
	 *
81
	 * @since 1.0
82
	 *
83
	 * @param string $propertyName
84
	 *
85
	 * @return array
86
	 */
87 5
	public function getPropertyType( $propertyName = null ) {
88
89 5
		$this->checkType( 'getPropertyType', 1, $propertyName, 'string' );
90 5
		$propertyName = trim( $propertyName );
91
92 5
		if ( $propertyName === '' ) {
93 3
			return [ null ];
94
		}
95
96 3
		$property = DIProperty::newFromUserLabel( $propertyName );
97
98 3
		if ( $property === null ) {
99
			return [ null ];
100
		}
101
102 3
		return [ $property->findPropertyTypeID() ];
0 ignored issues
show
Deprecated Code introduced by
The method SMW\DIProperty::findPropertyTypeId() has been deprecated with message: since 3.0, use DIProperty::findPropertyValueType

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
103
	}
104
105
	/**
106
	 * Returns query results in for of the standard API return format
107
	 *
108
	 * @since 1.0
109
	 *
110
	 * @param string|array $arguments
111
	 *
112
	 * @return array
113
	 */
114 8
	public function getQueryResult( $arguments = null ) {
115
116 8
		$queryResult = $this->getLibraryFactory()->newQueryResultFrom(
117 8
			$this->processLuaArguments( $arguments )
118
		);
119
120 8
		if ( !$this->isAQueryResult( $queryResult ) ) {
121 1
			return [ $queryResult ];
122
		}
123
124 7
		$result = $queryResult->toArray();
125
126 7
		if( !empty( $result["results"] ) ) {
127
			// as of now, "results" has page names as keys. lua is not very good, keeping non-number keys in order
128
			// so replace string keys with the corresponding number, starting with 0.
129 3
		    $result["results"] = array_combine( range( 0, count( $result["results"] ) - 1 ), array_values( $result["results"] ) );
130
		}
131
132 7
		return [ $this->convertArrayToLuaTable( $result ) ];
133
	}
134
135
	/**
136
	 * This mirrors the functionality of the parser function #info and makes it
137
	 * available to lua.
138
	 *
139
	 * @since 1.0
140
	 *
141
	 * @param string $text text to show inside the info popup
142
	 * @param string $icon identifier for the icon to use
143
	 *
144
	 * @return string[]
145
	 */
146 7
	public function info( $text, $icon = 'info' ) {
147
148
		// do some parameter processing
149 7
		if ( ! trim( $text ) || ! is_string( $text ) ) {
150
			// no info-text present, or wrong type. abort
151 3
			return null;
152
		}
153
154
		// check if icon is set and valid
155 5
		if ( !is_string( $icon ) || !in_array( $icon, [ 'note', 'warning' ] ) ) {
156 5
			$icon = 'info';
157
		}
158
159
		// the actual info message is easy to create:
160 5
		$result = smwfEncodeMessages(
161 5
			[ $text ],
162 5
			$icon,
163 5
			' <!--br-->',
164 5
			false // No escaping.
165
		);
166
167
		// to have all necessary data committed to output, use SMWOutputs::commitToParser()
168 5
		SMWOutputs::commitToParser(
169 5
			$this->getEngine()->getParser()
170
		);
171
172 5
		return [ $this->doPostProcessParserFunctionCallResult( $result ) ];
173
	}
174
175
	/**
176
	 * This mirrors the functionality of the parser function #set and makes it
177
	 * available in lua.
178
	 *
179
	 * @since 1.0
180
	 *
181
	 * @param string|array $arguments arguments passed from lua, string or array depending on call
182
	 *
183
	 * @return null|array|array[]
184
	 */
185 20
	public function set( $arguments ) {
186
187 20
		$arguments = $this->processLuaArguments( $arguments );
188
189 20
		$setParserFunction = $this->getLibraryFactory()->newSetParserFunction(
190 20
			$this->getEngine()->getParser()
191
		);
192
193 20
		$parserFunctionCallResult = $setParserFunction->parse(
194 20
			$this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
195
		);
196
197
		// get usable result
198 20
		$result = $this->doPostProcessParserFunctionCallResult(
199 20
			$parserFunctionCallResult
200
		);
201
202 20
		if ( strlen( $result ) ) {
203
			// if result is a non empty string, assume an error message
204 3
			return [ [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] ];
205
		}
206
207
		// on success, return true
208 18
		return [ 1 => true ];
209
	}
210
211
	/**
212
	 * This mirrors the functionality of the parser function #subobject and
213
	 * makes it available to lua.
214
	 *
215
	 * @param string|array $arguments arguments passed from lua, string or array depending on call
216
	 * @param string $subobjectId if you need to manually assign an id, do this here
217
	 *
218
	 * @return null|array|array[]
219
	 */
220 23
	public function subobject( $arguments, $subobjectId = null ) {
221
222 23
		$arguments = $this->processLuaArguments( $arguments );
223
224
		// parameters[0] would be the subobject id, so unshift
225 23
		array_unshift( $arguments, null );
226
227
		// if subobject id was set, put it on position 0
228 23
		if ( !is_null( $subobjectId ) && $subobjectId ) {
229
			// user deliberately set an id for this subobject
230 11
			$arguments[0] = $subobjectId;
231
232
			// we need to ksort, otherwise ParameterProcessorFactory doesn't
233
			// recognize the id
234 11
			ksort( $arguments );
235
		}
236
237
		// prepare subobjectParserFunction object
238 23
		$subobjectParserFunction = $this->getLibraryFactory()->newSubobjectParserFunction(
239 23
			$this->getEngine()->getParser()
240
		);
241
242 23
		$parserFunctionCallResult = $subobjectParserFunction->parse(
243 23
			 $this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
244
		);
245
246 23
		if ( strlen( $result = $this->doPostProcessParserFunctionCallResult( $parserFunctionCallResult ) ) ) {
247
			// if result a non empty string, assume an error message
248 4
			return [ [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] ];
249
		}
250
251
		// on success, return true
252 19
		return [ 1 => true ];
253
	}
254
255
	/**
256
	 * This takes an array and converts it so, that the result is a viable lua table.
257
	 * I.e. the resulting table has its numerical indices start with 1
258
	 * If `$ar` is not an array, it is simply returned
259
	 * @param mixed $ar
260
	 * @return mixed array
261
	 */
262 15
	private function convertArrayToLuaTable( $ar ) {
263
264 15
		if ( is_array( $ar) ) {
265 10
			foreach ( $ar as $key => $value ) {
266 10
				$ar[$key] = $this->convertArrayToLuaTable( $value );
267
			}
268 10
			array_unshift( $ar, '' );
269 10
			unset( $ar[0] );
270
		}
271 15
		return $ar;
272
	}
273
274
	/**
275
	 * Takes a result returned from a parser function call and prepares it to be
276
	 * used as parsed string.
277
	 *
278
	 * @since 1.0
279
	 *
280
	 * @param string|array $parserFunctionResult
281
	 *
282
	 * @return string
283
	 */
284 48
	private function doPostProcessParserFunctionCallResult( $parserFunctionResult ) {
285
286
		// parser function call can return string or array
287 48
		if ( is_array( $parserFunctionResult ) ) {
288 20
			$result = $parserFunctionResult[0];
289 20
			$noParse = isset( $parserFunctionResult['noparse'] ) ? $parserFunctionResult['noparse'] : true;
290
		} else {
291 28
			$result = $parserFunctionResult;
292 28
			$noParse = true;
293
		}
294
295 48
		if ( !$noParse ) {
296
			$result = $this->getEngine()->getParser()->recursiveTagParseFully( $result );
297
		}
298
299 48
		return trim( $result );
300
	}
301
302
	/**
303
	 * Returns the LibraryFactory singleton (and creates it first, if not already present)
304
	 *
305
	 * @since 1.0
306
	 *
307
	 * @return LibraryFactory
308
	 */
309 59
	private function getLibraryFactory() {
310
311 59
		if ( $this->libraryFactory !== null ) {
312 53
			return $this->libraryFactory;
313
		}
314
315 59
		$this->libraryFactory = new LibraryFactory(
316 59
			ApplicationFactory::getInstance()->getStore()
317
		);
318
319 59
		return $this->libraryFactory;
320
	}
321
322
	/**
323
	 * Tests, if supplied parameter `$queryResult` is a valid {@see QueryResult}
324
	 *
325
	 * @since 1.0
326
	 *
327
	 * @param mixed $queryResult
328
	 *
329
	 * @return bool
330
	 */
331 16
	private function isAQueryResult( $queryResult ) {
332 16
		return is_a( $queryResult, QueryResult::class );
333
	}
334
335
	/**
336
	 * Takes the $arguments passed from lua and pre-processes them: make sure,
337
	 * we have a sequence array (not associative)
338
	 *
339
	 * @since 1.0
340
	 *
341
	 * @param string|array $arguments
342
	 *
343
	 * @return array
344
	 */
345 59
	private function processLuaArguments( $arguments ) {
346
347
		// make sure, we have an array of parameters
348 59
		if ( !is_array( $arguments ) ) {
349 21
			$arguments = preg_split( "/(?<=[^\|])\|(?=[^\|])/", $arguments );
350
		}
351
352
		// if $arguments were supplied as key => value pair (aka associative array),
353
		// we rectify this here
354 59
		$processedArguments = [];
355 59
		foreach ( $arguments as $key => $value ) {
356 55
			if ( is_array( $value ) ) {
357
				// user supplied data in form property => [ 'value1', 'value2' ]
358 2
				foreach ( $value as $item ) {
359 2
					$processedArguments[] = $key . '=' . $item;
360
				}
361
			} else {
362 53
				if ( !is_int($key) && !preg_match('/^[0-9]+$/', $key) ) {
363 22
					$value = (string)$key . '=' . (string)$value;
364
				}
365 55
				$processedArguments[] = $value;
366
			}
367
		}
368
369 59
		return $processedArguments;
370
	}
371
372
}
373