Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial draft for listing new and modified concepts for a vocabulary in the REST API #982

Merged
merged 31 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7f4ada2
initial draft for the REST API methods returning new and modified con…
joelit May 6, 2020
765e9a1
Separated the functionality of WebController and RestController when …
joelit May 8, 2020
c177381
Amended tests to reflect the change in functionality
joelit May 8, 2020
65ea798
Timestamps passed from vocabulary as native PHP dateTimes, then proce…
joelit May 8, 2020
ce77bc6
Added handling of malformed date strings and tests
joelit May 12, 2020
80bde33
Fixed a method argument
joelit May 12, 2020
1b672e1
Fixed a method argument
joelit May 12, 2020
852dedc
using a PHP 7.1 compatible way for formating DateTime object
joelit May 12, 2020
be3076c
Numerous style tweaks. Added a limit parameter to parameterize the si…
joelit May 12, 2020
f2b8a57
Additional documentation for mappings-method
joelit May 14, 2020
c0bde73
Merge branch 'master' into issue862-mappings-documantation
May 14, 2020
454f1d0
Merge pull request #985 from NatLibFi/issue862-mappings-documantation
May 14, 2020
b42ff05
fixed a parameter name
joelit May 14, 2020
a326450
Merge pull request #987 from NatLibFi/issue986-fix-mappings-apidoc
May 14, 2020
d110308
fix typo in test name
kouralex Jun 3, 2020
4dd782f
initial draft for the REST API methods returning new and modified con…
joelit May 6, 2020
cb1bf10
Separated the functionality of WebController and RestController when …
joelit May 8, 2020
8d7bbdb
Amended tests to reflect the change in functionality
joelit May 8, 2020
31a422f
Timestamps passed from vocabulary as native PHP dateTimes, then proce…
joelit May 8, 2020
a3482bc
Added handling of malformed date strings and tests
joelit May 12, 2020
02c9b04
Fixed a method argument
joelit May 12, 2020
8be9f70
Fixed a method argument
joelit May 12, 2020
d209a45
using a PHP 7.1 compatible way for formating DateTime object
joelit May 12, 2020
52c84dc
Numerous style tweaks. Added a limit parameter to parameterize the si…
joelit May 12, 2020
2b5a423
Refactored methods, added swagger documentation
joelit Jun 10, 2020
0c20bac
Merge commit
joelit Jun 10, 2020
a171d68
cleaning up the code
joelit Jun 12, 2020
4d84b21
Added tests. Fixed abiguity between the namespace prefixes dc, dct, d…
joelit Jun 12, 2020
e5c649d
created & modified properties moved to the correct namespace
joelit Jun 12, 2020
053b065
Handling and tests for malformed dates
joelit Jun 12, 2020
a907434
Fixed PHPDoc comments
joelit Jun 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions controller/RestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1063,4 +1063,59 @@ public function related($request)
$ret = $this->transformPropertyResults($request->getUri(), $request->getLang(), $related, "related", "skos:related");
return $this->returnJson($ret);
}

/**
* Used for querying new concepts in the vocabulary
* @param Request $request
* @return object json-ld wrapped list of changed concepts
*/
public function newConcepts($request)
{
$offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
$limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200;

return $this->changedConcepts($request, 'dc:created', $offset, $limit);
}

/**
* Used for querying modified concepts in the vocabulary
* @param Request $request
* @return object json-ld wrapped list of changed concepts
*/
public function modifiedConcepts($request)
{
$offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
$limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200;

return $this->changedConcepts($request, 'dc:modified', $offset, $limit);
}

