3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
21 namespace MediaWiki\Sparql
;
24 use MediaWiki\Http\HttpRequestFactory
;
27 * Simple SPARQL client
29 * @author Stas Malyshev
34 * Limit on how long can be the query to be sent by GET.
36 const MAX_GET_SIZE
= 2048;
39 * User agent for HTTP requests.
45 * Query timeout (seconds)
48 private $timeout = 30;
60 private $options = [];
63 * @var HttpRequestFactory
65 private $requestFactory;
68 * @param string $url SPARQL Endpoint
69 * @param HttpRequestFactory $requestFactory
71 public function __construct( $url, HttpRequestFactory
$requestFactory ) {
72 $this->endpoint
= $url;
73 $this->requestFactory
= $requestFactory;
74 $this->userAgent
= Http
::userAgent() . " SparqlClient";
78 * Set query timeout (in seconds)
82 public function setTimeout( $timeout ) {
83 if ( $timeout >= 0 ) {
84 $this->timeout
= $timeout;
91 * @param array $options
94 public function setClientOptions( $options ) {
95 $this->options
= $options;
100 * Get current user agent.
103 public function getUserAgent() {
104 return $this->userAgent
;
108 * Set user agent string.
110 * Mote it is not recommended to completely override user agent for
112 * @see appendUserAgent() for recommended way of specifying user agent.
114 * @param string $agent
116 public function setUserAgent( $agent ) {
117 $this->userAgent
= $agent;
121 * Append specific string to user agent.
123 * This is the recommended way of specifying the user agent
124 * for specific applications of the SparqlClient inside MediaWiki
125 * and extension code.
127 * @param string $agent
129 public function appendUserAgent( $agent ) {
130 $this->userAgent
.= ' ' . $agent;
134 * Query SPARQL endpoint
136 * @param string $sparql query
137 * @param bool $rawData Whether to return only values or full data objects
139 * @return array List of results, one row per array element
140 * Each row will contain fields indexed by variable name.
141 * @throws SparqlException
143 public function query( $sparql, $rawData = false ) {
144 if ( empty( $this->endpoint
) ) {
145 throw new SparqlException( 'Endpoint URL can not be empty' );
147 $queryData = [ "query" => $sparql, "format" => "json" ];
148 $options = array_merge( [ 'method' => 'GET' ], $this->options
);
150 if ( empty( $options['userAgent'] ) ) {
151 $options['userAgent'] = $this->userAgent
;
154 if ( $this->timeout
>= 0 ) {
155 // Blazegraph setting, see https://wiki.blazegraph.com/wiki/index.php/REST_API
156 $queryData['maxQueryTimeMillis'] = $this->timeout
* 1000;
157 $options['timeout'] = $this->timeout
;
160 if ( strlen( $sparql ) > self
::MAX_GET_SIZE
) {
161 // big requests go to POST
162 $options['method'] = 'POST';
163 $options['postData'] = 'query=' . urlencode( $sparql );
164 unset( $queryData['query'] );
167 $url = wfAppendQuery( $this->endpoint
, $queryData );
168 $request = $this->requestFactory
->create( $url, $options, __METHOD__
);
170 $status = $request->execute();
172 if ( !$status->isOK() ) {
173 throw new SparqlException( 'HTTP error: ' . $status->getWikiText( false, false, 'en' ) );
175 $result = $request->getContent();
176 \Wikimedia\
suppressWarnings();
177 $data = json_decode( $result, true );
178 \Wikimedia\restoreWarnings
();
179 if ( $data === null ||
$data === false ) {
180 throw new SparqlException( "HTTP request failed, response:\n" .
181 substr( $result, 1024 ) );
184 return $this->extractData( $data, $rawData );
188 * Extract data from SPARQL response format.
189 * The response must be in format described in:
190 * https://www.w3.org/TR/sparql11-results-json/
192 * @param array $data SPARQL result
193 * @param bool $rawData Whether to return only values or full data objects
195 * @return array List of results, one row per element.
197 private function extractData( $data, $rawData = false ) {
199 if ( $data && !empty( $data['results'] ) ) {
200 $vars = $data['head']['vars'];
202 foreach ( $data['results']['bindings'] as $row ) {
203 foreach ( $vars as $var ) {
204 if ( !isset( $row[$var] ) ) {
205 $resrow[$var] = null;
209 $resrow[$var] = $row[$var];
211 $resrow[$var] = $row[$var]['value'];