summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php530
1 files changed, 530 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php b/www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php
new file mode 100644
index 00000000..ed851db5
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/includes/query/SMW_QueryProcessor.php
@@ -0,0 +1,530 @@
+<?php
+
+use ParamProcessor\Options;
+use ParamProcessor\Param;
+use ParamProcessor\ParamDefinition;
+use ParamProcessor\Processor;
+use SMW\ApplicationFactory;
+use SMW\Message;
+use SMW\Parser\RecursiveTextProcessor;
+use SMW\Query\Deferred;
+use SMW\Query\PrintRequest;
+use SMW\Query\Processor\ParamListProcessor;
+use SMW\Query\Processor\DefaultParamDefinition;
+use SMW\Query\QueryContext;
+use SMW\Query\Exception\ResultFormatNotFoundException;
+
+/**
+ * This file contains a static class for accessing functions to generate and execute
+ * semantic queries and to serialise their results.
+ *
+ * @ingroup SMWQuery
+ * @author Markus Krötzsch
+ */
+
+/**
+ * Static class for accessing functions to generate and execute semantic queries
+ * and to serialise their results.
+ * @ingroup SMWQuery
+ */
+class SMWQueryProcessor implements QueryContext {
+
+ /**
+ * @var RecursiveTextProcessor
+ */
+ private static $recursiveTextProcessor;
+
+ /**
+ * @since 3.0
+ *
+ * @param RecursiveTextProcessor|null $recursiveTextProcessor
+ */
+ public static function setRecursiveTextProcessor( RecursiveTextProcessor $recursiveTextProcessor = null ) {
+ self::$recursiveTextProcessor = $recursiveTextProcessor;
+ }
+
+ /**
+ * Takes an array of unprocessed parameters, processes them using
+ * Validator, and returns them.
+ *
+ * Both input and output arrays are
+ * param name (string) => param value (mixed)
+ *
+ * @since 1.6.2
+ * The return value changed in SMW 1.8 from an array with result values
+ * to an array with Param objects.
+ *
+ * @param array $params
+ * @param array $printRequests
+ * @param boolean $unknownInvalid
+ *
+ * @return Param[]
+ */
+ public static function getProcessedParams( array $params, array $printRequests = [], $unknownInvalid = true, $context = null, $showMode = false ) {
+ $validator = self::getValidatorForParams( $params, $printRequests, $unknownInvalid, $context, $showMode );
+ $validator->processParameters();
+ $parameters = $validator->getParameters();
+
+ // Negates some weird behaviour of ParamDefinition::setDefault used in
+ // an individual printer.
+ // Applying $smwgQMaxLimit, $smwgQMaxInlineLimit will happen at a later
+ // stage.
+ if ( isset( $params['limit'] ) && isset( $parameters['limit'] ) ) {
+ $parameters['limit']->setValue( (int)$params['limit'] );
+ }
+
+ return $parameters;
+ }
+
+ /**
+ * Parse a query string given in SMW's query language to create
+ * an SMWQuery. Parameters are given as key-value-pairs in the
+ * given array. The parameter $context defines in what context the
+ * query is used, which affects ceretain general settings.
+ * An object of type SMWQuery is returned.
+ *
+ * The format string is used to specify the output format if already
+ * known. Otherwise it will be determined from the parameters when
+ * needed. This parameter is just for optimisation in a common case.
+ *
+ * @param string $queryString
+ * @param array $params These need to be the result of a list fed to getProcessedParams
+ * @param $context
+ * @param string $format
+ * @param array $extraPrintouts
+ *
+ * @return SMWQuery
+ */
+ static public function createQuery( $queryString, array $params, $context = self::INLINE_QUERY, $format = '', array $extraPrintouts = [], $contextPage = null ) {
+
+ if ( $format === '' || is_null( $format ) ) {
+ $format = $params['format']->getValue();
+ }
+
+ $defaultSort = 'ASC';
+
+ if ( $format == 'count' ) {
+ $queryMode = SMWQuery::MODE_COUNT;
+ } elseif ( $format == 'debug' ) {
+ $queryMode = SMWQuery::MODE_DEBUG;
+ } else {
+ $printer = self::getResultPrinter( $format, $context );
+ $queryMode = $printer->getQueryMode( $context );
+ $defaultSort = $printer->getDefaultSort();
+ }
+
+ // set mode, limit, and offset:
+ $offset = 0;
+ $limit = $GLOBALS['smwgQDefaultLimit'];
+
+ if ( ( array_key_exists( 'offset', $params ) ) && ( is_int( $params['offset']->getValue() + 0 ) ) ) {
+ $offset = $params['offset']->getValue();
+ }
+
+ if ( ( array_key_exists( 'limit', $params ) ) && ( is_int( trim( $params['limit']->getValue() ) + 0 ) ) ) {
+ $limit = $params['limit']->getValue();
+
+ // limit < 0: always show further results link only
+ if ( ( trim( $params['limit']->getValue() ) + 0 ) < 0 ) {
+ $queryMode = SMWQuery::MODE_NONE;
+ }
+ }
+
+ // largest possible limit for "count", even inline
+ if ( $queryMode == SMWQuery::MODE_COUNT ) {
+ $offset = 0;
+ $limit = $GLOBALS['smwgQMaxLimit'];
+ }
+
+ $queryCreator = ApplicationFactory::getInstance()->singleton( 'QueryCreator' );
+
+ $params = [
+ 'extraPrintouts' => $extraPrintouts,
+ 'queryMode' => $queryMode,
+ 'context' => $context,
+ 'contextPage' => $contextPage,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'source' => $params['source']->getValue(),
+ 'mainLabel' => $params['mainlabel']->getValue(),
+ 'sort' => $params['sort']->getValue(),
+ 'order' => $params['order']->getValue(),
+ 'defaultSort' => $defaultSort
+ ];
+
+ return $queryCreator->create( $queryString, $params );
+ }
+
+ /**
+ * Add the subject print request, unless mainlabel is set to "-".
+ *
+ * @since 1.7
+ *
+ * @param array $printRequests
+ * @param array $rawParams
+ */
+ public static function addThisPrintout( array &$printRequests, array $rawParams ) {
+
+ if ( $printRequests === null ) {
+ return;
+ }
+
+ // If THIS is already registered, bail-out!
+ foreach ( $printRequests as $printRequest ) {
+ if ( $printRequest->isMode( PrintRequest::PRINT_THIS ) ) {
+ return;
+ }
+ }
+
+ $hasMainlabel = array_key_exists( 'mainlabel', $rawParams );
+
+ if ( !$hasMainlabel || trim( $rawParams['mainlabel'] ) !== '-' ) {
+ $printRequest = new PrintRequest(
+ PrintRequest::PRINT_THIS,
+ $hasMainlabel ? $rawParams['mainlabel'] : ''
+ );
+
+ // Signal to any post-processing that THIS was added outside of
+ // the normal processing chain
+ $printRequest->isDisconnected( true );
+
+ array_unshift( $printRequests, $printRequest );
+ }
+ }
+
+ /**
+ * Preprocess a query as given by an array of parameters as is typically
+ * produced by the #ask parser function. The parsing results in a querystring,
+ * an array of additional parameters, and an array of additional SMWPrintRequest
+ * objects, which are filled into call-by-ref parameters.
+ * $showMode is true if the input should be treated as if given by #show
+ *
+ * @param array $rawParams
+ * @param string $querystring
+ * @param array $params
+ * @param array $printouts array of SMWPrintRequest
+ * @param boolean $showMode
+ * @deprecated Will vanish after SMW 1.8 is released.
+ * Use getComponentsFromFunctionParams which has a cleaner interface.
+ */
+ static public function processFunctionParams( array $rawParams, &$querystring, &$params, &$printouts, $showMode = false ) {
+ list( $querystring, $params, $printouts ) = self::getComponentsFromFunctionParams( $rawParams, $showMode );
+ }
+
+
+ /**
+ * Preprocess a query as given by an array of parameters as is
+ * typically produced by the #ask parser function or by Special:Ask.
+ * The parsing results in a querystring, an array of additional
+ * parameters, and an array of additional SMWPrintRequest objects,
+ * which are returned in an array with three components. If
+ * $showMode is true then the input will be processed as if for #show.
+ * This uses a slightly different way to get the query, and different
+ * default labels (empty) for additional print requests.
+ *
+ * @param array $rawParams
+ * @param boolean $showMode
+ * @return array( string, array( string => string ), array( SMWPrintRequest ) )
+ */
+ static public function getComponentsFromFunctionParams( array $rawParams, $showMode ) {
+
+ $paramListProcessor = ApplicationFactory::getInstance()->singleton( 'ParamListProcessor' );
+
+ return $paramListProcessor->format(
+ $paramListProcessor->preprocess( $rawParams, $showMode ),
+ ParamListProcessor::FORMAT_LEGACY
+ );
+ }
+
+ /**
+ * Process and answer a query as given by an array of parameters as is
+ * typically produced by the #ask parser function. The parameter
+ * $context defines in what context the query is used, which affects
+ * certain general settings.
+ *
+ * The main task of this function is to preprocess the raw parameters
+ * to obtain actual parameters, printout requests, and the query string
+ * for further processing.
+ *
+ * @since 1.8
+ * @param array $rawParams user-provided list of unparsed parameters
+ * @param integer $outputMode SMW_OUTPUT_WIKI, SMW_OUTPUT_HTML, ...
+ * @param integer $context INLINE_QUERY, SPECIAL_PAGE, CONCEPT_DESC
+ * @param boolean $showMode process like #show parser function?
+ * @return array( SMWQuery, array of IParam )
+ */
+ static public function getQueryAndParamsFromFunctionParams( array $rawParams, $outputMode, $context, $showMode, $contextPage = null ) {
+ list( $queryString, $params, $printouts ) = self::getComponentsFromFunctionParams( $rawParams, $showMode );
+
+ if ( !$showMode ) {
+ self::addThisPrintout( $printouts, $params );
+ }
+
+ $params = self::getProcessedParams( $params, $printouts, true, $context, $showMode );
+
+ $query = self::createQuery( $queryString, $params, $context, '', $printouts, $contextPage );
+
+ // For convenience keep parameters and options to be available for immediate
+ // processing
+ if ( $context === self::DEFERRED_QUERY ) {
+ $query->setOption( Deferred::QUERY_PARAMETERS, implode( '|', $rawParams ) );
+ $query->setOption( Deferred::SHOW_MODE, $showMode );
+ $query->setOption( Deferred::CONTROL_ELEMENT, isset( $params['@control'] ) ? $params['@control']->getValue() : '' );
+ }
+
+ return [ $query, $params ];
+ }
+
+ /**
+ * Process and answer a query as given by an array of parameters as is
+ * typically produced by the #ask parser function. The result is formatted
+ * according to the specified $outputformat. The parameter $context defines
+ * in what context the query is used, which affects ceretain general settings.
+ *
+ * The main task of this function is to preprocess the raw parameters to
+ * obtain actual parameters, printout requests, and the query string for
+ * further processing.
+ *
+ * @note Consider using getQueryAndParamsFromFunctionParams() and
+ * getResultFromQuery() instead.
+ * @deprecated Will vanish after release of SMW 1.8.
+ * See SMW_Ask.php for example code on how to get query results from
+ * #ask function parameters.
+ */
+ static public function getResultFromFunctionParams( array $rawParams, $outputMode, $context = self::INLINE_QUERY, $showMode = false ) {
+ list( $queryString, $params, $printouts ) = self::getComponentsFromFunctionParams( $rawParams, $showMode );
+
+ if ( !$showMode ) {
+ self::addThisPrintout( $printouts, $params );
+ }
+
+ $params = self::getProcessedParams( $params, $printouts );
+
+ return self::getResultFromQueryString( $queryString, $params, $printouts, SMW_OUTPUT_WIKI, $context );
+ }
+
+ /**
+ * Process a query string in SMW's query language and return a formatted
+ * result set as specified by $outputmode. A parameter array of key-value-pairs
+ * constrains the query and determines the serialisation mode for results. The
+ * parameter $context defines in what context the query is used, which affects
+ * certain general settings. Finally, $extraprintouts supplies additional
+ * printout requests for the query results.
+ *
+ * @param string $queryString
+ * @param array $params These need to be the result of a list fed to getProcessedParams
+ * @param $extraPrintouts
+ * @param $outputMode
+ * @param $context
+ *
+ * @return string
+ * @deprecated Will vanish after release of SMW 1.8.
+ * See SMW_Ask.php for example code on how to get query results from
+ * #ask function parameters.
+ */
+ static public function getResultFromQueryString( $queryString, array $params, $extraPrintouts, $outputMode, $context = self::INLINE_QUERY ) {
+
+ $query = self::createQuery( $queryString, $params, $context, '', $extraPrintouts );
+ $result = self::getResultFromQuery( $query, $params, $outputMode, $context );
+
+
+ return $result;
+ }
+
+ /**
+ * Create a fully formatted result string from a query and its
+ * parameters. The method takes care of processing various types of
+ * query result. Most cases are handled by printers, but counting and
+ * debugging uses special code.
+ *
+ * @param SMWQuery $query
+ * @param array $params These need to be the result of a list fed to getProcessedParams
+ * @param integer $outputMode
+ * @param integer $context
+ * @since before 1.7, but public only since 1.8
+ *
+ * @return string
+ */
+ public static function getResultFromQuery( SMWQuery $query, array $params, $outputMode, $context ) {
+
+ $printer = self::getResultPrinter(
+ $params['format']->getValue(),
+ $context
+ );
+
+ if ( $printer->isDeferrable() && $context === self::DEFERRED_QUERY && $query->getLimit() > 0 ) {
+
+ // Halt processing that is not `DEFERRED_DATA` as it is expected the
+ // process is picked-up by the `deferred.js` loader that will
+ // initiate an API request to finalize the query after MW has build
+ // the page.
+ if ( $printer->isDeferrable() !== $printer::DEFERRED_DATA ) {
+ return Deferred::buildHTML( $query );
+ }
+
+ // `DEFERRED_DATA` is interpret as "execute the query with limit=0" (i.e.
+ // no query execution) but allow the printer to setup the HTML so that
+ // the data can be loaded after MW has finished the page build including
+ // the pre-rendered query HTML representation. This mode deferrers the
+ // actual query execution and data load to after the page build.
+ //
+ // Each printer that uses this mode has to handle the required parameters
+ // and data load accordingly.
+ $query->querymode = SMWQuery::MODE_INSTANCES;
+ $query->setOption( 'deferred.limit', $query->getLimit() );
+ $query->setLimit( 0 );
+ }
+
+ $res = self::getStoreFromParams( $params )->getQueryResult( $query );
+ $start = microtime( true );
+
+ if ( $res instanceof SMWQueryResult && $query->getOption( 'calc.result_hash' ) ) {
+ $query->setOption( 'result_hash', $res->getHash( 'quick' ) );
+ }
+
+ if ( ( $query->querymode == SMWQuery::MODE_INSTANCES ) ||
+ ( $query->querymode == SMWQuery::MODE_NONE ) ) {
+
+ $result = $printer->getResult( $res, $params, $outputMode );
+
+ $query->setOption( SMWQuery::PROC_PRINT_TIME, microtime( true ) - $start );
+ return $result;
+ } else { // result for counting or debugging is just a string or number
+
+ if ( $res instanceof SMWQueryResult ) {
+ $res = $res->getCountValue();
+ }
+
+ if ( is_numeric( $res ) ) {
+ $res = strval( $res );
+ }
+
+ if ( is_string( $res ) ) {
+ $result = str_replace( '_', ' ', $params['intro']->getValue() )
+ . $res
+ . str_replace( '_', ' ', $params['outro']->getValue() )
+ . smwfEncodeMessages( $query->getErrors() );
+ } else {
+ // When no valid result was obtained, $res will be a SMWQueryResult.
+ $result = smwfEncodeMessages( $query->getErrors() );
+ }
+
+ $query->setOption( SMWQuery::PROC_PRINT_TIME, microtime( true ) - $start );
+
+ return $result;
+ }
+ }
+
+ private static function getStoreFromParams( array $params ) {
+ return ApplicationFactory::getInstance()->getQuerySourceFactory()->get( $params['source']->getValue() );
+ }
+
+ /**
+ * Find suitable SMWResultPrinter for the given format. The context in
+ * which the query is to be used determines some basic settings of the
+ * returned printer object. Possible contexts are
+ * SMWQueryProcessor::SPECIAL_PAGE, SMWQueryProcessor::INLINE_QUERY,
+ * SMWQueryProcessor::CONCEPT_DESC.
+ *
+ * @param string $format
+ * @param $context
+ *
+ * @return SMWResultPrinter
+ * @throws MissingResultFormatException
+ */
+ static public function getResultPrinter( $format, $context = self::SPECIAL_PAGE ) {
+ global $smwgResultFormats;
+
+ SMWParamFormat::resolveFormatAliases( $format );
+
+ if ( !array_key_exists( $format, $smwgResultFormats ) ) {
+ throw new ResultFormatNotFoundException( "There is no result format for '$format'." );
+ }
+
+ $formatClass = $smwgResultFormats[$format];
+
+ $printer = new $formatClass( $format, ( $context != self::SPECIAL_PAGE ) );
+
+ if ( self::$recursiveTextProcessor === null ) {
+ self::$recursiveTextProcessor = new RecursiveTextProcessor();
+ }
+
+ $printer->setRecursiveTextProcessor(
+ self::$recursiveTextProcessor
+ );
+
+ return $printer;
+ }
+
+ /**
+ * Produces a list of default allowed parameters for a result printer. Most
+ * query printers should override this function.
+ *
+ * @since 1.6.2, return element type changed in 1.8
+ *
+ * @param integer|null $context
+ * @param ResultPrinter|null $resultPrinter
+ *
+ * @return IParamDefinition[]
+ */
+ public static function getParameters( $context = null, $resultPrinter = null ) {
+ return DefaultParamDefinition::getParamDefinitions( $context, $resultPrinter );
+ }
+
+ /**
+ * Returns the definitions of all parameters supported by the specified format.
+ *
+ * @since 1.8
+ *
+ * @param string $format
+ *
+ * @return ParamDefinition[]
+ */
+ public static function getFormatParameters( $format ) {
+ SMWParamFormat::resolveFormatAliases( $format );
+
+ if ( !array_key_exists( $format, $GLOBALS['smwgResultFormats'] ) ) {
+ return [];
+ }
+
+ $resultPrinter = self::getResultPrinter( $format );
+
+ if ( $resultPrinter instanceof \SMW\Query\ResultPrinters\NullResultPrinter ) {
+ return [];
+ }
+
+ return ParamDefinition::getCleanDefinitions(
+ $resultPrinter->getParamDefinitions( self::getParameters( null, $resultPrinter ) )
+ );
+ }
+
+ /**
+ * Takes an array of unprocessed parameters,
+ * and sets them on a new Validator object,
+ * which is returned and ready to process the parameters.
+ *
+ * @since 1.8
+ *
+ * @param array $params
+ * @param array $printRequests
+ * @param boolean $unknownInvalid
+ *
+ * @return Processor
+ */
+ private static function getValidatorForParams( array $params, array $printRequests = [], $unknownInvalid = true, $context = null, $showMode = false ) {
+ $paramDefinitions = self::getParameters( $context );
+
+ $paramDefinitions['format']->setPrintRequests( $printRequests );
+ $paramDefinitions['format']->setShowMode( $showMode );
+
+ $processorOptions = new Options();
+ $processorOptions->setUnknownInvalid( $unknownInvalid );
+
+ $validator = Processor::newFromOptions( $processorOptions );
+
+ $validator->setParameters( $params, $paramDefinitions, false );
+
+ return $validator;
+ }
+
+}