diff --git a/controller/RestController.php b/controller/RestController.php index 48f9c1b64..0b0b2ef43 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -700,6 +700,62 @@ public function label($request) return $this->returnJson($ret); } + /** + * Query for the available letters in the alphabetical index. + * @param Request $request + * @return object JSON-LD wrapped list of letters + */ + + public function indexLetters($request) + { + $this->setLanguageProperties($request->getLang()); + $letters = $request->getVocab()->getAlphabet($request->getLang()); + + $ret = array_merge_recursive($this->context, array( + '@context' => array( + 'indexLetters' => array( + '@id' => 'skosmos:indexLetters', + '@container' => '@list', + '@language' => $request->getLang() + ) + ), + 'uri' => '', + 'indexLetters' => $letters) + ); + return $this->returnJson($ret); + } + + /** + * Query for the concepts with terms starting with a given letter in the + * alphabetical index. + * @param Request $request + * @return object JSON-LD wrapped list of terms/concepts + */ + + public function indexConcepts($letter, $request) + { + $this->setLanguageProperties($request->getLang()); + + $offset_param = $request->getQueryParam('offset'); + $offset = (is_numeric($offset_param) && $offset_param >= 0) ? $offset_param : 0; + $limit_param = $request->getQueryParam('limit'); + $limit = (is_numeric($limit_param) && $limit_param >= 0) ? $limit_param : 0; + + $concepts = $request->getVocab()->searchConceptsAlphabetical($letter, $limit, $offset, $request->getLang()); + + $ret = array_merge_recursive($this->context, array( + '@context' => array( + 'indexConcepts' => array( + '@id' => 'skosmos:indexConcepts', + '@container' => '@list' + ) + ), + 'uri' => '', + 'indexConcepts' => $concepts) + ); + return $this->returnJson($ret); + } + private function transformPropertyResults($uri, $lang, $objects, $propname, $propuri) { $results = array(); diff --git a/rest.php b/rest.php index 6b02dcbe2..b335d5bb5 100644 --- a/rest.php +++ b/rest.php @@ -66,6 +66,13 @@ $controller->label($request); } elseif ($parts[2] == 'lookup') { $controller->lookup($request); + } elseif ($parts[2] == 'index' && sizeof($parts) == 4) { + $letter = $parts[3]; + if ($letter == "") { + $controller->indexLetters($request); + } else { + $controller->indexConcepts($letter, $request); + } } elseif ($parts[2] == 'broader') { $controller->broader($request); } elseif ($parts[2] == 'broaderTransitive') { diff --git a/swagger.json b/swagger.json index 1485aa9db..116090d88 100644 --- a/swagger.json +++ b/swagger.json @@ -353,20 +353,20 @@ "required": false, "type": "string" }, - { + { "name": "lang", "in": "query", "description": "RDF language code when the requested resource for the MIME type is language specific, e.g. \"fi\" or \"en\".", "required": false, "type": "string" - } + } ], "produces": [ "application/rdf+xml", "text/turtle", "application/ld+json", "application/json", - "application/marcxml+xml" + "application/marcxml+xml" ], "responses": { "200": { @@ -597,6 +597,91 @@ ] } }, + "/{vocid}/index/": { + "get": { + "summary": "Initial letters of the alphabetical index", + "description": "Returns a list of the initial letters of labels (skos:prefLabel, skos:altLabel) in the given language, or the default language of the vocabulary. The special value \"0-9\" indicates the presence of labels starting with a number and the value \"!*\" indicates labels starting with a special character.", + "parameters": [ + { + "name": "vocid", + "in": "path", + "description": "a Skosmos vocabulary identifier e.g. \"stw\" or \"yso\"", + "required": true, + "type": "string" + }, + { + "name": "lang", + "in": "query", + "description": "language of labels, e.g. \"en\" or \"fi\"", + "required": false, + "type": "string" + } + ], + "produces": [ + "application/ld+json" + ], + "responses": { + "200": { + "description": "initial letters of the alphabetical index", + "schema": { + "$ref": "#/definitions/IndexLetters" + } + }, + "404": { + "description": "no vocabulary could be found with the requested id" + } + }, + "tags": [ + "Vocabulary-specific methods" + ] + } + }, + "/{vocid}/index/{letter}": { + "get": { + "summary": "Concepts for a given letter in the alphabetical index", + "description": "Returns a list of the concepes which have a label (skos:prefLabel or skos:altLabel) starting with the given letter in the given language, or the default language of the vocabulary. The special value \"0-9\" matches labels starting with a number and the value \"!*\" matches labels starting with a special character.", + "parameters": [ + { + "name": "vocid", + "in": "path", + "description": "a Skosmos vocabulary identifier e.g. \"stw\" or \"yso\"", + "required": true, + "type": "string" + }, + { + "name": "letter", + "in": "path", + "description": "an initial letter, or one of the special values \"0-9 or \"!*\"", + "required": true, + "type": "string" + }, + { + "name": "lang", + "in": "query", + "description": "language of labels, e.g. \"en\" or \"fi\"", + "required": false, + "type": "string" + } + ], + "produces": [ + "application/ld+json" + ], + "responses": { + "200": { + "description": "concepts of the alphabetical index", + "schema": { + "$ref": "#/definitions/IndexConcepts" + } + }, + "404": { + "description": "no vocabulary could be found with the requested id" + } + }, + "tags": [ + "Vocabulary-specific methods" + ] + } + }, "/{vocid}/label": { "get": { "summary": "Preferred label for the requested concept", @@ -1294,6 +1379,71 @@ "result" ] }, + "IndexLetters": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "indexLetters": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "A", + "B", + "C", + "0-9", + "!*" + ] + } + }, + "required": [ + "uri", + "indexLetters" + ] + }, + "IndexConcepts": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "indexConcepts": { + "type": "array", + "items": { + "$ref": "#/definitions/IndexConcept" + } + } + }, + "required": [ + "uri", + "indexLetters" + ] + }, + "IndexConcept": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "prefLabel": { + "type": "string" + }, + "altLabel": { + "type": "string" + }, + "lang": { + "type": "string" + } + }, + "required": [ + "uri", + "prefLabel", + "lang" + ] + }, "VocabularyStatistics": { "type": "object", "properties": { @@ -1818,4 +1968,4 @@ ] } } -} +} \ No newline at end of file diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index 850869812..62204029e 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -65,4 +65,79 @@ public function testSearchJsonLdWithAdditionalFields() { $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","isothes":"http:\/\/purl.org\/iso25964\/skos-thes#","onki":"http:\/\/schema.onki.fi\/onki#","uri":"@id","type":"@type","results":{"@id":"onki:results","@container":"@list"},"prefLabel":"skos:prefLabel","altLabel":"skos:altLabel","hiddenLabel":"skos:hiddenLabel","broader":"skos:broader","relatedMatch":"skos:relatedMatch"},"uri":"","results":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta117","type":["skos:Concept","meta:TestClass"],"broader":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta1"}],"relatedMatch":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta115"}],"prefLabel":"3D Bass","lang":"en","vocab":"test"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta116","type":["skos:Concept","meta:TestClass"],"broader":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta1"}],"prefLabel":"Bass","lang":"en","vocab":"test"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta122","type":["skos:Concept","meta:TestClass"],"broader":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta116"}],"prefLabel":"Black sea bass","lang":"en","vocab":"test"}]}', $out); } + + /** + * @covers RestController::indexLetters + */ + public function testIndexLettersJsonLd() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $this->controller->indexLetters($request); + + $out = $this->getActualOutput(); + + $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","uri":"@id","type":"@type","indexLetters":{"@id":"skosmos:indexLetters","@container":"@list","@language":"en"}},"uri":"","indexLetters":["B","C","E","F","M","T","!*","0-9"]}', $out); + } + + /** + * @covers RestController::indexConcepts + */ + public function testIndexConceptsJsonLd() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $this->controller->indexConcepts("B", $request); + + $out = $this->getActualOutput(); + + $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","uri":"@id","type":"@type","indexConcepts":{"@id":"skosmos:indexConcepts","@container":"@list"}},"uri":"","indexConcepts":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta116","localname":"ta116","prefLabel":"Bass","lang":"en"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta122","localname":"ta122","prefLabel":"Black sea bass","lang":"en"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta114","localname":"ta114","prefLabel":"Buri","lang":"en"}]}', $out); + } + + /** + * @covers RestController::indexConcepts + */ + public function testIndexConceptsJsonLdLimit() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setQueryParam('limit', '2'); + $this->controller->indexConcepts("B", $request); + + $out = $this->getActualOutput(); + + $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","uri":"@id","type":"@type","indexConcepts":{"@id":"skosmos:indexConcepts","@container":"@list"}},"uri":"","indexConcepts":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta116","localname":"ta116","prefLabel":"Bass","lang":"en"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta122","localname":"ta122","prefLabel":"Black sea bass","lang":"en"}]}', $out); + } + + /** + * @covers RestController::indexConcepts + */ + public function testIndexConceptsJsonLdOffset() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setQueryParam('offset', '1'); + $this->controller->indexConcepts("B", $request); + + $out = $this->getActualOutput(); + + $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","uri":"@id","type":"@type","indexConcepts":{"@id":"skosmos:indexConcepts","@container":"@list"}},"uri":"","indexConcepts":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta122","localname":"ta122","prefLabel":"Black sea bass","lang":"en"},{"uri":"http:\/\/www.skosmos.skos\/test\/ta114","localname":"ta114","prefLabel":"Buri","lang":"en"}]}', $out); + } + + /** + * @covers RestController::indexConcepts + */ + public function testIndexConceptsJsonLdLimitOffset() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setQueryParam('limit', '1'); + $request->setQueryParam('offset', '1'); + $this->controller->indexConcepts("B", $request); + + $out = $this->getActualOutput(); + + $this->assertJsonStringEqualsJsonString('{"@context":{"skos":"http:\/\/www.w3.org\/2004\/02\/skos\/core#","uri":"@id","type":"@type","indexConcepts":{"@id":"skosmos:indexConcepts","@container":"@list"}},"uri":"","indexConcepts":[{"uri":"http:\/\/www.skosmos.skos\/test\/ta122","localname":"ta122","prefLabel":"Black sea bass","lang":"en"}]}', $out); + } + }