Completed
Push — master ( 48c1e9...d73f9a )
by mw
20:09
created

ScribuntoLuaLibrary::convertArrayToLuaTable()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 2
nop 1
dl 0
loc 11
ccs 4
cts 4
cp 1
crap 3
rs 9.4285
c 0
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 43
	public function register() {
36
37
		$lib = array(
38 43
			'ask'             => array( $this, 'ask' ),
39 43
			'getPropertyType' => array( $this, 'getPropertyType' ),
40 43
			'getQueryResult'  => array( $this, 'getQueryResult' ),
41 43
			'info'            => array( $this, 'info' ),
42 43
			'set'             => array( $this, 'set' ),
43 43
			'subobject'       => array( $this, 'subobject' ),
44 43
		);
45
46 43
		$this->getEngine()->registerInterface( __DIR__ . '/' . 'mw.smw.lua', $lib, array() );
47 43
	}
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 2
	}
77 2
78
	/**
79 8
	 * Returns property type
80
	 *
81
	 * @since 1.0
82
	 *
83
	 * @param string $propertyName
84
	 *
85
	 * @return array
86
	 */
87
	public function getPropertyType( $propertyName = null ) {
88
89
		$this->checkType( 'getPropertyType', 1, $propertyName, 'string' );
90
		$propertyName = trim( $propertyName );
91 5
92
		if ( $propertyName === '' ) {
93 5
			return array( null );
94 5
		}
95
96 5
		$property = DIProperty::newFromUserLabel( $propertyName );
97 3
98
		if ( $property === null ) {
99
			return array( null );
100 3
		}
101
102 3
		return array( $property->findPropertyTypeID() );
103
	}
104
105
	/**
106 3
	 * 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
	public function getQueryResult( $arguments = null ) {
115
116
		$queryResult = $this->getLibraryFactory()->newQueryResultFrom(
117
			$this->processLuaArguments( $arguments )
118 7
		);
119
120 7
		if ( !$this->isAQueryResult( $queryResult ) ) {
121 7
			return array( $queryResult );
122 7
		}
123
124 7
		$result = $queryResult->toArray();
125 1
126
		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 6
			// so replace string keys with the corresponding number, starting with 0.
129
		    $result["results"] = array_combine( range( 0, count( $result["results"] ) - 1 ), array_values( $result["results"] ) );
130 6
		}
131 2
132 2
		return array( $this->convertArrayToLuaTable( $result ) );
133
	}
134 7
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
	public function info( $text, $icon = 'info' ) {
147
148 6
		// do some parameter processing
149
		if ( ! trim( $text ) || ! is_string( $text ) ) {
150
			// no info-text present, or wrong type. abort
151 6
			return null;
152
		}
153 3
154
		// check if icon is set and valid
155
		if ( !is_string( $icon ) || !in_array( $icon, [ 'note', 'warning' ] ) ) {
156
			$icon = 'info';
157 4
		}
158 4
159 4
		// the actual info message is easy to create:
160
		$result = smwfEncodeMessages(
161
			array( $text ),
162 4
			$icon,
163 4
			' <!--br-->',
164 4
			false // No escaping.
165 4
		);
166
167 4
		// to have all necessary data committed to output, use SMWOutputs::commitToParser()
168
		SMWOutputs::commitToParser(
169
			$this->getEngine()->getParser()
170 4
		);
171 4
172 4
		return array( $this->doPostProcessParserFunctionCallResult( $result ) );
173
	}
174 4
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
	public function set( $arguments ) {
186
187 18
		$arguments = $this->processLuaArguments( $arguments );
188
189 18
		$setParserFunction = $this->getLibraryFactory()->newSetParserFunction(
190
			$this->getEngine()->getParser()
191 18
		);
192 18
193 18
		$parserFunctionCallResult = $setParserFunction->parse(
194
			$this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
195 18
		);
196 18
197 18
		// get usable result
198
		$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 18
			return array( [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] );
205
		}
206 3
207
		// on success, return true
208
		return array( 1 => true );
209
	}
210 16
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
	public function subobject( $arguments, $subobjectId = null ) {
221
222 21
		$arguments = $this->processLuaArguments( $arguments );
223
224 21
		// parameters[0] would be the subobject id, so unshift
225
		array_unshift( $arguments, null );
226
227 21
		// if subobject id was set, put it on position 0
228
		if ( !is_null( $subobjectId ) && $subobjectId ) {
229
			// user deliberately set an id for this subobject
230 21
			$arguments[0] = $subobjectId;
231
232 10
			// we need to ksort, otherwise ParameterProcessorFactory doesn't
233
			// recognize the id
234
			ksort( $arguments );
235
		}
236 10
237 10
		// prepare subobjectParserFunction object
238
		$subobjectParserFunction = $this->getLibraryFactory()->newSubobjectParserFunction(
239
			$this->getEngine()->getParser()
240 21
		);
241 21
242 21
		$parserFunctionCallResult = $subobjectParserFunction->parse(
243
			 $this->getLibraryFactory()->newParserParameterProcessorFrom( $arguments )
244 21
		);
245 21
246 21
		if ( strlen( $result = $this->doPostProcessParserFunctionCallResult( $parserFunctionCallResult ) ) ) {
247
			// if result a non empty string, assume an error message
248 21
			return array( [ 1 => false, self::SMW_ERROR_FIELD => preg_replace( '/<[^>]+>/', '', $result ) ] );
249
		}
250 4
251
		// on success, return true
252
		return array( 1 => true );
253
	}
254 17
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
	private function convertArrayToLuaTable( $ar ) {
263
264
		if ( is_array( $ar) ) {
265
			foreach ( $ar as $key => $value ) {
266
				$ar[$key] = $this->convertArrayToLuaTable( $value );
267 43
			}
268
			array_unshift( $ar, '' );
269
			unset( $ar[0] );
270 43
		}
271 18
		return $ar;
272 18
	}
273 18
274 25
	/**
275 25
	 * Takes a result returned from a parser function call and prepares it to be
276
	 * used as parsed string.
277
	 *
278 43
	 * @since 1.0
279
	 *
280
	 * @param string|array $parserFunctionResult
281
	 *
282 43
	 * @return string
283
	 */
