Completed
Push — master ( d73f9a...cbc1cd )
by mw
23:09 queued 16:04
created

ScribuntoLuaLibrary::getQueryResult()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 3
rs 9.4285
c 3
b 0
f 0
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 45
	public function register() {
36
37
		$lib = array(
38 45
			'ask'             => array( $this, 'ask' ),
39 45
			'getPropertyType' => array( $this, 'getPropertyType' ),
40 45
			'getQueryResult'  => array( $this, 'getQueryResult' ),
41 45
			'info'            => array( $this, 'info' ),
42 45
			'set'             => array( $this, 'set' ),
43 45
			'subobject'       => array( $this, 'subobject' ),
44 45
		);
45
46 45
		$this->getEngine()->registerInterface( __DIR__ . '/' . 'mw.smw.lua', $lib, array() );
47 45
	}
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 9
	public function ask( $arguments = null ) {
60
61 9
		$queryResult = $this->getLibraryFactory()->newQueryResultFrom(
62 9
			$this->processLuaArguments( $arguments )
63 9
		);
64
65 9
		if ( !$this->isAQueryResult( $queryResult ) ) {
66 1
			return array( $queryResult );
67
		}
68
69 8
		$luaResultProcessor = $this->getLibraryFactory()->newLuaAskResultProcessor(
70
			$queryResult
71 8
		);
72
73 8
		$result = $luaResultProcessor->getQueryResultAsTable();
74
75 8
		return array( $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 array( null );
94
		}
95
96 3
		$property = DIProperty::newFromUserLabel( $propertyName );
97
98 3
		if ( $property === null ) {
99
			return array( null );
100
		}
101
102 3
		return array( $property->findPropertyTypeID() );
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 7
	public function getQueryResult( $arguments = null ) {
115
116 7
		$queryResult = $this->getLibraryFactory()->newQueryResultFrom(
117 7
			$this->processLuaArguments( $arguments )
118 7
		);
119
120 7
		if ( !$this->isAQueryResult( $queryResult ) ) {
121 1
			return array( $queryResult );
122
		}
123
124 6
		$result = $queryResult->toArray();
125
126 6
		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 2
		    $result["results"] = array_combine( range( 0, count( $result["results"] ) - 1 ), array_values( $result["results"] ) );
130 2
		}
131
132 6
		return array( $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 5
		}
158
159
		// the actual info message is easy to create:
160 5
		$result = smwfEncodeMessages(
161 5
			array( $text ),
162 5
			$icon,
163 5
			' <!--br-->',
164
			false // No escaping.
165 5
		);
166
167
		// to have all necessary data committed to output, use SMWOutputs::commitToParser()
168 5
		SMWOutputs::commitToParser(
169 5
			$this->getEngine()->getParser()
170 5
		);
171
172 5
		return array( $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 18
	public function set( $arguments ) {
186
187 18
		$arguments = $this->processLuaArguments( $arguments );
188
189 18
		$setParserFunction = $this->getLibraryFactory()->newSetParserFunction(
190 18
			$this->getEngine()->getParser()
191 18
		);
192
193 18
		$parserFunctionCallResult = $setParserFunction->parse(
194 18
			$this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
195 18
		);
196
197
		// get usable result
198 18
		$result = $this->doPostProcessParserFunctionCallResult(
199
			$parserFunctionCallResult
200 18
		);
201
202 18
		if ( strlen( $result ) ) {
203
			// if result is a non empty string, assume an error message
204 3
			return array( [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] );
205
		}
206
207
		// on success, return true
208 16
		return array( 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 22
	public function subobject( $arguments, $subobjectId = null ) {
221
222 22
		$arguments = $this->processLuaArguments( $arguments );
223
224
		// parameters[0] would be the subobject id, so unshift
225 22
		array_unshift( $arguments, null );
226
227
		// if subobject id was set, put it on position 0
228 22
		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 11
		}
236
237
		// prepare subobjectParserFunction object
238 22
		$subobjectParserFunction = $this->getLibraryFactory()->newSubobjectParserFunction(
239 22
			$this->getEngine()->getParser()
240 22
		);
241
242 22
		$parserFunctionCallResult = $subobjectParserFunction->parse(
243 22
			 $this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
244 22
		);
245
246 22
		if ( strlen( $result = $this->doPostProcessParserFunctionCallResult( $parserFunctionCallResult ) ) ) {
247
			// if result a non empty string, assume an error message
248 4
			return array( [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] );
249
		}
250
251
		// on success, return true
252 18
		return array( 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 14
	private function convertArrayToLuaTable( $ar ) {
263
264 14
		if ( is_array( $ar) ) {
265 8
			foreach ( $ar as $key => $value ) {
266 8
				$ar[$key] = $this->convertArrayToLuaTable( $value );
267 8
			}
268 8
			array_unshift( $ar, '' );
269 8
			unset( $ar[0] );
270 8
		}
271 14
		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 45
	private function doPostProcessParserFunctionCallResult( $parserFunctionResult ) {
285
286
		// parser function call can return string or array
287 45
		if ( is_array( $parserFunctionResult ) ) {
288 18
			$result = $parserFunctionResult[0];
289 18
			$noParse = isset( $parserFunctionResult['noparse'] ) ? $parserFunctionResult['noparse'] : true;
290 18
		} else {
291 27
			$result = $parserFunctionResult;
292 27
			$noParse = true;
293
		}
294
295 45
		if ( !$noParse ) {
296
			$result = $this->getEngine()->getParser()->recursiveTagParseFully( $result );
297
		}
298
299 45
		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 55
	private function getLibraryFactory() {
310
311 55
		if ( $this->libraryFactory !== null ) {
312 49
			return $this->libraryFactory;
313
		}
314
315 55
		$this->libraryFactory = new LibraryFactory(
316 55
			ApplicationFactory::getInstance()->getStore()
317 55
		);
318
319 55
		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 15
	private function isAQueryResult( $queryResult ) {
332 15
		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 55
	private function processLuaArguments( $arguments ) {
346
347
		// make sure, we have an array of parameters
348 55
		if ( !is_array( $arguments ) ) {
349 21
			$arguments = preg_split( "/(?<=[^\|])\|(?=[^\|])/", $arguments );
350 21
		}
351
352
		// if $arguments were supplied as key => value pair (aka associative array),
353
		// we rectify this here
354 55
		$processedArguments = array();
355 55
		foreach ( $arguments as $key => $value ) {
356 51
			if ( !is_int( $key ) && !preg_match( '/[0-9]+/', $key ) ) {
357 20
				$value = (string) $key . '=' . (string) $value;
358 20
			}
359 51
			$processedArguments[] = $value;
360 55
		}
361
362 55
		return $processedArguments;
363
	}
364
365
}
366