server/src/app/Http/Controllers/Sparql/SparqlClientController.php
changeset 387 7fba86fa8604
parent 386 c731ab9b934d
child 389 2204faa0b41a
--- 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) {