Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 105
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
CargoCompoundQuery
0.00% covered (danger)
0.00%
0 / 105
0.00% covered (danger)
0.00%
0 / 2
930
0.00% covered (danger)
0.00%
0 / 1
 run
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
420
 getOrDisplayQueryResultsFromStrings
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2/**
3 * CargoCompoundQuery - class for the #cargo_compound_query parser function.
4 *
5 * @author Yaron Koren
6 * @ingroup Cargo
7 */
8
9class CargoCompoundQuery {
10
11    /**
12     * Handles the #cargo_compound_query parser function - calls a
13     * "compound query", consisting of two or more queries of the
14     * Cargo data stored in the database, and then displays their
15     * results together.
16     *
17     * This function is based conceptually on the #compound_query
18     * parser function defined by the Semantic Compound Queries
19     * extension.
20     *
21     * @param Parser $parser
22     * @return string|array Error message string, or an array holding output text and format flags
23     */
24    public static function run( $parser ) {
25        $params = func_get_args();
26        array_shift( $params ); // we already know the $parser...
27
28        // Split up the parameters into query params and other params -
29        // we do that just by looking for the string "tables=";
30        // hopefully that will never show up in non-query params.
31        // Another possibility is to always check for ";", but query
32        // params can in theory hold a "tables=" clause and nothing
33        // else.
34        $queryParams = $otherParams = [];
35        foreach ( $params as $param ) {
36            if ( strpos( $param, 'tables=' ) !== false ) {
37                $queryParams[] = $param;
38            } else {
39                $otherParams[] = $param;
40            }
41        }
42
43        $sqlQueries = [];
44        $querySpecificParams = [];
45        foreach ( $queryParams as $param ) {
46            $tablesStr = null;
47            $fieldsStr = null;
48            $whereStr = null;
49            $joinOnStr = null;
50            $groupByStr = null;
51            $havingStr = null;
52            $orderByStr = null;
53            $limitStr = null;
54            $offsetStr = null;
55
56            $queryClauses = CargoUtils::smartSplit( ';', $param );
57            $displayParamsForThisQuery = [];
58            foreach ( $queryClauses as $clause ) {
59                $parts = explode( '=', $clause, 2 );
60                if ( count( $parts ) != 2 ) {
61                    continue;
62                }
63                $key = trim( $parts[0] );
64                $value = trim( $parts[1] );
65                if ( $key == 'tables' ) {
66                    $tablesStr = $value;
67                } elseif ( $key == 'fields' ) {
68                    $fieldsStr = $value;
69                } elseif ( $key == 'where' ) {
70                    $whereStr = $value;
71                } elseif ( $key == 'join on' ) {
72                    $joinOnStr = $value;
73                } elseif ( $key == 'group by' ) {
74                    $groupByStr = $value;
75                } elseif ( $key == 'having' ) {
76                    $havingStr = $value;
77                } elseif ( $key == 'order by' ) {
78                    $orderByStr = $value;
79                } elseif ( $key == 'limit' ) {
80                    $limitStr = $value;
81                } elseif ( $key == 'offset' ) {
82                    $offsetStr = $value;
83                } else {
84                    $displayParamsForThisQuery[$key] = $value;
85                }
86            }
87            try {
88                $sqlQueries[] = CargoSQLQuery::newFromValues( $tablesStr, $fieldsStr, $whereStr, $joinOnStr,
89                    $groupByStr, $havingStr, $orderByStr, $limitStr, $offsetStr );
90            } catch ( Exception $e ) {
91                return CargoUtils::formatError( $e->getMessage() );
92            }
93            $querySpecificParams[] = $displayParamsForThisQuery;
94        }
95
96        $format = 'auto'; // default
97        $displayParams = [];
98        foreach ( $otherParams as $param ) {
99            $parts = explode( '=', $param, 2 );
100
101            if ( count( $parts ) != 2 ) {
102                continue;
103            }
104            $key = trim( $parts[0] );
105            $value = trim( $parts[1] );
106            if ( $key == 'format' ) {
107                $format = $value;
108            } else {
109                // We'll assume it's going to the formatter.
110                $displayParams[$key] = $value;
111            }
112        }
113
114        try {
115            $queryResults = self::getOrDisplayQueryResultsFromStrings( $sqlQueries, $querySpecificParams,
116                    $format, $displayParams, $parser );
117        } catch ( Exception $e ) {
118            return CargoUtils::formatError( $e->getMessage() );
119        }
120
121        return $queryResults;
122    }
123
124    /**
125     * @todo - this should probably be streamlined and renamed.
126     */
127    public static function getOrDisplayQueryResultsFromStrings( $sqlQueries, $querySpecificParams,
128        $format, $displayParams, Parser $parser ) {
129        $queryDisplayer = new CargoQueryDisplayer();
130        $queryDisplayer->mParser = $parser;
131        $queryDisplayer->mFormat = $format;
132        $formatter = $queryDisplayer->getFormatter( $parser->getOutput() );
133        if ( $formatter->isDeferred() ) {
134            $text = $formatter->queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams );
135            return [ $text, 'noparse' => true, 'isHTML' => true ];
136        }
137
138        $allQueryResults = [];
139        $formattedQueryResults = [];
140        $allFieldDescriptions = [];
141
142        $rowNum = 0;
143        foreach ( $sqlQueries as $i => $sqlQuery ) {
144            $queryResults = $sqlQuery->run();
145            $allQueryResults = array_merge( $allQueryResults, $queryResults );
146            $queryDisplayer->mFieldDescriptions = $sqlQuery->mFieldDescriptions;
147            $formattedQueryResults = array_merge( $formattedQueryResults,
148                $queryDisplayer->getFormattedQueryResults( $queryResults ) );
149            // $formattedQueryResultsArray[] = $formattedQueryResults;
150            foreach ( $sqlQuery->mFieldDescriptions as $alias => $description ) {
151                $allFieldDescriptions[$alias] = $description;
152            }
153
154            // Now add this query's own display parameters to
155            // the row for every result of that query within an
156            // array contained in the $diaplayParams object.
157            $numResultsForThisQuery = count( $queryResults );
158            $displayParamsForThisQuery = $querySpecificParams[$i];
159            foreach ( $displayParamsForThisQuery as $paramName => $paramValue ) {
160                if ( array_key_exists( $paramName, $displayParams ) ) {
161                    // Just make sure it's an array.
162                    if ( !is_array( $displayParams[$paramName] ) ) {
163                        throw new MWException( "Error: \"$paramName\" cannot be used as both a "
164                        . "query-specific parameter and an overall display parameter." );
165                    }
166                } else {
167                    $displayParams[$paramName] = [];
168                }
169                // Now, add it in for each row.
170                for ( $j = $rowNum; $j < $rowNum + $numResultsForThisQuery; $j++ ) {
171                    $displayParams[$paramName][$j] = $paramValue;
172                }
173            }
174
175            $rowNum += $numResultsForThisQuery;
176        }
177
178        if ( $format === null ) {
179            return $allQueryResults;
180        }
181
182        // Finally, do the display, based on the format.
183        $text = $formatter->display( $allQueryResults, $formattedQueryResults, $allFieldDescriptions,
184            $displayParams );
185
186        // The 'template' format gets special parsing, because
187        // it can be used to display a larger component, like a table,
188        // which means that everything needs to be parsed together
189        // instead of one instance at a time. Also, the template will
190        // contain wikitext, not HTML.
191        $displayHTML = ( $format != 'template' );
192
193        // Don't show a "view more" link.
194        // @TODO - is such a thing possible for a compound query,
195        // especially if there's a limit set for each query?
196
197        if ( $displayHTML ) {
198            return [ $text, 'noparse' => true, 'isHTML' => true ];
199        } else {
200            return [ $text, 'noparse' => false ];
201        }
202    }
203
204}