summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php')
-rw-r--r--www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php663
1 files changed, 663 insertions, 0 deletions
diff --git a/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php b/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php
new file mode 100644
index 00000000..8edc7e17
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php
@@ -0,0 +1,663 @@
+<?php
+/**
+ * Class for handling the parser functions for External Data
+ */
+
+class EDParserFunctions {
+
+ /**
+ * A helper function, called by doGetWebData().
+ */
+ static public function setGlobalValuesArray( $external_values, $filters, $mappings ) {
+ global $edgValues;
+
+ foreach ( $filters as $filter_var => $filter_value ) {
+ // Find the entry of $external_values that matches
+ // the filter variable; if none exists, just ignore
+ // the filter.
+ if ( array_key_exists( $filter_var, $external_values ) ) {
+ if ( is_array( $external_values[$filter_var] ) ) {
+ $column_values = $external_values[$filter_var];
+ foreach ( $column_values as $i => $single_value ) {
+ // if a value doesn't match
+ // the filter value, remove
+ // the value from this row for
+ // all columns
+ if ( trim( $single_value ) != trim( $filter_value ) ) {
+ foreach ( $external_values as $external_var => $external_value ) {
+ unset( $external_values[$external_var][$i] );
+ }
+ }
+ }
+ } else {
+ // if we have only one row of values,
+ // and the filter doesn't match, just
+ // keep the results array blank and
+ // return
+ if ( $external_values[$filter_var] != $filter_value ) {
+ return;
+ }
+ }
+ }
+ }
+ // for each external variable name specified in the function
+ // call, get its value or values (if any exist), and attach it
+ // or them to the local variable name
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $external_values ) ) {
+ if ( is_array( $external_values[$external_var] ) ) {
+ // array_values() restores regular
+ // 1, 2, 3 indexes to array, after unset()
+ // in filtering may have removed some
+ $edgValues[$local_var] = array_values( $external_values[$external_var] );
+ } else {
+ $edgValues[$local_var][] = $external_values[$external_var];
+ }
+ }
+ }
+ }
+
+ /**
+ * Render the #get_web_data parser function.
+ */
+ static function doGetWebData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'url', $args ) ) {
+ $url = $args['url'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'url')->parse() );
+ }
+ $url = str_replace( ' ', '%20', $url ); // do some minor URL-encoding
+ // if the URL isn't allowed (based on a whitelist), exit
+ if ( ! EDUtils::isURLAllowed( $url ) ) {
+ return EDUtils::formatErrorMessage( "URL is not allowed" );
+ }
+
+ if ( array_key_exists( 'format', $args ) ) {
+ $format = strtolower( $args['format'] );
+ } else {
+ $format = '';
+ }
+ if ( $format == 'xml' ) {
+ if ( array_key_exists( 'use xpath', $args ) ) {
+ // Somewhat of a hack - store the fact that
+ // we're using XPath within the format, even
+ // though the format is still XML.
+ $format = 'xml with xpath';
+ }
+ } elseif ( $format == 'csv' || $format == 'csv with header' ) {
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = $args['delimiter'];
+ // Hopefully this solution isn't "too clever".
+ $format = array( $format, $args['delimiter'] );
+ }
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ if ( $format == 'xml with xpath' ) {
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ $mappings = EDUtils::paramToArray( $args['data'], false, true );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( array_key_exists( 'cache seconds', $args) ) {
+ // set cache expire time
+ $cacheExpireTime = $args['cache seconds'];
+ } else {
+ $cacheExpireTime = $edgCacheExpireTime;
+ }
+
+ if ( array_key_exists( 'json offset', $args) ) {
+ $prefixLength = $args['json offset'];
+ } else {
+ $prefixLength = 0;
+ }
+
+ $postData = array_key_exists( 'post data', $args ) ? $args['post data'] : '';
+ $external_values = EDUtils::getDataFromURL( $url, $format, $mappings, $postData, $cacheExpireTime, $prefixLength );
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+ if ( count( $external_values ) == 0 ) {
+ return;
+ }
+
+ if ( array_key_exists( 'filters', $args ) ) {
+ // parse the 'filters' arg
+ $filters = EDUtils::paramToArray( $args['filters'], true, false );
+ } else {
+ $filters = array();
+ }
+
+ self::setGlobalValuesArray( $external_values, $filters, $mappings );
+ }
+
+ /**
+ * Render the #get_file_data parser function.
+ */
+ static function doGetFileData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'file', $args ) ) {
+ $file = $args['file'];
+ } elseif ( array_key_exists( 'directory', $args ) ) {
+ $directory = $args['directory'];
+ if ( array_key_exists( 'file name', $args ) ) {
+ $fileName = $args['file name'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'file name')->parse() );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'file|directory')->parse() );
+ }
+
+ if ( array_key_exists( 'format', $args ) ) {
+ $format = strtolower( $args['format'] );
+ } else {
+ $format = '';
+ }
+ if ( $format == 'xml' ) {
+ if ( array_key_exists( 'use xpath', $args ) ) {
+ // Somewhat of a hack - store the fact that
+ // we're using XPath within the format, even
+ // though the format is still XML.
+ $format = 'xml with xpath';
+ }
+ } elseif ( $format == 'csv' || $format == 'csv with header' ) {
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = $args['delimiter'];
+ // Hopefully this solution isn't "too clever".
+ $format = array( $format, $args['delimiter'] );
+ }
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ if ( $format == 'xml with xpath' ) {
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ $mappings = EDUtils::paramToArray( $args['data'], false, true );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( array_key_exists( 'cache seconds', $args) ) {
+ // set cache expire time
+ $cacheExpireTime = $args['cache seconds'];
+ } else {
+ $cacheExpireTime = $edgCacheExpireTime;
+ }
+
+ if ( isset( $file ) ) {
+ $external_values = EDUtils::getDataFromFile( $file, $format, $mappings );
+ } else {
+ $external_values = EDUtils::getDataFromDirectory( $directory, $fileName, $format, $mappings );
+ }
+
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+ if ( count( $external_values ) == 0 ) {
+ return;
+ }
+
+ if ( array_key_exists( 'filters', $args ) ) {
+ // parse the 'filters' arg
+ $filters = EDUtils::paramToArray( $args['filters'], true, false );
+ } else {
+ $filters = array();
+ }
+
+ self::setGlobalValuesArray( $external_values, $filters, $mappings );
+ }
+ /**
+ * Render the #get_soap_data parser function.
+ */
+ static function doGetSOAPData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'url', $args ) ) {
+ $url = $args['url'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'url')->parse() );
+ }
+ $url = str_replace( ' ', '%20', $url ); // do some minor URL-encoding
+ // if the URL isn't allowed (based on a whitelist), exit
+ if ( ! EDUtils::isURLAllowed( $url ) ) {
+ return EDUtils::formatErrorMessage( "URL is not allowed" );
+ }
+
+ if ( array_key_exists( 'request', $args ) ) {
+ $requestName = $args['request'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'request')->parse() );
+ }
+
+ if ( array_key_exists( 'requestData', $args ) ) {
+ $requestData = EDUtils::paramToArray( $args['requestData'] );
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'requestData')->parse() );
+ }
+
+ if ( array_key_exists( 'response', $args ) ) {
+ $responseName = $args['response'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'response')->parse() );
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ $mappings = EDUtils::paramToArray( $args['data'] ); // parse the data arg into mappings
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ $external_values = EDUtils::getSOAPData( $url, $requestName, $requestData, $responseName, $mappings);
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+
+ self::setGlobalValuesArray( $external_values, array(), $mappings );
+ }
+
+ /**
+ * Render the #get_ldap_data parser function
+ */
+ static function doGetLDAPData( &$parser ) {
+ global $edgCurPageName, $edgValues;
+
+ // if we're handling multiple pages, reset $edgValues
+ // when we move from one page to another
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'data', $args ) ) {
+ $mappings = EDUtils::paramToArray( $args['data'] ); // parse the data arg into mappings
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( !array_key_exists( 'filter', $args ) ) {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'filter')->parse() );
+ } elseif ( !array_key_exists( 'domain', $args ) ) {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'domain')->parse() );
+ } else {
+ $external_values = EDUtils::getLDAPData( $args['filter'], $args['domain'], array_values( $mappings ) );
+ }
+
+ // Build $edgValues
+ foreach ( $external_values as $i => $row ) {
+ if ( !is_array( $row ) ) {
+ continue;
+ }
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $row ) ) {
+ $edgValues[$local_var][] = $row[$external_var][0];
+ } else {
+ $edgValues[$local_var][] = '';
+ }
+ }
+ }
+ }
+
+ /**
+ * Render the #get_db_data parser function
+ */
+ static function doGetDBData( &$parser ) {
+ global $edgCurPageName, $edgValues;
+
+ // if we're handling multiple pages, reset $edgValues
+ // when we move from one page to another
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ $data = ( array_key_exists( 'data', $args ) ) ? $args['data'] : null;
+ if ( array_key_exists( 'db', $args ) ) {
+ $dbID = $args['db'];
+ } elseif ( array_key_exists( 'server', $args ) ) {
+ // For backwards-compatibility - 'db' parameter was
+ // added in External Data version 1.3.
+ $dbID = $args['server'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'db' )->parse() );
+ }
+ if ( array_key_exists( 'from', $args ) ) {
+ $from = $args['from'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'from')->parse() );
+ }
+ $conds = ( array_key_exists( 'where', $args ) ) ? $args['where'] : null;
+ $limit = ( array_key_exists( 'limit', $args ) ) ? $args['limit'] : null;
+ $orderBy = ( array_key_exists( 'order by', $args ) ) ? $args['order by'] : null;
+ $groupBy = ( array_key_exists( 'group by', $args ) ) ? $args['group by'] : null;
+ $sqlOptions = array( 'LIMIT' => $limit, 'ORDER BY' => $orderBy, 'GROUP BY' => $groupBy );
+ $joinOn = ( array_key_exists( 'join on', $args ) ) ? $args['join on'] : null;
+ $otherParams = array();
+ if ( array_key_exists('aggregate', $args ) ) {
+ $otherParams['aggregate'] = $args['aggregate'];
+ } elseif ( array_key_exists( 'find query', $args ) ) {
+ $otherParams['find query'] = $args['find query'];
+ }
+ $mappings = EDUtils::paramToArray( $data ); // parse the data arg into mappings
+
+ $external_values = EDUtils::getDBData( $dbID, $from, array_values( $mappings ), $conds, $sqlOptions, $joinOn, $otherParams );
+
+ // Handle error cases.
+ if ( !is_array( $external_values ) ) {
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+
+ // Build $edgValues.
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $external_values ) ) {
+ foreach ( $external_values[$external_var] as $value ) {
+ $edgValues[$local_var][] = $value;
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the specified index of the array for the specified local
+ * variable retrieved by one of the #get... parser functions.
+ */
+ static function getIndexedValue( $var, $i ) {
+ global $edgValues;
+ if ( array_key_exists( $var, $edgValues ) && array_key_exists( $i, $edgValues[$var] ) ) {
+ return $edgValues[$var][$i];
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Render the #external_value parser function
+ */
+ static function doExternalValue( &$parser, $local_var = '' ) {
+ global $edgValues, $edgExternalValueVerbose;
+ if ( ! array_key_exists( $local_var, $edgValues ) ) {
+ return $edgExternalValueVerbose ? EDUtils::formatErrorMessage( "Error: no local variable \"$local_var\" was set." ) : '';
+ } elseif ( is_array( $edgValues[$local_var] ) ) {
+ return $edgValues[$local_var][0];
+ } else {
+ return $edgValues[$local_var];
+ }
+ }
+
+ /**
+ * Render the #for_external_table parser function
+ */
+ static function doForExternalTable( &$parser, $expression = '' ) {
+ global $edgValues;
+
+ // Get the variables used in this expression, get the number
+ // of values for each, and loop through.
+ $matches = array();
+ preg_match_all( '/{{{([^}]*)}}}/', $expression, $matches );
+ $variables = $matches[1];
+ $num_loops = 0;
+
+ $commands = array( "urlencode", "htmlencode" );
+ // Used for a regexp check.
+ $commandsStr = implode( '|', $commands );
+
+ foreach ( $variables as $variable ) {
+ // If it ends with one of the pre-defined "commands",
+ // ignore the command to get the actual variable name.
+ foreach ( $commands as $command ) {
+ $variable = str_replace( $command, '', $variable );
+ }
+ $variable = str_replace( '.urlencode', '', $variable );
+ if ( array_key_exists( $variable, $edgValues ) ) {
+ $num_loops = max( $num_loops, count( $edgValues[$variable] ) );
+ }
+ }
+
+ $text = "";
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ $cur_expression = $expression;
+ foreach ( $variables as $variable ) {
+ // If it ends with one of the pre-defined "commands",
+ // ignore the command to get the actual variable name.
+ $matches = array();
+ preg_match( "/([^.]*)\.?($commandsStr)?$/", $variable, $matches );
+
+ $real_var = $matches[1];
+ if ( count( $matches ) == 3 ) {
+ $command = $matches[2];
+ } else {
+ $command = null;
+ }
+
+ switch( $command ) {
+ case "htmlencode":
+ $value = htmlentities( self::getIndexedValue( $real_var, $i ), ENT_COMPAT | ENT_HTML401| ENT_SUBSTITUTE, null, false );
+ break;
+ case "urlencode":
+ $value = urlencode( self::getIndexedValue( $real_var, $i ) );
+ break;
+ default:
+ $value = self::getIndexedValue( $real_var, $i );
+ }
+
+ $cur_expression = str_replace( '{{{' . $variable . '}}}', $value, $cur_expression );
+ }
+ $text .= $cur_expression;
+ }
+ return $text;
+ }
+
+ /**
+ * Render the #display_external_table parser function
+ *
+ * @author Dan Bolser
+ */
+ static function doDisplayExternalTable( &$parser ) {
+ global $edgValues;
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+
+ if ( array_key_exists( 'template', $args ) ) {
+ $template = $args['template'];
+ } else {
+ return EDUtils::formatErrorMessage( "No template specified" );
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ // or just use keys from edgValues
+ foreach ( $edgValues as $local_variable => $values ) {
+ $mappings[$local_variable] = $local_variable;
+ }
+ }
+
+ // The string placed in the wikitext between template calls -
+ // default is a newline.
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = str_replace( '\n', "\n", $args['delimiter'] );
+ } else {
+ $delimiter = "\n";
+ }
+
+ $num_loops = 0; // May differ when multiple '#get_'s are used in one page
+ foreach ( $mappings as $template_param => $local_variable ) {
+ if ( !array_key_exists( $local_variable, $edgValues ) ) {
+ // Don't throw an error message - the source may just
+ // not publish this variable.
+ continue;
+ }
+ $num_loops = max( $num_loops, count( $edgValues[$local_variable] ) );
+ }
+
+ if ( array_key_exists( 'intro template', $args ) && $num_loops > 0) {
+ $text = '{{' . $args['intro template'] . '}}';
+ } else {
+ $text = "";
+ }
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ if ( $i > 0 ) {
+ $text .= $delimiter;
+ }
+ $text .= '{{' . $template;
+ foreach ( $mappings as $template_param => $local_variable ) {
+ $value = self::getIndexedValue( $local_variable, $i );
+ $text .= "|$template_param=$value";
+ }
+ $text .= "}}";
+ }
+ if ( array_key_exists( 'outro template', $args ) && $num_loops > 0 ) {
+ $text .= '{{' . $args['outro template'] . '}}';
+ }
+
+ // This actually 'calls' the template that we built above
+ return array( $text, 'noparse' => false );
+ }
+
+ /**
+ * Based on Semantic Internal Objects'
+ * SIOSubobjectHandler::doSetInternal().
+ */
+ public static function callSubobject( $parser, $params ) {
+ // This is a hack, since SMW's SMWSubobject::render() call is
+ // not meant to be called outside of SMW. However, this seemed
+ // like the better solution than copying over all of that
+ // method's code. Ideally, a true public function can be
+ // added to SMW, that handles a subobject creation, that this
+ // code can then call.
+
+ $subobjectArgs = array( &$parser );
+ // Blank first argument, so that subobject ID will be
+ // an automatically-generated random number.
+ $subobjectArgs[1] = '';
+ // "main" property, pointing back to the page.
+ $mainPageName = $parser->getTitle()->getText();
+ $mainPageNamespace = $parser->getTitle()->getNsText();
+ if ( $mainPageNamespace != '' ) {
+ $mainPageName = $mainPageNamespace . ':' . $mainPageName;
+ }
+ $subobjectArgs[2] = $params[0] . '=' . $mainPageName;
+
+ foreach ( $params as $i => $value ) {
+ if ( $i == 0 ) continue;
+ $subobjectArgs[] = $value;
+ }
+
+ // SMW 1.9+
+ $instance = \SMW\ParserFunctionFactory::newFromParser( $parser )->getSubobjectParser();
+ return $instance->parse( new SMW\ParserParameterFormatter( $subobjectArgs ) );
+ }
+
+ /**
+ * Render the #store_external_table parser function
+ */
+ static function doStoreExternalTable( &$parser ) {
+ global $edgValues;
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser...
+
+ // Get the variables used in this expression, get the number
+ // of values for each, and loop through.
+ $expression = implode( '|', $params );
+ $matches = array();
+ preg_match_all( '/{{{([^}]*)}}}/', $expression, $matches );
+ $variables = $matches[1];
+ $num_loops = 0;
+ foreach ( $variables as $variable ) {
+ // ignore the presence of '.urlencode' - it's a command,
+ // not part of the actual variable name
+ $variable = str_replace( '.urlencode', '', $variable );
+ if ( array_key_exists( $variable, $edgValues ) ) {
+ $num_loops = max( $num_loops, count( $edgValues[$variable] ) );
+ }
+ }
+ $text = "";
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ // re-get $params
+ $params = func_get_args();
+ array_shift( $params );
+ foreach ( $params as $j => $param ) {
+ foreach ( $variables as $variable ) {
+ // If variable name ends with a ".urlencode",
+ // that's a command - URL-encode the value of
+ // the actual variable.
+ if ( strrpos( $variable, '.urlencode' ) === strlen( $variable ) - strlen( '.urlencode' ) ) {
+ $real_var = str_replace( '.urlencode', '', $variable );
+ $value = urlencode( self::getIndexedValue( $real_var , $i ) );
+ } else {
+ $value = self::getIndexedValue( $variable , $i );
+ }
+ $params[$j] = str_replace( '{{{' . $variable . '}}}', $value, $params[$j] );
+ }
+ }
+
+ self::callSubobject( $parser, $params );
+ }
+ return null;
+ }
+
+ /**
+ * Render the #clear_external_data parser function
+ */
+ static function doClearExternalData( &$parser ) {
+ global $edgValues;
+ $edgValues = array();
+ }
+}