summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php336
1 files changed, 336 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php b/www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php
new file mode 100644
index 00000000..a6866225
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/src/ParserParameterProcessor.php
@@ -0,0 +1,336 @@
+<?php
+
+namespace SMW;
+
+use SMW\Utils\ErrorCodeFormatter;
+
+/**
+ * @license GNU GPL v2+
+ * @since 1.9
+ *
+ * @author mwjames
+ */
+class ParserParameterProcessor {
+
+ /**
+ * @var string
+ */
+ private $defaultSeparator = ',';
+
+ /**
+ * @var array
+ */
+ private $rawParameters;
+
+ /**
+ * @var array
+ */
+ private $parameters;
+
+ /**
+ * @var null
+ */
+ private $first = null;
+
+ /**
+ * @var array
+ */
+ private $errors = [];
+
+ /**
+ * @since 1.9
+ *
+ * @param array $rawParameters
+ */
+ public function __construct( array $rawParameters = [] ) {
+ $this->rawParameters = $rawParameters;
+ $this->parameters = $this->doMap( $rawParameters );
+ }
+
+ /**
+ * Returns collected errors
+ *
+ * @since 1.9
+ *
+ * @return array
+ */
+ public function getErrors() {
+ return $this->errors;
+ }
+
+ /**
+ * Adds an error
+ *
+ * @since 1.9
+ *
+ * @param mixed $error
+ */
+ public function addError( $error ) {
+ $this->errors = array_merge( (array)$error === $error ? $error : [ $error ], $this->errors );
+ }
+
+ /**
+ * @deprecated since 2.3, use ParserParameterProcessor::getFirstParameter
+ */
+ public function getFirst() {
+ return $this->getFirstParameter();
+ }
+
+ /**
+ * @since 2.3
+ *
+ * @return string
+ */
+ public function getFirstParameter() {
+ return $this->first;
+ }
+
+ /**
+ * Returns raw parameters
+ *
+ * @since 1.9
+ *
+ * @return string
+ */
+ public function getRaw() {
+ return $this->rawParameters;
+ }
+
+ /**
+ * Returns remapped parameters
+ *
+ * @since 1.9
+ *
+ * @return array
+ */
+ public function toArray() {
+ return $this->parameters;
+ }
+
+ /**
+ * @since 2.3
+ *
+ * @param string $key
+ *
+ * @return boolean
+ */
+ public function hasParameter( $key ) {
+ return isset( $this->parameters[$key] ) || array_key_exists( $key, $this->parameters );
+ }
+
+ /**
+ * @since 2.5
+ *
+ * @param string $key
+ */
+ public function removeParameterByKey( $key ) {
+ unset( $this->parameters[$key] );
+ }
+
+ /**
+ * @deprecated since 2.5, use ParserParameterProcessor::getParameterValuesByKey
+ * @since 2.3
+ *
+ * @return array
+ */
+ public function getParameterValuesFor( $key ) {
+ return $this->getParameterValuesByKey( $key );
+ }
+
+ /**
+ * @since 2.5
+ *
+ * @param string $key
+ *
+ * @return array
+ */
+ public function getParameterValuesByKey( $key ) {
+
+ if ( $this->hasParameter( $key ) ) {
+ return $this->parameters[$key];
+ }
+
+ return [];
+ }
+
+ /**
+ * @since 1.9
+ *
+ * @param array $parameters
+ */
+ public function setParameters( array $parameters ) {
+ $this->parameters = $parameters;
+ }
+
+ /**
+ * @since 1.9
+ *
+ * @param string $key
+ * @param string $value
+ */
+ public function addParameter( $key, $value ) {
+ if( $key !== '' && $value !== '' ) {
+ $this->parameters[$key][] = $value;
+ }
+ }
+
+ /**
+ * @since 2.3
+ *
+ * @param string $key
+ * @param array $values
+ */
+ public function setParameter( $key, array $values ) {
+ if ( $key !== '' && $values !== [] ) {
+ $this->parameters[$key] = $values;
+ }
+ }
+
+ /**
+ * @since 3.0
+ *
+ * @param array $parameters
+ * @param boolean $associative
+ */
+ public static function sort( array &$parameters, $associative = true ) {
+
+ // Associative vs. simple index array sort
+ if ( $associative ) {
+ ksort( $parameters );
+ } else {
+ sort( $parameters );
+ }
+
+ foreach ( $parameters as $key => &$value ) {
+ if ( is_array( $value ) ) {
+ self::sort( $value, is_int( $key ) );
+ }
+ }
+ }
+
+ /**
+ * Map raw parameters array into an 2n-array for simplified
+ * via [key] => [value1, value2]
+ */
+ private function doMap( array $params ) {
+ $results = [];
+ $previousProperty = null;
+
+ while ( key( $params ) !== null ) {
+
+ $pipe = false;
+ $values = [];
+
+ // Only strings are allowed for processing
+ if( !is_string( current ( $params ) ) ) {
+ next( $params );
+ }
+
+ // Get the current element and divide it into parts
+ $currentElement = explode( '=', trim( current ( $params ) ), 2 );
+
+ // Looking to the next element for comparison
+ $separator = $this->lookAheadOnNextElement( $params, $pipe );
+
+ // First named parameter
+ if ( count( $currentElement ) == 1 && $previousProperty === null ) {
+ $this->first = str_replace( ' ', '_', $currentElement[0] );
+ }
+
+ // Here we allow to support assignments of type |Has property=Test1|Test2|Test3
+ // for multiple values with the same preceding property
+ if ( count( $currentElement ) == 1 && $previousProperty !== null ) {
+ $currentElement[1] = $currentElement[0];
+ $currentElement[0] = $previousProperty;
+ } else {
+ $previousProperty = $currentElement[0];
+ }
+
+ // Reassign values
+ if ( $separator !== '' && isset( $currentElement[1] ) ) {
+ $values = explode( $separator, $currentElement[1] );
+ } elseif ( isset( $currentElement[1] ) ) {
+ $values[] = $currentElement[1];
+ }
+
+ // Remap properties and values to output a simple array
+ foreach ( $values as $value ) {
+ if ( $value !== '' ) {
+ $results[$currentElement[0]][] = trim( $value );
+ }
+ }
+
+ // +pipe indicates that elements are expected to be concatenated
+ // with a | that was removed during a #parserFunction invocation
+ if ( $pipe ) {
+ $results[$currentElement[0]] = [ implode( '|', $results[$currentElement[0]] ) ];
+ }
+ }
+
+ return $this->parseFromJson( $results );
+ }
+
+ private function lookAheadOnNextElement( &$params, &$pipe ) {
+
+ $separator = '';
+
+ if( !next( $params ) ) {
+ return $separator;
+ }
+
+ $nextElement = explode( '=', trim( current( $params ) ), 2 );
+
+ if ( $nextElement !== [] ) {
+ // This allows assignments of type |Has property=Test1,Test2|+sep=,
+ // as a means to support multiple value declaration
+ if ( substr( $nextElement[0], - 5 ) === '+sep' ) {
+ $separator = isset( $nextElement[1] ) ? $nextElement[1] !== '' ? $nextElement[1] : $this->defaultSeparator : $this->defaultSeparator;
+ next( $params );
+ }
+ }
+
+ if ( current( $params ) === '+pipe' ) {
+ $pipe = true;
+ next( $params );
+ }
+
+ return $separator;
+ }
+
+ private function parseFromJson( $results ) {
+
+ if ( !isset( $results['@json'] ) || !isset( $results['@json'][0] ) ) {
+ return $results;
+ }
+
+ // Restrict the depth to avoid resolving recursive assignment
+ // that can not be handled beyond the 2:n
+ $depth = 3;
+ $params = json_decode( $results['@json'][0], true, $depth );
+
+ if ( $params === null || json_last_error() !== JSON_ERROR_NONE ) {
+ $this->addError( Message::encode(
+ [
+ 'smw-parser-invalid-json-format',
+ ErrorCodeFormatter::getStringFromJsonErrorCode( json_last_error() )
+ ]
+ ) );
+ return $results;
+ }
+
+ array_walk( $params, function( &$value, $key ) {
+
+ if ( $value === '' ) {
+ $value = [];
+ }
+
+ if ( !is_array( $value ) ) {
+ $value = [ $value ];
+ }
+ } );
+
+ unset( $results['@json'] );
+ return array_merge( $results, $params );
+ }
+
+}