/**
* Used for querying changed concepts in the vocabulary
* @param Request $request
* @param int $offset starting index offset
* @param int $limit maximum number of concepts to return
* @return object json-ld wrapped list of changed concepts
*/
private function changedConcepts($request, $prop, $offset, $limit)
{
$changeList = $request->getVocab()->getChangeList($prop, $request->getLang(), $offset, $limit);

$simpleChangeList = array();
foreach($changeList as $conceptInfo) {
if (array_key_exists('date', $conceptInfo)) {
$simpleChangeList[] = array( 'uri' => $conceptInfo['uri'],
'prefLabel' => $conceptInfo['prefLabel'],
'date' => $conceptInfo['date']->format("Y-m-d\TH:i:sO") );
}
}
return $this->returnJson(array_merge_recursive($this->context,
array('@context' => array( '@language' => $request->getLang(),
'prefLabel' => 'skos:prefLabel',
'xsd' => 'http://www.w3.org/2001/XMLSchema#',
'date' => array( '@id' => 'http://purl.org/dc/terms/date', '@type' => 'http://www.w3.org/2001/XMLSchema#dateTime') )
),
array('changeList' => $simpleChangeList)));

}
}
43 changes: 37 additions & 6 deletions controller/WebController.php
Original file line number Diff line number Diff line change
Expand Up @@ -559,22 +559,53 @@ public function invokeGenericErrorPage($request, $message = null)
*/
public function invokeChangeList($request, $prop='dc:created')
{
// set language parameters for gettext
$this->setLanguageProperties($request->getLang());
$vocab = $request->getVocab();
$offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0;
$changeList = $vocab->getChangeList($prop, $request->getContentLang(), $request->getLang(), $offset);
$limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200;

$changeList = $this->getChangeList($request, $prop, $offset, $limit);
$bydate = $this->formatChangeList($changeList, $request->getLang());

// load template
$template = $this->twig->loadTemplate('changes.twig');

// render template
echo $template->render(
array(
'vocab' => $vocab,
'vocab' => $request->getVocab(),
'languages' => $this->languages,
'request' => $request,
'changeList' => $changeList)
'changeList' => $bydate)
);
}
/**
* Gets the list of newest concepts for a vocabulary according to timestamp indicated by a property
* @param Request $request
* @param string $prop the name of the property eg. 'dc:modified'.
* @param int $offset starting index offset
* @param int $limit maximum number of concepts to return
* @return Array list of concepts
*/
public function getChangeList($request, $prop, $offset=0, $limit=200)
{
// set language parameters for gettext
$this->setLanguageProperties($request->getLang());

return $request->getVocab()->getChangeList($prop, $request->getContentLang(), $offset, $limit);
}

/**
* Formats the list of concepts as labels arranged by modification month
* @param Array $changeList
* @param string $lang the language for displaying dates in the change list
*/
public function formatChangeList($changeList, $lang)
{
$formatByDate = array();
foreach($changeList as $concept) {
$concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $lang);
$formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $lang, true) . Punic\Calendar::format($concept['date'], ' y', $lang) ][strtolower($concept['prefLabel'])] = $concept;
}
return $formatByDate;
}

}
14 changes: 5 additions & 9 deletions model/Vocabulary.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,19 +615,15 @@ public function verifyVocabularyLanguage($lang)

/**
* Returns a list of recently changed or entirely new concepts.
* @param string $prop the property uri pointing to timestamps, eg. 'dc:modified'
* @param string $clang content language for the labels
* @param string $lang UI language for the dates
* @param int $offset starting index offset
* @param int $limit maximum number of concepts to return
* @return Array
*/
public function getChangeList($prop, $clang, $lang, $offset)
public function getChangeList($prop, $clang, $offset, $limit)
{
$changelist = $this->getSparql()->queryChangeList($clang, $offset, $prop);
$bydate = array();
foreach($changelist as $concept) {
$concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $lang);
$bydate[Punic\Calendar::getMonthName($concept['date'], 'wide', $lang, true) . Punic\Calendar::format($concept['date'], ' y', $lang) ][strtolower($concept['prefLabel'])] = $concept;
}
return $bydate;
return $this->getSparql()->queryChangeList($prop, $clang, $offset, $limit);
}

