server/src/app/Http/Controllers/Sparql/SparqlClientController.php
changeset 387 7fba86fa8604
parent 386 c731ab9b934d
child 389 2204faa0b41a
equal deleted inserted replaced
386:c731ab9b934d 387:7fba86fa8604
     3 namespace CorpusParole\Http\Controllers\Sparql;
     3 namespace CorpusParole\Http\Controllers\Sparql;
     4 
     4 
     5 use Log;
     5 use Log;
     6 
     6 
     7 use Illuminate\Http\Request;
     7 use Illuminate\Http\Request;
       
     8 use Illuminate\Pagination\LengthAwarePaginator;
       
     9 use Illuminate\Pagination\Paginator;
       
    10 
     8 use GuzzleHttp\Client;
    11 use GuzzleHttp\Client;
     9 use EasyRdf\Sparql\Result as SparqlResult;
    12 use EasyRdf\Sparql\Result as SparqlResult;
    10 use EasyRdf\Graph;
    13 use EasyRdf\Graph;
    11 use EasyRdf\RdfNamespace;
    14 use EasyRdf\RdfNamespace;
    12 
    15 
    50     public function __construct(SparqlClient $sparqlClient, Client $httpClient) {
    53     public function __construct(SparqlClient $sparqlClient, Client $httpClient) {
    51         $this->sparqlClient = $sparqlClient;
    54         $this->sparqlClient = $sparqlClient;
    52         $this->httpClient = $httpClient;
    55         $this->httpClient = $httpClient;
    53     }
    56     }
    54 
    57 
       
    58     public function getSparqlClient($timeout = null) {
       
    59         if(is_null($timeout)) {
       
    60             $timeout = config('corpusparole.sparql_client_timeout');
       
    61         }
       
    62         $queryUrl = config('corpusparole.sesame_query_url');
       
    63         if($timeout > 0) {
       
    64             $queryUrl = $queryUrl .
       
    65                 ((strlen(parse_url($queryUrl, PHP_URL_QUERY)) > 0)?"&":"?").
       
    66                 "timeout=$timeout";
       
    67         }
       
    68         return new \EasyRdf\Sparql\Client($queryUrl, config('corpusparole.sesame_update_url'));
       
    69     }
       
    70 
    55     // display form
    71     // display form
    56     public function index() {
    72     public function index() {
    57         return view('sparql/sparqlClientForm');
    73         return view('sparql/sparqlClientForm');
    58     }
    74     }
    59 
    75 
    60     private function querySelect(Request $request, $query, $analyser) {
    76     private function readDocs($docs, $fields) {
    61         $countResult = $this->sparqlClient->query($analyser->getCountQuery());
       
    62         $countField = $countResult->getFields()[0];
       
    63         $count = $countResult->current()->$countField;
       
    64         $docs = $this->sparqlClient->query($query);
       
    65         $fields = $docs->getFields();
       
    66         $results = [];
    77         $results = [];
    67         foreach($docs as $row) {
    78         foreach($docs as $row) {
    68             $results[] = array_reduce($fields, function($res, $field) use ($row) {
    79             $results[] = array_reduce($fields, function($res, $field) use ($row) {
    69                 if(isset($row->$field)) {
    80                 if(isset($row->$field)) {
    70                     $res[$field] = RdfHelper::serialiseValue($row->$field);
    81                     $res[$field] = RdfHelper::serialiseValue($row->$field);
    72                     $res[$field] = "<span class=\"corpus-rdf-blank-value\">&nbsp;</span>";
    83                     $res[$field] = "<span class=\"corpus-rdf-blank-value\">&nbsp;</span>";
    73                 }
    84                 }
    74                 return $res;
    85                 return $res;
    75             }, []);
    86             }, []);
    76         }
    87         }
       
    88         return $results;
       
    89     }
       
    90 
       
    91     private function abort($code, $message, $exception) {
       
    92         throw new \Symfony\Component\HttpKernel\Exception\HttpException($code, $message, $exception, []);
       
    93     }
       
    94 
       
    95     private function processQueryException($exception) {
       
    96         $message = $exception->getMessage();
       
    97         if($exception instanceof \EasyRdf\Http\Exception) {
       
    98             if(preg_match("/SPARQL\squery/", $message)) {
       
    99                 $this->abort(400, "La requête SPARQL n'est pas reconnue", $exception);
       
   100             } else {
       
   101                 $this->abort(500, "Problème HTTP lors de la requête SPARQL", $exception);
       
   102             }
       
   103         } elseif($exception instanceof \EasyRdf\Exception) {
       
   104             if(preg_match("/timed\sout/i", $message)) {
       
   105                 $this->abort(408, "Time-out causé par la requête SPARQL", $exception);
       
   106             } else {
       
   107                 $this->abort(500, "Problème dans la requête SPARQL", $exception);
       
   108             }
       
   109         } else {
       
   110             $this->abort(500, "Erreur serveur lors de la requête", $exception);
       
   111         }
       
   112     }
       
   113 
       
   114     private function querySelect(Request $request, $query, $analyser) {
       
   115 
       
   116         $limit = intval($request->input('limit', config('corpusparole.sparql_client_default_limit')));
       
   117 
       
   118         if($limit === 0 || !is_null($analyser->getLimit()) || !is_null($analyser->getOffset()) ) {
       
   119             try {
       
   120                 $docs = $this->getSparqlClient()->query($query);
       
   121             } catch(\Exception $exception) {
       
   122                 $this->processQueryException($exception);
       
   123             }
       
   124 
       
   125             $fields = $docs->getFields();
       
   126             $results = $this->readDocs($docs, $fields);
       
   127             $count = count($results);
       
   128 
       
   129         } else {
       
   130 
       
   131             $page = Paginator::resolveCurrentPage(config('corpusparole.pagination_page_param'));
       
   132             assert(is_null($page) || is_numeric($page));
       
   133 
       
   134             $offset = max(0,($page - 1) * $limit);
       
   135 
       
   136             try {
       
   137                 $countResult = $this->getSparqlClient()->query($analyser->getCountQuery());
       
   138                 $docs = $this->getSparqlClient()->query($query . " LIMIT $limit OFFSET $offset");
       
   139             } catch(\Exception $exception) {
       
   140                 $this->processQueryException($exception);
       
   141             }
       
   142 
       
   143 
       
   144             $countField = $countResult->getFields()[0];
       
   145             $count = $countResult->current()->$countField->getValue();
       
   146 
       
   147             $fields = $docs->getFields();
       
   148 
       
   149             $results = new LengthAwarePaginator($this->readDocs($docs, $fields), $count, $limit, $page, [
       
   150                 'path' => Paginator::resolveCurrentPath(),
       
   151                 'pageName' => config('corpusparole.pagination_page_param'),
       
   152             ]);
       
   153         }
       
   154 
    77         $namespaces = array_reduce(array_keys(RdfHelper::getPrefixes()), function($res, $p) {
   155         $namespaces = array_reduce(array_keys(RdfHelper::getPrefixes()), function($res, $p) {
    78             $res[$p] = RdfNamespace::namespaces()[$p];
   156             $res[$p] = RdfNamespace::namespaces()[$p];
    79             return $res;
   157             return $res;
    80         }, []);
   158         }, []);
       
   159 
    81         $data = [
   160         $data = [
    82             'query' => $query,
   161             'query' => $query,
    83             'count' => $count,
   162             'count' => $count,
    84             'fields' => $fields,
   163             'fields' => $fields,
    85             'fieldPrefix' => "?",
   164             'fieldPrefix' => "?",
    90         $view = 'sparql/sparqlClientResultList';
   169         $view = 'sparql/sparqlClientResultList';
    91         return [$view, $data];
   170         return [$view, $data];
    92     }
   171     }
    93 
   172 
    94     private function queryGraph(Request $request, $query, $analyser) {
   173     private function queryGraph(Request $request, $query, $analyser) {
    95 
   174         try {
    96         $docs = $this->sparqlClient->query($query);
   175             $docs = $this->getSparqlClient()->query($query);
       
   176         } catch(\Exception $exception) {
       
   177             $this->processQueryException($exception);
       
   178         }
       
   179 
       
   180 
    97         $fields = ["subject", "predicate", "object"];
   181         $fields = ["subject", "predicate", "object"];
    98         $results = [];
   182         $results = [];
    99         foreach ($docs->resources() as $resource ) {
   183         foreach ($docs->resources() as $resource ) {
   100             foreach ($resource->propertyUris() as $property) {
   184             foreach ($resource->propertyUris() as $property) {
   101                 $propertyResource = $docs->resource($property);
   185                 $propertyResource = $docs->resource($property);
   127 
   211 
   128         return [$view, $data];
   212         return [$view, $data];
   129     }
   213     }
   130 
   214 
   131     private function queryAsk(Request $request, $query, $analyser) {
   215     private function queryAsk(Request $request, $query, $analyser) {
       
   216         try {
       
   217             $result = $this->getSparqlClient()->query($query);
       
   218         } catch(\Exception $exception) {
       
   219             $this->processQueryException($exception);
       
   220         }
       
   221 
   132         $data = [
   222         $data = [
   133             'results' => $this->sparqlClient->query($query),
   223             'results' => $result,
   134             'namespaces' => $analyser->getPrefixes()
   224             'namespaces' => $analyser->getPrefixes()
   135         ];
   225         ];
   136 
   226 
   137         $view = 'sparql/sparqlClientResultBoolean';
   227         $view = 'sparql/sparqlClientResultBoolean';
   138         return [$view, $data];
   228         return [$view, $data];
   157         } elseif($queryType === SparqlQueryAnalyser::GRAPH_QUERY) {
   247         } elseif($queryType === SparqlQueryAnalyser::GRAPH_QUERY) {
   158             list($view, $data) = $this->queryGraph($request, $query, $analyser);
   248             list($view, $data) = $this->queryGraph($request, $query, $analyser);
   159         } elseif($queryType === SparqlQueryAnalyser::ASK_QUERY) {
   249         } elseif($queryType === SparqlQueryAnalyser::ASK_QUERY) {
   160             list($view, $data) = $this->queryAsk($request, $query, $analyser);
   250             list($view, $data) = $this->queryAsk($request, $query, $analyser);
   161         } else {
   251         } else {
   162             //return 500
   252             abort(400, "La requête n'est pas reconnue");
   163             abort(500, "Serialization format unknown");
       
   164         }
   253         }
   165 
   254 
   166         return view($view, $data);
   255         return view($view, $data);
   167 
   256 
   168     }
   257     }
   180 
   269 
   181         if(!empty($format)){
   270         if(!empty($format)){
   182             $headers['Accept'] = $format;
   271             $headers['Accept'] = $format;
   183         }
   272         }
   184 
   273 
   185         $sesameResp = $this->httpClient->get(config('corpusparole.sesame_query_url'), ['query' => $request->all(), 'headers' => $headers]);
   274         $queryParams = $request->all();
       
   275         $queryParams['timeout'] = config('corpusparole.sparql_client_timeout');
       
   276         $queryUrl = config('corpusparole.sesame_query_url');
       
   277 
       
   278         try {
       
   279             $sesameResp = $this->httpClient->post($queryUrl, ['form_params' => $queryParams, 'headers' => $headers]);
       
   280         } catch(\GuzzleHttp\Exception\ServerException $exception) {
       
   281             if($exception->getCode() == 503) {
       
   282                 $this->abort(408, "Time-out causé par la requête SPARQL", $exception);
       
   283             } else {
       
   284                 $this->abort(500, "Problème lors de la requête SPARQL", $exception);
       
   285             }
       
   286 
       
   287         } catch(\GuzzleHttp\Exception\RequestException $exception) {
       
   288             $message = $exception->getMessage();
       
   289             if(preg_match("/MALFORMED\sQUERY/i", $message)) {
       
   290                 $abortMessage = "Requête SPARQL mal-formée";
       
   291             } else {
       
   292                 $abortMessage = "Problème lors de la requête SPARQL";
       
   293             }
       
   294             $this->abort($exception->getCode(), $abortMessage, $exception);
       
   295         } catch(\Exception $exception) {
       
   296             $this->abort(500, "Erreur serveur lors de la requête", $exception);
       
   297         }
   186 
   298 
   187         $resp = response((string)$sesameResp->getBody(), $sesameResp->getStatusCode());
   299         $resp = response((string)$sesameResp->getBody(), $sesameResp->getStatusCode());
   188         foreach ($sesameResp->getHeaders() as $name => $values) {
   300         foreach ($sesameResp->getHeaders() as $name => $values) {
   189             if($name != 'Transfer-Encoding') {
   301             if($name != 'Transfer-Encoding') {
   190                 $resp->header($name, $values);
   302                 $resp->header($name, $values);