284
	private function doPostProcessParserFunctionCallResult( $parserFunctionResult ) {
285
286
		// parser function call can return string or array
287
		if ( is_array( $parserFunctionResult ) ) {
288
			$result = $parserFunctionResult[0];
289
			$noParse = isset( $parserFunctionResult['noparse'] ) ? $parserFunctionResult['noparse'] : true;
290
		} else {
291
			$result = $parserFunctionResult;
292 54
			$noParse = true;
293
		}
294 54
295 48
		if ( !$noParse ) {
296
			$result = $this->getEngine()->getParser()->recursiveTagParseFully( $result );
297
		}
298 54
299 54
		return trim( $result );
300 54
	}
301
302 54
	/**
303
	 * Returns the LibraryFactory singleton (and creates it first, if not already present)
304
	 *
305
	 * @since 1.0
306
	 *
307
	 * @return LibraryFactory
308
	 */
309
	private function getLibraryFactory() {
310
311
		if ( $this->libraryFactory !== null ) {
312
			return $this->libraryFactory;
313
		}
314 15
315 15
		$this->libraryFactory = new LibraryFactory(
316
			ApplicationFactory::getInstance()->getStore()
317
		);
318
319
		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 54
	 *
329
	 * @return bool
330
	 */
331 54
	private function isAQueryResult( $queryResult ) {
332 21
		return is_a( $queryResult, QueryResult::class );
333 21
	}
334
335
	/**
336
	 * Takes the $arguments passed from lua and pre-processes them: make sure,
337 54
	 * we have a sequence array (not associative)
338 54
	 *
339 50
	 * @since 1.0
340 19
	 *
341 19
	 * @param string|array $arguments
342 50
	 *
343 54
	 * @return array
344
	 */
345 54
	private function processLuaArguments( $arguments ) {
346
347
		// make sure, we have an array of parameters
348
		if ( !is_array( $arguments ) ) {
349
			$arguments = preg_split( "/(?<=[^\|])\|(?=[^\|])/", $arguments );
350
		}
351
352
		// if $arguments were supplied as key => value pair (aka associative array),
353
		// we rectify this here
354
		$processedArguments = array();
355
		foreach ( $arguments as $key => $value ) {
356
			if ( !is_int( $key ) && !preg_match( '/[0-9]+/', $key ) ) {
357
				$value = (string) $key . '=' . (string) $value;
358
			}
359
			$processedArguments[] = $value;
360
		}
361
362
		return $processedArguments;
363
	}
364
365
}
366