Minor dependency updates
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / Sparql / Client.php
1 <?php
2
3 /**
4  * EasyRdf
5  *
6  * LICENSE
7  *
8  * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
18  *    promote products derived from this software without specific prior
19  *    written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * @package    EasyRdf
34  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
35  * @license    http://www.opensource.org/licenses/bsd-license.php
36  */
37
38 /**
39  * Class for making SPARQL queries using the SPARQL 1.1 Protocol
40  *
41  * @package    EasyRdf
42  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
43  * @license    http://www.opensource.org/licenses/bsd-license.php
44  */
45 class EasyRdf_Sparql_Client
46 {
47     /** The query/read address of the SPARQL Endpoint */
48     private $queryUri = null;
49
50     private $queryUri_has_params = false;
51
52     /** The update/write address of the SPARQL Endpoint */
53     private $updateUri = null;
54
55     /** Create a new SPARQL endpoint client
56      *
57      * If the query and update endpoints are the same, then you
58      * only need to give a single URI.
59      *
60      * @param string $queryUri The address of the SPARQL Query Endpoint
61      * @param string $updateUri Optional address of the SPARQL Update Endpoint
62      */
63     public function __construct($queryUri, $updateUri = null)
64     {
65         $this->queryUri = $queryUri;
66
67         if (strlen(parse_url($queryUri, PHP_URL_QUERY)) > 0) {
68             $this->queryUri_has_params = true;
69         } else {
70             $this->queryUri_has_params = false;
71         }
72
73         if ($updateUri) {
74             $this->updateUri = $updateUri;
75         } else {
76             $this->updateUri = $queryUri;
77         }
78     }
79
80     /** Get the URI of the SPARQL query endpoint
81      *
82      * @return string The query URI of the SPARQL endpoint
83      */
84     public function getQueryUri()
85     {
86         return $this->queryUri;
87     }
88
89     /** Get the URI of the SPARQL update endpoint
90      *
91      * @return string The query URI of the SPARQL endpoint
92      */
93     public function getUpdateUri()
94     {
95         return $this->updateUri;
96     }
97
98     /**
99      * @depredated
100      * @ignore
101      */
102     public function getUri()
103     {
104         return $this->queryUri;
105     }
106
107     /** Make a query to the SPARQL endpoint
108      *
109      * SELECT and ASK queries will return an object of type
110      * EasyRdf_Sparql_Result.
111      *
112      * CONSTRUCT and DESCRIBE queries will return an object
113      * of type EasyRdf_Graph.
114      *
115      * @param string $query The query string to be executed
116      * @return object EasyRdf_Sparql_Result|EasyRdf_Graph Result of the query.
117      */
118     public function query($query)
119     {
120         return $this->request('query', $query);
121     }
122
123     /** Count the number of triples in a SPARQL 1.1 endpoint
124      *
125      * Performs a SELECT query to estriblish the total number of triples.
126      *
127      * Counts total number of triples by default but a conditional triple pattern
128      * can be given to count of a subset of all triples.
129      *
130      * @param string $condition Triple-pattern condition for the count query
131      * @return integer The number of triples
132      */
133     public function countTriples($condition = '?s ?p ?o')
134     {
135         // SELECT (COUNT(*) AS ?count)
136         // WHERE {
137         //   {?s ?p ?o}
138         //   UNION
139         //   {GRAPH ?g {?s ?p ?o}}
140         // }
141         $result = $this->query('SELECT (COUNT(*) AS ?count) {'.$condition.'}');
142         return $result[0]->count->getValue();
143     }
144
145     /** Get a list of named graphs from a SPARQL 1.1 endpoint
146      *
147      * Performs a SELECT query to get a list of the named graphs
148      *
149      * @param string $limit Optional limit to the number of results
150      * @return array Array of EasyRdf_Resource objects for each named graph
151      */
152     public function listNamedGraphs($limit = null)
153     {
154         $query = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s ?p ?o}}";
155         if (!is_null($limit)) {
156             $query .= " LIMIT ".(int)$limit;
157         }
158         $result = $this->query($query);
159
160         // Convert the result object into an array of resources
161         $graphs = array();
162         foreach ($result as $row) {
163             array_push($graphs, $row->g);
164         }
165         return $graphs;
166     }
167
168     /** Make an update request to the SPARQL endpoint
169      *
170      * Successful responses will return the HTTP response object
171      *
172      * Unsuccessful responses will throw an exception
173      *
174      * @param string $query The update query string to be executed
175      * @return object EasyRdf_Http_Response HTTP response
176      */
177     public function update($query)
178     {
179         return $this->request('update', $query);
180     }
181
182     public function insert($data, $graphUri = null)
183     {
184         #$this->updateData('INSET',
185         $query = 'INSERT DATA {';
186         if ($graphUri) {
187             $query .= "GRAPH <$graphUri> {";
188         }
189         $query .= $this->convertToTriples($data);
190         if ($graphUri) {
191             $query .= "}";
192         }
193         $query .= '}';
194         return $this->update($query);
195     }
196
197     protected function updateData($operation, $data, $graphUri = null)
198     {
199         $query = "$operation DATA {";
200         if ($graphUri) {
201             $query .= "GRAPH <$graphUri> {";
202         }
203         $query .= $this->convertToTriples($data);
204         if ($graphUri) {
205             $query .= "}";
206         }
207         $query .= '}';
208         return $this->update($query);
209     }
210
211     public function clear($graphUri, $silent = false)
212     {
213         $query = "CLEAR";
214         if ($silent) {
215             $query .= " SILENT";
216         }
217         if (preg_match('/^all|named|default$/i', $graphUri)) {
218             $query .= " $graphUri";
219         } else {
220             $query .= " GRAPH <$graphUri>";
221         }
222         return $this->update($query);
223     }
224
225     /*
226      * Internal function to make an HTTP request to SPARQL endpoint
227      *
228      * @ignore
229      */
230     protected function request($type, $query)
231     {
232         // Check for undefined prefixes
233         $prefixes = '';
234         foreach (EasyRdf_Namespace::namespaces() as $prefix => $uri) {
235             if (strpos($query, "$prefix:") !== false and
236                 strpos($query, "PREFIX $prefix:") === false) {
237                 $prefixes .=  "PREFIX $prefix: <$uri>\n";
238             }
239         }
240
241         $client = EasyRdf_Http::getDefaultHttpClient();
242         $client->resetParameters();
243
244         // Tell the server which response formats we can parse
245         $accept = EasyRdf_Format::getHttpAcceptHeader(
246             array(
247               'application/sparql-results+json' => 1.0,
248               'application/sparql-results+xml' => 0.8
249             )
250         );
251         $client->setHeaders('Accept', $accept);
252
253         if ($type == 'update') {
254             $client->setMethod('POST');
255             $client->setUri($this->updateUri);
256             $client->setRawData($prefixes . $query);
257             $client->setHeaders('Content-Type', 'application/sparql-update');
258         } elseif ($type == 'query') {
259             // Use GET if the query is less than 2kB
260             // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server
261             $encodedQuery = 'query='.urlencode($prefixes . $query);
262             if (strlen($encodedQuery) + strlen($this->queryUri) <= 2046) {
263                 $delimiter = $this->queryUri_has_params ? '&' : '?';
264
265                 $client->setMethod('GET');
266                 $client->setUri($this->queryUri.$delimiter.$encodedQuery);
267             } else {
268                 // Fall back to POST instead (which is un-cacheable)
269                 $client->setMethod('POST');
270                 $client->setUri($this->queryUri);
271                 $client->setRawData($encodedQuery);
272                 $client->setHeaders('Content-Type', 'application/x-www-form-urlencoded');
273             }
274         }
275
276         $response = $client->request();
277         if ($response->getStatus() == 204) {
278             // No content
279             return $response;
280         } elseif ($response->isSuccessful()) {
281             list($type, $params) = EasyRdf_Utils::parseMimeType(
282                 $response->getHeader('Content-Type')
283             );
284             if (strpos($type, 'application/sparql-results') === 0) {
285                 return new EasyRdf_Sparql_Result($response->getBody(), $type);
286             } else {
287                 return new EasyRdf_Graph($this->queryUri, $response->getBody(), $type);
288             }
289         } else {
290             throw new EasyRdf_Exception(
291                 "HTTP request for SPARQL query failed: ".$response->getBody()
292             );
293         }
294     }
295
296     protected function convertToTriples($data)
297     {
298         if (is_string($data)) {
299             return $data;
300         } elseif (is_object($data) and $data instanceof EasyRdf_Graph) {
301             # FIXME: insert Turtle when there is a way of seperateing out the prefixes
302             return $data->serialise('ntriples');
303         } else {
304             throw new EasyRdf_Exception(
305                 "Don't know how to convert to triples for SPARQL query: ".$response->getBody()
306             );
307         }
308     }
309 }