server/src/app/Http/Controllers/Sparql/SparqlClientController.php
author ymh <ymh.work@gmail.com>
Mon, 31 Oct 2016 14:24:23 +0100
changeset 386 c731ab9b934d
child 387 7fba86fa8604
permissions -rw-r--r--
implement first version of sparql client interface

<?php

namespace CorpusParole\Http\Controllers\Sparql;

use Log;

use Illuminate\Http\Request;
use GuzzleHttp\Client;
use EasyRdf\Sparql\Result as SparqlResult;
use EasyRdf\Graph;
use EasyRdf\RdfNamespace;

use CorpusParole\Http\Controllers\Controller;
use CorpusParole\Libraries\Utils;

use CorpusParole\Libraries\Sparql\SparqlClient;
use CorpusParole\Libraries\Sparql\SparqlQueryAnalyser;
use RdfHelper;

class SparqlClientController extends Controller
{

    const HEADERS_FORWARDED = [ "host", "user-agent", "accept", "accept-language", "accept-encoding", "connection" ];

    const SELECT_RESULT_FORMAT = [
        "SPARQL/CSV" => "text/csv",
        "SPARQL/JSON" => "application/sparql-results+json",
        "SPARQL/XML" => "application/sparql-results+xml",
        "SPARQL/TSV" => "text/tab-separated-values",
        "BINARY" => "application/x-binary-rdf-results-table"
    ];

    const GRAPH_RESULT_FORMAT = [
        "N-Triples" => "application/n-triples",
        "RDF/XML" => "application/rdf+xml",
        "Turtle" => "text/turtle",
        "N3" => "text/n3",
        "RDF/JSON" => "application/rdf+json",
        "TriG" => "application/trig",
        "N-Quads" => "application/n-quads",
        "BinaryRDF" => "application/x-binary-rdf",
        "TriX" => "application/trix",
        "JSON-LD" => "application/ld+json"
    ];


    private $sparqlClient;
    private $httpClient;

    public function __construct(SparqlClient $sparqlClient, Client $httpClient) {
        $this->sparqlClient = $sparqlClient;
        $this->httpClient = $httpClient;
    }

    // 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();
        $results = [];
        foreach($docs as $row) {
            $results[] = array_reduce($fields, function($res, $field) use ($row) {
                if(isset($row->$field)) {
                    $res[$field] = RdfHelper::serialiseValue($row->$field);
                } else {
                    $res[$field] = "<span class=\"corpus-rdf-blank-value\">&nbsp;</span>";
                }
                return $res;
            }, []);
        }
        $namespaces = array_reduce(array_keys(RdfHelper::getPrefixes()), function($res, $p) {
            $res[$p] = RdfNamespace::namespaces()[$p];
            return $res;
        }, []);
        $data = [
            'query' => $query,
            'count' => $count,
            'fields' => $fields,
            'fieldPrefix' => "?",
            'results' => $results,
            'namespaces' => $namespaces,
            'downloadFormats' => self::SELECT_RESULT_FORMAT
        ];
        $view = 'sparql/sparqlClientResultList';
        return [$view, $data];
    }

    private function queryGraph(Request $request, $query, $analyser) {

        $docs = $this->sparqlClient->query($query);
        $fields = ["subject", "predicate", "object"];
        $results = [];
        foreach ($docs->resources() as $resource ) {
            foreach ($resource->propertyUris() as $property) {
                $propertyResource = $docs->resource($property);
                foreach ($resource->all($propertyResource) as $value) {
                    $results[] = [
                        'subject' => RdfHelper::serialiseValue($resource),
                        'predicate'=> RdfHelper::serialiseValue($propertyResource),
                        'object'=> RdfHelper::serialiseValue($value)
                    ];
                }
            }
        }
        $namespaces = array_reduce(array_keys(RdfHelper::getPrefixes()), function($res, $p) {
            $res[$p] = RdfNamespace::namespaces()[$p];
            return $res;
        }, []);


        $data = [
            'query' => $query,
            'count' => count($results),
            'fields' => $fields,
            'fieldPrefix' => "",
            'results' => $results,
            'namespaces' => $namespaces,
            'downloadFormats' => self::GRAPH_RESULT_FORMAT
        ];
        $view = 'sparql/sparqlClientResultList';

        return [$view, $data];
    }

    private function queryAsk(Request $request, $query, $analyser) {
        $data = [
            'results' => $this->sparqlClient->query($query),
            'namespaces' => $analyser->getPrefixes()
        ];

        $view = 'sparql/sparqlClientResultBoolean';
        return [$view, $data];
    }

    private function showHtml(Request $request) {

        $query = $request->input('query');

        $analyser = new SparqlQueryAnalyser($query);

        $queryType = $analyser->getQueryType();

        $namespaces = $analyser->getPrefixes();

        foreach($namespaces as $prefix => $nUri) {
            RdfNamespace::set($prefix,$nUri);
        }

        if($queryType === SparqlQueryAnalyser::SELECT_QUERY) {
            list($view, $data) = $this->querySelect($request, $query, $analyser);
        } elseif($queryType === SparqlQueryAnalyser::GRAPH_QUERY) {
            list($view, $data) = $this->queryGraph($request, $query, $analyser);
        } elseif($queryType === SparqlQueryAnalyser::ASK_QUERY) {
            list($view, $data) = $this->queryAsk($request, $query, $analyser);
        } else {
            //return 500
            abort(500, "Serialization format unknown");
        }

        return view($view, $data);

    }


    private function proxyQuery(Request $request, $format=null) {
        $query = $request->input('query');
        $headers = [];
        foreach (self::HEADERS_FORWARDED as $h) {
            $headerValue = $request->header($h);
            if($headerValue) {
                $headers[$h] = $headerValue;
            }
        }

        if(!empty($format)){
            $headers['Accept'] = $format;
        }

        $sesameResp = $this->httpClient->get(config('corpusparole.sesame_query_url'), ['query' => $request->all(), 'headers' => $headers]);

        $resp = response((string)$sesameResp->getBody(), $sesameResp->getStatusCode());
        foreach ($sesameResp->getHeaders() as $name => $values) {
            if($name != 'Transfer-Encoding') {
                $resp->header($name, $values);
            }
        }

        return $resp;
    }

    // display result
    public function show(Request $request) {

        $format = $request->input('format');

        if($format === 'text/html') {
            return $this->showHtml($request);
        } else {
            return $this->proxyQuery($request, $format);
        }

    }

    // do the query
    public function query(Request $request) {
        return $this->proxyQuery($request);
    }

}