public function getTitle($lang=null) {
Expand Down
23 changes: 17 additions & 6 deletions model/sparql/GenericSparql.php
Original file line number Diff line number Diff line change
Expand Up @@ -2207,11 +2207,13 @@ public function listConceptGroupContents($groupClass, $group, $lang,$showDepreca

/**
* Generates the sparql query for queryChangeList.
* @param string $lang language of labels to return.
* @param string $property the property uri pointing to timestamps, eg. 'dc:modified'
* @param string $lang language of labels to return
* @param int $offset offset of results to retrieve; 0 for beginning of list
* @param int $limit maximum number of results to return
* @return string sparql query
*/
private function generateChangeListQuery($lang, $offset, $prop) {
private function generateChangeListQuery($prop, $lang, $offset, $limit=200) {
$fcl = $this->generateFromClause();
$offset = ($offset) ? 'OFFSET ' . $offset : '';

Expand All @@ -2224,8 +2226,9 @@ private function generateChangeListQuery($lang, $offset, $prop) {
FILTER (langMatches(lang(?label), '$lang'))
}
ORDER BY DESC(YEAR(?date)) DESC(MONTH(?date)) LCASE(?label)
LIMIT 200 $offset
LIMIT $limit $offset
EOQ;

return $query;
}

Expand All @@ -2243,7 +2246,12 @@ private function transformChangeListResults($result) {
}

if (isset($row->date)) {
$concept['date'] = $row->date->getValue();
try {
$concept['date'] = $row->date->getValue();
} catch (Exception $e) {
//don't record concepts with malformed dates e.g. 1986-21-00
continue;
}
}

$ret[] = $concept;
Expand All @@ -2253,12 +2261,15 @@ private function transformChangeListResults($result) {

/**
* return a list of recently changed or entirely new concepts
* @param string $property the property uri pointing to timestamps, eg. 'dc:modified'
* @param string $lang language of labels to return
* @param int $offset offset of results to retrieve; 0 for beginning of list
* @param int $limit maximum number of results to return
* @return array Result array
*/
public function queryChangeList($lang, $offset, $prop) {
$query = $this->generateChangeListQuery($lang, $offset, $prop);
public function queryChangeList($prop, $lang, $offset, $limit) {
$query = $this->generateChangeListQuery($prop, $lang, $offset, $limit);

$result = $this->query($query);
return $this->transformChangeListResults($result);
}
Expand Down
4 changes: 4 additions & 0 deletions rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
$controller->groups($request);
} elseif ($parts[2] == 'groupMembers') {
$controller->groupMembers($request);
} elseif ($parts[2] == 'new') {
$controller->newConcepts($request);
} elseif ($parts[2] == 'modified') {
$controller->modifiedConcepts($request);
} else {
header("HTTP/1.0 404 Not Found");
echo ("404 Not Found");
Expand Down
152 changes: 152 additions & 0 deletions swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,110 @@
]
}
},
"/{vocid}/new": {
"get": {
"summary": "New concepts in the vocabulary",
"parameters": [
{
"name": "vocid",
"in": "path",
"description": "a Skosmos vocabulary identifier e.g. \"stw\" or \"yso\"",
"required": true,
"type": "string"
},
{
"name": "lang",
"in": "query",
"description": "label language, e.g. \"en\" or \"fi\"",
"required": false,
"type": "string"
},
{
"name": "offset",
"in": "query",
"description": "offset of the starting index",
"required": false,
"type": "number"
},
{
"name": "limit",
"in": "query",
"description": "maximum number of concepts to return",
"required": false,
"type": "number"
}
],
"produces": [
"application/ld+json"
],
"responses": {
"200": {
"description": "list of most recently created concepts of the vocabulary",
"schema": {
"$ref": "#/definitions/changedConceptsResult"
}
},
"404": {
"description": "no vocabulary could be found with the requested id"
}
},
"tags": [
"Vocabulary-specific methods"
]
}
},
"/{vocid}/modified": {
"get": {
"summary": "Modified concepts in the vocabulary",
"parameters": [
{
"name": "vocid",
"in": "path",
"description": "a Skosmos vocabulary identifier e.g. \"stw\" or \"yso\"",
"required": true,
"type": "string"
},
{
"name": "lang",
"in": "query",
"description": "label language, e.g. \"en\" or \"fi\"",
"required": false,
"type": "string"
},
{
"name": "offset",
"in": "query",
"description": "offset of the starting index",
"required": false,
"type": "number"
},
{
"name": "limit",
"in": "query",
"description": "maximum number of concepts to return",
"required": false,
"type": "number"
}
],
"produces": [
"application/ld+json"
],
"responses": {
"200": {
"description": "list of most recently created concepts of the vocabulary",
"schema": {
"$ref": "#/definitions/changedConceptsResult"
}
},
"404": {
"description": "no vocabulary could be found with the requested id"
}
},
"tags": [
"Vocabulary-specific methods"
]
}
},
"/{vocid}/groupMembers": {
"get": {
"summary": "Members of the requested concept group",
Expand Down Expand Up @@ -1228,6 +1332,13 @@
"required": true,
"type": "string"
},
{
"name": "external",
"in": "query",
"description": "Indicates whether mappings to external vocabularies should be listed",
"required": false,
"type": "boolean"
},
{
"name": "clang",
"in": "query",
Expand Down Expand Up @@ -1256,6 +1367,9 @@
"304": {
"description": "the resource was not modified, so there is no need to retransmit the requested resources"
},
"400": {
"description": "URI parameter is missing"
},
"404": {
"description": "no concept mappings could be found with the requested URI"
}
Expand Down Expand Up @@ -2271,6 +2385,44 @@
"vocabName",
"typeLabel"
]
},
"changedConceptsResult": {
"type": "object",
"properties": {
"changeList": {
"type": "array",
"description": "List of changed concepts",
"items": {
"$ref": "#/definitions/changedConcept"
}
}
},
"required": [
"changeList"
]
},
"changedConcept": {
"type": "object",
"properties": {
"uri": {
"type": "string",
"description": "URI of the concept"
},
"prefLabel": {
"type": "string",
"description": "Preferred label of the concept"
},
"date": {
"type": "string",
"format": "date-time",
"description": "Time stamp"
}
},
"required": [
"uri",
"prefLabel",
"date"
]
}
}
}
Loading