--- a/server/src/app/Http/Controllers/Sparql/SparqlClientController.php Mon Oct 31 14:24:23 2016 +0100
+++ b/server/src/app/Http/Controllers/Sparql/SparqlClientController.php Thu Nov 03 01:52:26 2016 +0100
@@ -5,6 +5,9 @@
use Log;
use Illuminate\Http\Request;
+use Illuminate\Pagination\LengthAwarePaginator;
+use Illuminate\Pagination\Paginator;
+
use GuzzleHttp\Client;
use EasyRdf\Sparql\Result as SparqlResult;
use EasyRdf\Graph;
@@ -52,17 +55,25 @@
$this->httpClient = $httpClient;
}
+ public function getSparqlClient($timeout = null) {
+ if(is_null($timeout)) {
+ $timeout = config('corpusparole.sparql_client_timeout');
+ }
+ $queryUrl = config('corpusparole.sesame_query_url');
+ if($timeout > 0) {
+ $queryUrl = $queryUrl .
+ ((strlen(parse_url($queryUrl, PHP_URL_QUERY)) > 0)?"&":"?").
+ "timeout=$timeout";
+ }
+ return new \EasyRdf\Sparql\Client($queryUrl, config('corpusparole.sesame_update_url'));
+ }
+
// display form
public function index() {
return view('sparql/sparqlClientForm');
}
- private function querySelect(Request $request, $query, $analyser) {
- $countResult = $this->sparqlClient->query($analyser->getCountQuery());
- $countField = $countResult->getFields()[0];
- $count = $countResult->current()->$countField;
- $docs = $this->sparqlClient->query($query);
- $fields = $docs->getFields();
+ private function readDocs($docs, $fields) {
$results = [];
foreach($docs as $row) {
$results[] = array_reduce($fields, function($res, $field) use ($row) {
@@ -74,10 +85,78 @@
return $res;
}, []);
}
+ return $results;
+ }
+
+ private function abort($code, $message, $exception) {
+ throw new \Symfony\Component\HttpKernel\Exception\HttpException($code, $message, $exception, []);
+ }
+
+ private function processQueryException($exception) {
+ $message = $exception->getMessage();
+ if($exception instanceof \EasyRdf\Http\Exception) {
+ if(preg_match("/SPARQL\squery/", $message)) {
+ $this->abort(400, "La requête SPARQL n'est pas reconnue", $exception);
+ } else {
+ $this->abort(500, "Problème HTTP lors de la requête SPARQL", $exception);
+ }
+ } elseif($exception instanceof \EasyRdf\Exception) {
+ if(preg_match("/timed\sout/i", $message)) {
+ $this->abort(408, "Time-out causé par la requête SPARQL", $exception);
+ } else {
+ $this->abort(500, "Problème dans la requête SPARQL", $exception);
+ }
+ } else {
+ $this->abort(500, "Erreur serveur lors de la requête", $exception);
+ }
+ }
+
+ private function querySelect(Request $request, $query, $analyser) {
+
+ $limit = intval($request->input('limit', config('corpusparole.sparql_client_default_limit')));
+
+ if($limit === 0 || !is_null($analyser->getLimit()) || !is_null($analyser->getOffset()) ) {
+ try {
+ $docs = $this->getSparqlClient()->query($query);
+ } catch(\Exception $exception) {
+ $this->processQueryException($exception);
+ }
+
+ $fields = $docs->getFields();
+ $results = $this->readDocs($docs, $fields);
+ $count = count($results);
+
+ } else {
+
+ $page = Paginator::resolveCurrentPage(config('corpusparole.pagination_page_param'));
+ assert(is_null($page) || is_numeric($page));
+
+ $offset = max(0,($page - 1) * $limit);
+
+ try {
+ $countResult = $this->getSparqlClient()->query($analyser->getCountQuery());
+ $docs = $this->getSparqlClient()->query($query . " LIMIT $limit OFFSET $offset");
+ } catch(\Exception $exception) {
+ $this->processQueryException($exception);
+ }
+
+
+ $countField = $countResult->getFields()[0];
+ $count = $countResult->current()->$countField->getValue();
+
+ $fields = $docs->getFields();
+
+ $results = new LengthAwarePaginator($this->readDocs($docs, $fields), $count, $limit, $page, [
+ 'path' => Paginator::resolveCurrentPath(),
+ 'pageName' => config('corpusparole.pagination_page_param'),
+ ]);
+ }
+
$namespaces = array_reduce(array_keys(RdfHelper::getPrefixes()), function($res, $p) {
$res[$p] = RdfNamespace::namespaces()[$p];
return $res;
}, []);
+
$data = [
'query' => $query,
'count' => $count,
@@ -92,8 +171,13 @@
}
private function queryGraph(Request $request, $query, $analyser) {
+ try {
+ $docs = $this->getSparqlClient()->query($query);
+ } catch(\Exception $exception) {
+ $this->processQueryException($exception);
+ }
- $docs = $this->sparqlClient->query($query);
+
$fields = ["subject", "predicate", "object"];
$results = [];
foreach ($docs->resources() as $resource ) {
@@ -129,8 +213,14 @@
}
private function queryAsk(Request $request, $query, $analyser) {
+ try {
+ $result = $this->getSparqlClient()->query($query);
+ } catch(\Exception $exception) {
+ $this->processQueryException($exception);
+ }
+
$data = [
- 'results' => $this->sparqlClient->query($query),
+ 'results' => $result,
'namespaces' => $analyser->getPrefixes()
];
@@ -159,8 +249,7 @@
} elseif($queryType === SparqlQueryAnalyser::ASK_QUERY) {
list($view, $data) = $this->queryAsk($request, $query, $analyser);
} else {
- //return 500
- abort(500, "Serialization format unknown");
+ abort(400, "La requête n'est pas reconnue");
}
return view($view, $data);
@@ -182,7 +271,30 @@
$headers['Accept'] = $format;
}
- $sesameResp = $this->httpClient->get(config('corpusparole.sesame_query_url'), ['query' => $request->all(), 'headers' => $headers]);
+ $queryParams = $request->all();
+ $queryParams['timeout'] = config('corpusparole.sparql_client_timeout');
+ $queryUrl = config('corpusparole.sesame_query_url');
+
+ try {
+ $sesameResp = $this->httpClient->post($queryUrl, ['form_params' => $queryParams, 'headers' => $headers]);
+ } catch(\GuzzleHttp\Exception\ServerException $exception) {
+ if($exception->getCode() == 503) {
+ $this->abort(408, "Time-out causé par la requête SPARQL", $exception);
+ } else {
+ $this->abort(500, "Problème lors de la requête SPARQL", $exception);
+ }
+
+ } catch(\GuzzleHttp\Exception\RequestException $exception) {
+ $message = $exception->getMessage();
+ if(preg_match("/MALFORMED\sQUERY/i", $message)) {
+ $abortMessage = "Requête SPARQL mal-formée";
+ } else {
+ $abortMessage = "Problème lors de la requête SPARQL";
+ }
+ $this->abort($exception->getCode(), $abortMessage, $exception);
+ } catch(\Exception $exception) {
+ $this->abort(500, "Erreur serveur lors de la requête", $exception);
+ }
$resp = response((string)$sesameResp->getBody(), $sesameResp->getStatusCode());
foreach ($sesameResp->getHeaders() as $name => $values) {