From 7f4ada29fdb52fbc1172b6df3676ca2bfeff1e66 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Wed, 6 May 2020 13:46:02 +0300 Subject: [PATCH 01/24] initial draft for the REST API methods returning new and modified concepts for a vocabulary --- controller/RestController.php | 40 +++++++++++++++++++++++++++++++++++ rest.php | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/controller/RestController.php b/controller/RestController.php index c62eb4216..fbafc5b56 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1063,4 +1063,44 @@ 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) + { + return $this->changed($request); + } + + /** + * Used for querying modified concepts in the vocabulary + * @param Request $request + * @return object json-ld wrapped list of changed concepts + */ + public function modifiedConcepts($request) + { + return $this->changed($request, 'dc:modified'); + } + + /** + * Used for querying changed concepts in the vocabulary + * @param Request $request + * @return object json-ld wrapped list of changed concepts + */ + private function changed($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; + $contentLang = ($request->getContentLang() != null) ? $request->getContentLang() : $request->getLang(); + $changeList = $vocab->getChangeList($prop, $contentLang, $request->getLang(), $offset); + + return $this->returnJson(array_merge_recursive($this->context, + array('@context' => array('@language' => $request->getLang())), + array('changeList' => $changeList))); + + } } diff --git a/rest.php b/rest.php index 5d276f105..86066dcf4 100644 --- a/rest.php +++ b/rest.php @@ -97,6 +97,10 @@ $controller->groups($request); } elseif ($parts[2] == 'groupMembers') { $controller->groupMembers($request); + } elseif ($parts[2] == 'newConcepts') { + $controller->newConcepts($request); + } elseif ($parts[2] == 'modifiedConcepts') { + $controller->modifiedConcepts($request); } else { header("HTTP/1.0 404 Not Found"); echo ("404 Not Found"); From 765e9a182db6c13c7becf349df4ba5099ff03cda Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 13:06:35 +0300 Subject: [PATCH 02/24] Separated the functionality of WebController and RestController when forming the change list --- controller/RestController.php | 9 ++++++--- controller/WebController.php | 12 ++++++++++-- model/Vocabulary.php | 12 +++--------- model/sparql/GenericSparql.php | 2 +- rest.php | 4 ++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index fbafc5b56..b052aed64 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1095,11 +1095,14 @@ private function changed($request, $prop='dc:created') //$this->setLanguageProperties($request->getLang()); $vocab = $request->getVocab(); $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; - $contentLang = ($request->getContentLang() != null) ? $request->getContentLang() : $request->getLang(); - $changeList = $vocab->getChangeList($prop, $contentLang, $request->getLang(), $offset); + $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset); return $this->returnJson(array_merge_recursive($this->context, - array('@context' => array('@language' => $request->getLang())), + 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#date') ) + ), array('changeList' => $changeList))); } diff --git a/controller/WebController.php b/controller/WebController.php index ee547c8f4..3233647c1 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -563,7 +563,15 @@ public function invokeChangeList($request, $prop='dc:created') $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); + $changeList = $vocab->getChangeList($prop, $request->getContentLang(), $offset); + + $bydate = array(); + foreach($changeList as $concept) { + $dateTime = Punic\Calendar::toDateTime($concept['date']); + $concept['datestring'] = Punic\Calendar::formatDate($dateTime, 'medium', $request->getLang()); + $bydate[Punic\Calendar::getMonthName($dateTime, 'wide', $request->getLang(), true) . Punic\Calendar::format($dateTime, ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; + } + // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -573,7 +581,7 @@ public function invokeChangeList($request, $prop='dc:created') 'vocab' => $vocab, 'languages' => $this->languages, 'request' => $request, - 'changeList' => $changeList) + 'changeList' => $bydate) ); } diff --git a/model/Vocabulary.php b/model/Vocabulary.php index a671f2598..2849c14d7 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -619,15 +619,9 @@ public function verifyVocabularyLanguage($lang) * @param string $lang UI language for the dates * @return Array */ - public function getChangeList($prop, $clang, $lang, $offset) - { - $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; + public function getChangeList($prop, $clang, $offset) + { + return $this->getSparql()->queryChangeList($clang, $offset, $prop); } public function getTitle($lang=null) { diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 4a2e7a830..5c38ecbca 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,7 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->getValue(); + $concept['date'] = $row->date->__toString(); } $ret[] = $concept; diff --git a/rest.php b/rest.php index 86066dcf4..ddd884fcd 100644 --- a/rest.php +++ b/rest.php @@ -97,9 +97,9 @@ $controller->groups($request); } elseif ($parts[2] == 'groupMembers') { $controller->groupMembers($request); - } elseif ($parts[2] == 'newConcepts') { + } elseif ($parts[2] == 'new') { $controller->newConcepts($request); - } elseif ($parts[2] == 'modifiedConcepts') { + } elseif ($parts[2] == 'modified') { $controller->modifiedConcepts($request); } else { header("HTTP/1.0 404 Not Found"); From c1773816bb9b025d9ca3396e6c991e8f11abc303 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 14:04:52 +0300 Subject: [PATCH 03/24] Amended tests to reflect the change in functionality --- tests/VocabularyTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index ae84610cd..98e290153 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -433,10 +433,9 @@ public function testGetTopConcepts() { */ public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); - $months = $vocab->getChangeList('dc11:created','en', 'en', 0); - $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); - $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); - $this->assertEquals($expected, $months['February 2010']); + $changeList = $vocab->getChangeList('dc11:created','en', 0); + $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => '2010-02-12T10:26:39'); + $this->assertEquals($expected, $changeList[1]); } /** From 65ea798eb39ea966d7c1b005c38fe17203c5f2d5 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 18:11:56 +0300 Subject: [PATCH 04/24] Timestamps passed from vocabulary as native PHP dateTimes, then processed by each controller to the format they need --- controller/RestController.php | 8 +++++++- controller/WebController.php | 30 ++++++++++++++++++------------ model/sparql/GenericSparql.php | 2 +- tests/VocabularyTest.php | 2 +- tests/WebControllerTest.php | 26 ++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index b052aed64..4c0fce9aa 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1097,13 +1097,19 @@ private function changed($request, $prop='dc:created') $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset); + $simpleChangeList = array(); + foreach($changeList as $conceptInfo) { + $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], + 'prefLabel' => $conceptInfo['prefLabel'], + 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + } 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#date') ) ), - array('changeList' => $changeList))); + array('changeList' => $simpleChangeList))); } } diff --git a/controller/WebController.php b/controller/WebController.php index 3233647c1..6220f5b5e 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,18 +559,7 @@ 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(), $offset); - - $bydate = array(); - foreach($changeList as $concept) { - $dateTime = Punic\Calendar::toDateTime($concept['date']); - $concept['datestring'] = Punic\Calendar::formatDate($dateTime, 'medium', $request->getLang()); - $bydate[Punic\Calendar::getMonthName($dateTime, 'wide', $request->getLang(), true) . Punic\Calendar::format($dateTime, ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; - } + $bydate = $this->formatChangeList($request, $prop); // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -585,4 +574,21 @@ public function invokeChangeList($request, $prop='dc:created') ); } + public function formatChangeList($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(), $offset); + + $formatByDate = array(); + foreach($changeList as $concept) { + $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); + $formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $request->getLang(), true) . Punic\Calendar::format($concept['date'], ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; + } + return $formatByDate; + } + } diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 5c38ecbca..4a2e7a830 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,7 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->__toString(); + $concept['date'] = $row->date->getValue(); } $ret[] = $concept; diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index 98e290153..86dadd2ec 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -434,7 +434,7 @@ public function testGetTopConcepts() { public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); $changeList = $vocab->getChangeList('dc11:created','en', 0); - $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => '2010-02-12T10:26:39'); + $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))); $this->assertEquals($expected, $changeList[1]); } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index f9d401b41..44cb2987f 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -4,6 +4,14 @@ class WebControllerTest extends TestCase { + private $controller; + private $model; + + protected function setUp() { + $globalConfig = new GlobalConfig('/../tests/testconfig.ttl'); + $this->model = Mockery::mock(new Model($globalConfig)); + $this->controller = new WebController($this->model); + } /** * Data for testGetGitModifiedDateCacheEnabled and for testGetConfigModifiedDate. We are able to use the @@ -199,4 +207,22 @@ public function testGetModifiedDate($concept, $git, $config, $modifiedDate) $returnedValue = $controller->getModifiedDate($modifiable); $this->assertEquals($modifiedDate, $returnedValue); } + + /** + * @covers WebController::formatChangeList + */ + public function testFormatChangeList() { + $request = new Request($this->model); + $request->setVocab('changes'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); + + $months =$this->controller->formatChangeList($request, 'dc11:created'); + + $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); + $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); + $this->assertEquals($expected, $months['February 2010']); + } + } From ce77bc69c1d0a306422be639a854ad6fb6deeb1d Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 09:49:20 +0300 Subject: [PATCH 05/24] Added handling of malformed date strings and tests --- controller/RestController.php | 10 +++++----- controller/WebController.php | 4 +--- model/sparql/GenericSparql.php | 6 +++++- tests/RestControllerTest.php | 29 +++++++++++++++++++++++++++++ tests/WebControllerTest.php | 6 +++--- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index 4c0fce9aa..ac2e690a5 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1091,17 +1091,17 @@ public function modifiedConcepts($request) */ private function changed($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->getLang(), $offset); $simpleChangeList = array(); foreach($changeList as $conceptInfo) { - $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], - 'prefLabel' => $conceptInfo['prefLabel'], - 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + if (array_key_exists('date', $conceptInfo)) { + $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], + 'prefLabel' => $conceptInfo['prefLabel'], + 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + } } return $this->returnJson(array_merge_recursive($this->context, array('@context' => array( '@language' => $request->getLang(), diff --git a/controller/WebController.php b/controller/WebController.php index 6220f5b5e..19d7fecc4 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,7 +559,7 @@ public function invokeGenericErrorPage($request, $message = null) */ public function invokeChangeList($request, $prop='dc:created') { - $bydate = $this->formatChangeList($request, $prop); + $bydate = $this->formatChangeList($request, $prop='dc:created'); // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -575,10 +575,8 @@ public function invokeChangeList($request, $prop='dc:created') } public function formatChangeList($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(), $offset); diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 4a2e7a830..8088ef8ff 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,11 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->getValue(); + try { + $concept['date'] = $row->date->getValue(); + } catch (Exception $e) { + //don't do anything to malformed dates e.g. 1986-21-00 + } } $ret[] = $concept; diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index e5180d00c..89f22ff62 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -340,4 +340,33 @@ public function testLabelNoConcept() { $this->assertEquals($expected, $out); } + /** + * @covers RestController::newConcepts + */ + public function testNewConcepts() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); + + $this->controller->modifiedConcepts($request); + $changeList = $this->getActualOutput(); + + $expected = <<assertJsonStringEqualsJsonString($changeList, $expected); + + } } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index 44cb2987f..58a6cc336 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -4,13 +4,13 @@ class WebControllerTest extends TestCase { - private $controller; + private $webController; private $model; protected function setUp() { $globalConfig = new GlobalConfig('/../tests/testconfig.ttl'); $this->model = Mockery::mock(new Model($globalConfig)); - $this->controller = new WebController($this->model); + $this->webController = new WebController($this->model); } /** @@ -218,7 +218,7 @@ public function testFormatChangeList() { $request->setContentLang('en'); $request->setQueryParam('offset', '0'); - $months =$this->controller->formatChangeList($request, 'dc11:created'); + $months =$this->webController->formatChangeList($request, 'dc11:created'); $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); From 80bde3363ff1475bb0a6fa14470f75f230534acd Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 10:10:40 +0300 Subject: [PATCH 06/24] Fixed a method argument --- controller/WebController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/WebController.php b/controller/WebController.php index 19d7fecc4..88c1d5f9c 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,7 +559,7 @@ public function invokeGenericErrorPage($request, $message = null) */ public function invokeChangeList($request, $prop='dc:created') { - $bydate = $this->formatChangeList($request, $prop='dc:created'); + $bydate = $this->formatChangeList($request, $prop); // load template $template = $this->twig->loadTemplate('changes.twig'); From 1b672e196ae5c619581c07c45678ecf2f22dc379 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 10:15:01 +0300 Subject: [PATCH 07/24] Fixed a method argument --- controller/WebController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/WebController.php b/controller/WebController.php index 88c1d5f9c..58c499cbe 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -567,7 +567,7 @@ public function invokeChangeList($request, $prop='dc:created') // render template echo $template->render( array( - 'vocab' => $vocab, + 'vocab' => $request->getVocab(), 'languages' => $this->languages, 'request' => $request, 'changeList' => $bydate) From 852dedc775070674658f0b1ce7cc630ddad94733 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 11:04:39 +0300 Subject: [PATCH 08/24] using a PHP 7.1 compatible way for formating DateTime object --- controller/RestController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/RestController.php b/controller/RestController.php index ac2e690a5..a6bbd1d21 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1100,7 +1100,7 @@ private function changed($request, $prop='dc:created') if (array_key_exists('date', $conceptInfo)) { $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], 'prefLabel' => $conceptInfo['prefLabel'], - 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + 'date' => $conceptInfo['date']->format("Y-m-d\TH:i:sO") ); } } return $this->returnJson(array_merge_recursive($this->context, From be3076cddf2d2dabb1cbdf9505812f327a7af8d1 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 14:06:59 +0300 Subject: [PATCH 09/24] Numerous style tweaks. Added a limit parameter to parameterize the size of the list of changed concepts. --- controller/RestController.php | 11 ++++++----- controller/WebController.php | 26 +++++++++++++++++++++++--- model/Vocabulary.php | 4 ++-- model/sparql/GenericSparql.php | 8 ++++---- tests/GenericSparqlTest.php | 2 +- tests/RestControllerTest.php | 2 +- tests/VocabularyTest.php | 2 +- 7 files changed, 38 insertions(+), 17 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index a6bbd1d21..fb5602459 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1071,7 +1071,7 @@ public function related($request) */ public function newConcepts($request) { - return $this->changed($request); + return $this->changedConcepts($request, 'dc:created'); } /** @@ -1081,7 +1081,7 @@ public function newConcepts($request) */ public function modifiedConcepts($request) { - return $this->changed($request, 'dc:modified'); + return $this->changedConcepts($request, 'dc:modified'); } /** @@ -1089,11 +1089,12 @@ public function modifiedConcepts($request) * @param Request $request * @return object json-ld wrapped list of changed concepts */ - private function changed($request, $prop='dc:created') + private function changedConcepts($request, $prop) { $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->getLang(), $offset); + $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; + $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset, $limit); $simpleChangeList = array(); foreach($changeList as $conceptInfo) { @@ -1107,7 +1108,7 @@ private function changed($request, $prop='dc:created') 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#date') ) + 'date' => array( '@id' => 'http://purl.org/dc/terms/date', '@type' => 'http://www.w3.org/2001/XMLSchema#dateTime') ) ), array('changeList' => $simpleChangeList))); diff --git a/controller/WebController.php b/controller/WebController.php index 58c499cbe..4ffb3e1b8 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -573,14 +573,34 @@ public function invokeChangeList($request, $prop='dc:created') 'changeList' => $bydate) ); } - - public function formatChangeList($request, $prop='dc:created') { + /** + * 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'. + * @return Array list of concepts + */ + private function getChangeList($request, $prop) + { // 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(), $offset); + $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; + + return $vocab->getChangeList($prop, $request->getContentLang(), $offset, $limit); + } + + /** + * Formats the list of concepts as labels arranged by modification month + * @param Request $request + * @param string $prop the name of the property for a time stamp + * @return Array list of concept labels + */ + public function formatChangeList($request, $prop) + { + $changeList = $this->getChangeList($request, $prop); $formatByDate = array(); foreach($changeList as $concept) { $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); diff --git a/model/Vocabulary.php b/model/Vocabulary.php index 2849c14d7..c9a0c2a8d 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -619,9 +619,9 @@ public function verifyVocabularyLanguage($lang) * @param string $lang UI language for the dates * @return Array */ - public function getChangeList($prop, $clang, $offset) + public function getChangeList($prop, $clang, $offset, $limit) { - return $this->getSparql()->queryChangeList($clang, $offset, $prop); + return $this->getSparql()->queryChangeList($clang, $offset, $prop, $limit); } public function getTitle($lang=null) { diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 8088ef8ff..34b58396b 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2211,7 +2211,7 @@ public function listConceptGroupContents($groupClass, $group, $lang,$showDepreca * @param int $offset offset of results to retrieve; 0 for beginning of list * @return string sparql query */ - private function generateChangeListQuery($lang, $offset, $prop) { + private function generateChangeListQuery($lang, $offset, $prop, $limit=200) { $fcl = $this->generateFromClause(); $offset = ($offset) ? 'OFFSET ' . $offset : ''; @@ -2224,7 +2224,7 @@ 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; } @@ -2261,8 +2261,8 @@ private function transformChangeListResults($result) { * @param int $offset offset of results to retrieve; 0 for beginning of list * @return array Result array */ - public function queryChangeList($lang, $offset, $prop) { - $query = $this->generateChangeListQuery($lang, $offset, $prop); + public function queryChangeList($lang, $offset, $prop, $limit) { + $query = $this->generateChangeListQuery($lang, $offset, $prop, $limit); $result = $this->query($query); return $this->transformChangeListResults($result); } diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index d680a3dd3..d654bd24d 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -1098,7 +1098,7 @@ public function testQueryChangeList() $voc = $this->model->getVocabulary('changes'); $graph = $voc->getGraph(); $sparql = new GenericSparql('http://localhost:13030/skosmos-test/sparql', $graph, $this->model); - $actual = $sparql->queryChangeList('en', 0, 'dc11:created'); + $actual = $sparql->queryChangeList('en', 0, 'dc11:created', 10); $order = array(); foreach($actual as $concept) { array_push($order, $concept['prefLabel']); diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index 89f22ff62..033532e04 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -361,7 +361,7 @@ public function testNewConcepts() { "@language": "en", "prefLabel": "skos:prefLabel", "xsd": "http://www.w3.org/2001/XMLSchema#", - "date": { "@id":"http://purl.org/dc/terms/date","@type":"http://www.w3.org/2001/XMLSchema#date" } + "date": { "@id":"http://purl.org/dc/terms/date","@type":"http://www.w3.org/2001/XMLSchema#dateTime" } }, "changeList": [ { "uri":"http://www.skosmos.skos/test/ta123", "prefLabel":"multiple broaders", "date":"2014-10-01T16:29:03+0000" } ] } diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index 86dadd2ec..1ed1e0171 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -433,7 +433,7 @@ public function testGetTopConcepts() { */ public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); - $changeList = $vocab->getChangeList('dc11:created','en', 0); + $changeList = $vocab->getChangeList('dc11:created','en', 0, 5); $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))); $this->assertEquals($expected, $changeList[1]); } From 4dd782fc6564b6b841aac6c17524f0fdc4368451 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Wed, 6 May 2020 13:46:02 +0300 Subject: [PATCH 10/24] initial draft for the REST API methods returning new and modified concepts for a vocabulary --- controller/RestController.php | 40 +++++++++++++++++++++++++++++++++++ rest.php | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/controller/RestController.php b/controller/RestController.php index c62eb4216..fbafc5b56 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1063,4 +1063,44 @@ 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) + { + return $this->changed($request); + } + + /** + * Used for querying modified concepts in the vocabulary + * @param Request $request + * @return object json-ld wrapped list of changed concepts + */ + public function modifiedConcepts($request) + { + return $this->changed($request, 'dc:modified'); + } + + /** + * Used for querying changed concepts in the vocabulary + * @param Request $request + * @return object json-ld wrapped list of changed concepts + */ + private function changed($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; + $contentLang = ($request->getContentLang() != null) ? $request->getContentLang() : $request->getLang(); + $changeList = $vocab->getChangeList($prop, $contentLang, $request->getLang(), $offset); + + return $this->returnJson(array_merge_recursive($this->context, + array('@context' => array('@language' => $request->getLang())), + array('changeList' => $changeList))); + + } } diff --git a/rest.php b/rest.php index 5d276f105..86066dcf4 100644 --- a/rest.php +++ b/rest.php @@ -97,6 +97,10 @@ $controller->groups($request); } elseif ($parts[2] == 'groupMembers') { $controller->groupMembers($request); + } elseif ($parts[2] == 'newConcepts') { + $controller->newConcepts($request); + } elseif ($parts[2] == 'modifiedConcepts') { + $controller->modifiedConcepts($request); } else { header("HTTP/1.0 404 Not Found"); echo ("404 Not Found"); From cb1bf1031002c814cb52a556b222d675cd94d96b Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 13:06:35 +0300 Subject: [PATCH 11/24] Separated the functionality of WebController and RestController when forming the change list --- controller/RestController.php | 9 ++++++--- controller/WebController.php | 12 ++++++++++-- model/Vocabulary.php | 12 +++--------- model/sparql/GenericSparql.php | 2 +- rest.php | 4 ++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index fbafc5b56..b052aed64 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1095,11 +1095,14 @@ private function changed($request, $prop='dc:created') //$this->setLanguageProperties($request->getLang()); $vocab = $request->getVocab(); $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; - $contentLang = ($request->getContentLang() != null) ? $request->getContentLang() : $request->getLang(); - $changeList = $vocab->getChangeList($prop, $contentLang, $request->getLang(), $offset); + $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset); return $this->returnJson(array_merge_recursive($this->context, - array('@context' => array('@language' => $request->getLang())), + 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#date') ) + ), array('changeList' => $changeList))); } diff --git a/controller/WebController.php b/controller/WebController.php index ee547c8f4..3233647c1 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -563,7 +563,15 @@ public function invokeChangeList($request, $prop='dc:created') $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); + $changeList = $vocab->getChangeList($prop, $request->getContentLang(), $offset); + + $bydate = array(); + foreach($changeList as $concept) { + $dateTime = Punic\Calendar::toDateTime($concept['date']); + $concept['datestring'] = Punic\Calendar::formatDate($dateTime, 'medium', $request->getLang()); + $bydate[Punic\Calendar::getMonthName($dateTime, 'wide', $request->getLang(), true) . Punic\Calendar::format($dateTime, ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; + } + // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -573,7 +581,7 @@ public function invokeChangeList($request, $prop='dc:created') 'vocab' => $vocab, 'languages' => $this->languages, 'request' => $request, - 'changeList' => $changeList) + 'changeList' => $bydate) ); } diff --git a/model/Vocabulary.php b/model/Vocabulary.php index a671f2598..2849c14d7 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -619,15 +619,9 @@ public function verifyVocabularyLanguage($lang) * @param string $lang UI language for the dates * @return Array */ - public function getChangeList($prop, $clang, $lang, $offset) - { - $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; + public function getChangeList($prop, $clang, $offset) + { + return $this->getSparql()->queryChangeList($clang, $offset, $prop); } public function getTitle($lang=null) { diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 4a2e7a830..5c38ecbca 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,7 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->getValue(); + $concept['date'] = $row->date->__toString(); } $ret[] = $concept; diff --git a/rest.php b/rest.php index 86066dcf4..ddd884fcd 100644 --- a/rest.php +++ b/rest.php @@ -97,9 +97,9 @@ $controller->groups($request); } elseif ($parts[2] == 'groupMembers') { $controller->groupMembers($request); - } elseif ($parts[2] == 'newConcepts') { + } elseif ($parts[2] == 'new') { $controller->newConcepts($request); - } elseif ($parts[2] == 'modifiedConcepts') { + } elseif ($parts[2] == 'modified') { $controller->modifiedConcepts($request); } else { header("HTTP/1.0 404 Not Found"); From 8d7bbdb5e51b958917f4c574f8d235e13e27c589 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 14:04:52 +0300 Subject: [PATCH 12/24] Amended tests to reflect the change in functionality --- tests/VocabularyTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index ae84610cd..98e290153 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -433,10 +433,9 @@ public function testGetTopConcepts() { */ public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); - $months = $vocab->getChangeList('dc11:created','en', 'en', 0); - $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); - $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); - $this->assertEquals($expected, $months['February 2010']); + $changeList = $vocab->getChangeList('dc11:created','en', 0); + $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => '2010-02-12T10:26:39'); + $this->assertEquals($expected, $changeList[1]); } /** From 31a422f25d73a212ef41a7d6ee2a0d6373558d10 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 8 May 2020 18:11:56 +0300 Subject: [PATCH 13/24] Timestamps passed from vocabulary as native PHP dateTimes, then processed by each controller to the format they need --- controller/RestController.php | 8 +++++++- controller/WebController.php | 30 ++++++++++++++++++------------ model/sparql/GenericSparql.php | 2 +- tests/VocabularyTest.php | 2 +- tests/WebControllerTest.php | 26 ++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index b052aed64..4c0fce9aa 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1097,13 +1097,19 @@ private function changed($request, $prop='dc:created') $offset = ($request->getQueryParam('offset') && is_numeric($request->getQueryParam('offset')) && $request->getQueryParam('offset') >= 0) ? $request->getQueryParam('offset') : 0; $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset); + $simpleChangeList = array(); + foreach($changeList as $conceptInfo) { + $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], + 'prefLabel' => $conceptInfo['prefLabel'], + 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + } 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#date') ) ), - array('changeList' => $changeList))); + array('changeList' => $simpleChangeList))); } } diff --git a/controller/WebController.php b/controller/WebController.php index 3233647c1..6220f5b5e 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,18 +559,7 @@ 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(), $offset); - - $bydate = array(); - foreach($changeList as $concept) { - $dateTime = Punic\Calendar::toDateTime($concept['date']); - $concept['datestring'] = Punic\Calendar::formatDate($dateTime, 'medium', $request->getLang()); - $bydate[Punic\Calendar::getMonthName($dateTime, 'wide', $request->getLang(), true) . Punic\Calendar::format($dateTime, ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; - } + $bydate = $this->formatChangeList($request, $prop); // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -585,4 +574,21 @@ public function invokeChangeList($request, $prop='dc:created') ); } + public function formatChangeList($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(), $offset); + + $formatByDate = array(); + foreach($changeList as $concept) { + $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); + $formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $request->getLang(), true) . Punic\Calendar::format($concept['date'], ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $concept; + } + return $formatByDate; + } + } diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 5c38ecbca..4a2e7a830 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,7 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->__toString(); + $concept['date'] = $row->date->getValue(); } $ret[] = $concept; diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index 98e290153..86dadd2ec 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -434,7 +434,7 @@ public function testGetTopConcepts() { public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); $changeList = $vocab->getChangeList('dc11:created','en', 0); - $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => '2010-02-12T10:26:39'); + $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))); $this->assertEquals($expected, $changeList[1]); } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index f9d401b41..44cb2987f 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -4,6 +4,14 @@ class WebControllerTest extends TestCase { + private $controller; + private $model; + + protected function setUp() { + $globalConfig = new GlobalConfig('/../tests/testconfig.ttl'); + $this->model = Mockery::mock(new Model($globalConfig)); + $this->controller = new WebController($this->model); + } /** * Data for testGetGitModifiedDateCacheEnabled and for testGetConfigModifiedDate. We are able to use the @@ -199,4 +207,22 @@ public function testGetModifiedDate($concept, $git, $config, $modifiedDate) $returnedValue = $controller->getModifiedDate($modifiable); $this->assertEquals($modifiedDate, $returnedValue); } + + /** + * @covers WebController::formatChangeList + */ + public function testFormatChangeList() { + $request = new Request($this->model); + $request->setVocab('changes'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); + + $months =$this->controller->formatChangeList($request, 'dc11:created'); + + $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); + $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); + $this->assertEquals($expected, $months['February 2010']); + } + } From a3482bc81fb674675e0afc3d05189099f62ed3b7 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 09:49:20 +0300 Subject: [PATCH 14/24] Added handling of malformed date strings and tests --- controller/RestController.php | 10 +++++----- controller/WebController.php | 4 +--- model/sparql/GenericSparql.php | 6 +++++- tests/RestControllerTest.php | 29 +++++++++++++++++++++++++++++ tests/WebControllerTest.php | 6 +++--- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index 4c0fce9aa..ac2e690a5 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1091,17 +1091,17 @@ public function modifiedConcepts($request) */ private function changed($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->getLang(), $offset); $simpleChangeList = array(); foreach($changeList as $conceptInfo) { - $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], - 'prefLabel' => $conceptInfo['prefLabel'], - 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + if (array_key_exists('date', $conceptInfo)) { + $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], + 'prefLabel' => $conceptInfo['prefLabel'], + 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + } } return $this->returnJson(array_merge_recursive($this->context, array('@context' => array( '@language' => $request->getLang(), diff --git a/controller/WebController.php b/controller/WebController.php index 6220f5b5e..19d7fecc4 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,7 +559,7 @@ public function invokeGenericErrorPage($request, $message = null) */ public function invokeChangeList($request, $prop='dc:created') { - $bydate = $this->formatChangeList($request, $prop); + $bydate = $this->formatChangeList($request, $prop='dc:created'); // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -575,10 +575,8 @@ public function invokeChangeList($request, $prop='dc:created') } public function formatChangeList($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(), $offset); diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 4a2e7a830..8088ef8ff 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2243,7 +2243,11 @@ private function transformChangeListResults($result) { } if (isset($row->date)) { - $concept['date'] = $row->date->getValue(); + try { + $concept['date'] = $row->date->getValue(); + } catch (Exception $e) { + //don't do anything to malformed dates e.g. 1986-21-00 + } } $ret[] = $concept; diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index e5180d00c..89f22ff62 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -340,4 +340,33 @@ public function testLabelNoConcept() { $this->assertEquals($expected, $out); } + /** + * @covers RestController::newConcepts + */ + public function testNewConcepts() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); + + $this->controller->modifiedConcepts($request); + $changeList = $this->getActualOutput(); + + $expected = <<assertJsonStringEqualsJsonString($changeList, $expected); + + } } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index 44cb2987f..58a6cc336 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -4,13 +4,13 @@ class WebControllerTest extends TestCase { - private $controller; + private $webController; private $model; protected function setUp() { $globalConfig = new GlobalConfig('/../tests/testconfig.ttl'); $this->model = Mockery::mock(new Model($globalConfig)); - $this->controller = new WebController($this->model); + $this->webController = new WebController($this->model); } /** @@ -218,7 +218,7 @@ public function testFormatChangeList() { $request->setContentLang('en'); $request->setQueryParam('offset', '0'); - $months =$this->controller->formatChangeList($request, 'dc11:created'); + $months =$this->webController->formatChangeList($request, 'dc11:created'); $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); From 02c9b04b0c3ca98afb4b7c693dd3af4c240a8bf7 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 10:10:40 +0300 Subject: [PATCH 15/24] Fixed a method argument --- controller/WebController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/WebController.php b/controller/WebController.php index 19d7fecc4..88c1d5f9c 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,7 +559,7 @@ public function invokeGenericErrorPage($request, $message = null) */ public function invokeChangeList($request, $prop='dc:created') { - $bydate = $this->formatChangeList($request, $prop='dc:created'); + $bydate = $this->formatChangeList($request, $prop); // load template $template = $this->twig->loadTemplate('changes.twig'); From 8be9f703a85b0810c2ca208d63dc403620c6ad76 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 10:15:01 +0300 Subject: [PATCH 16/24] Fixed a method argument --- controller/WebController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/WebController.php b/controller/WebController.php index 88c1d5f9c..58c499cbe 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -567,7 +567,7 @@ public function invokeChangeList($request, $prop='dc:created') // render template echo $template->render( array( - 'vocab' => $vocab, + 'vocab' => $request->getVocab(), 'languages' => $this->languages, 'request' => $request, 'changeList' => $bydate) From d209a45c51471ec57299958cbba9917c79a1056c Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 11:04:39 +0300 Subject: [PATCH 17/24] using a PHP 7.1 compatible way for formating DateTime object --- controller/RestController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/RestController.php b/controller/RestController.php index ac2e690a5..a6bbd1d21 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1100,7 +1100,7 @@ private function changed($request, $prop='dc:created') if (array_key_exists('date', $conceptInfo)) { $simpleChangeList[] = array( 'uri' => $conceptInfo['uri'], 'prefLabel' => $conceptInfo['prefLabel'], - 'date' => $conceptInfo['date']->format(DateTimeInterface::ISO8601) ); + 'date' => $conceptInfo['date']->format("Y-m-d\TH:i:sO") ); } } return $this->returnJson(array_merge_recursive($this->context, From 52c84dcf0b622f39f551a4825e36f73754c4a134 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Tue, 12 May 2020 14:06:59 +0300 Subject: [PATCH 18/24] Numerous style tweaks. Added a limit parameter to parameterize the size of the list of changed concepts. --- controller/RestController.php | 11 ++++++----- controller/WebController.php | 26 +++++++++++++++++++++++--- model/Vocabulary.php | 4 ++-- model/sparql/GenericSparql.php | 8 ++++---- tests/GenericSparqlTest.php | 2 +- tests/RestControllerTest.php | 2 +- tests/VocabularyTest.php | 2 +- 7 files changed, 38 insertions(+), 17 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index a6bbd1d21..fb5602459 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1071,7 +1071,7 @@ public function related($request) */ public function newConcepts($request) { - return $this->changed($request); + return $this->changedConcepts($request, 'dc:created'); } /** @@ -1081,7 +1081,7 @@ public function newConcepts($request) */ public function modifiedConcepts($request) { - return $this->changed($request, 'dc:modified'); + return $this->changedConcepts($request, 'dc:modified'); } /** @@ -1089,11 +1089,12 @@ public function modifiedConcepts($request) * @param Request $request * @return object json-ld wrapped list of changed concepts */ - private function changed($request, $prop='dc:created') + private function changedConcepts($request, $prop) { $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->getLang(), $offset); + $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; + $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset, $limit); $simpleChangeList = array(); foreach($changeList as $conceptInfo) { @@ -1107,7 +1108,7 @@ private function changed($request, $prop='dc:created') 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#date') ) + 'date' => array( '@id' => 'http://purl.org/dc/terms/date', '@type' => 'http://www.w3.org/2001/XMLSchema#dateTime') ) ), array('changeList' => $simpleChangeList))); diff --git a/controller/WebController.php b/controller/WebController.php index 58c499cbe..4ffb3e1b8 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -573,14 +573,34 @@ public function invokeChangeList($request, $prop='dc:created') 'changeList' => $bydate) ); } - - public function formatChangeList($request, $prop='dc:created') { + /** + * 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'. + * @return Array list of concepts + */ + private function getChangeList($request, $prop) + { // 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(), $offset); + $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; + + return $vocab->getChangeList($prop, $request->getContentLang(), $offset, $limit); + } + + /** + * Formats the list of concepts as labels arranged by modification month + * @param Request $request + * @param string $prop the name of the property for a time stamp + * @return Array list of concept labels + */ + public function formatChangeList($request, $prop) + { + $changeList = $this->getChangeList($request, $prop); $formatByDate = array(); foreach($changeList as $concept) { $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); diff --git a/model/Vocabulary.php b/model/Vocabulary.php index 2849c14d7..c9a0c2a8d 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -619,9 +619,9 @@ public function verifyVocabularyLanguage($lang) * @param string $lang UI language for the dates * @return Array */ - public function getChangeList($prop, $clang, $offset) + public function getChangeList($prop, $clang, $offset, $limit) { - return $this->getSparql()->queryChangeList($clang, $offset, $prop); + return $this->getSparql()->queryChangeList($clang, $offset, $prop, $limit); } public function getTitle($lang=null) { diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 8088ef8ff..34b58396b 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2211,7 +2211,7 @@ public function listConceptGroupContents($groupClass, $group, $lang,$showDepreca * @param int $offset offset of results to retrieve; 0 for beginning of list * @return string sparql query */ - private function generateChangeListQuery($lang, $offset, $prop) { + private function generateChangeListQuery($lang, $offset, $prop, $limit=200) { $fcl = $this->generateFromClause(); $offset = ($offset) ? 'OFFSET ' . $offset : ''; @@ -2224,7 +2224,7 @@ 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; } @@ -2261,8 +2261,8 @@ private function transformChangeListResults($result) { * @param int $offset offset of results to retrieve; 0 for beginning of list * @return array Result array */ - public function queryChangeList($lang, $offset, $prop) { - $query = $this->generateChangeListQuery($lang, $offset, $prop); + public function queryChangeList($lang, $offset, $prop, $limit) { + $query = $this->generateChangeListQuery($lang, $offset, $prop, $limit); $result = $this->query($query); return $this->transformChangeListResults($result); } diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index d680a3dd3..d654bd24d 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -1098,7 +1098,7 @@ public function testQueryChangeList() $voc = $this->model->getVocabulary('changes'); $graph = $voc->getGraph(); $sparql = new GenericSparql('http://localhost:13030/skosmos-test/sparql', $graph, $this->model); - $actual = $sparql->queryChangeList('en', 0, 'dc11:created'); + $actual = $sparql->queryChangeList('en', 0, 'dc11:created', 10); $order = array(); foreach($actual as $concept) { array_push($order, $concept['prefLabel']); diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index 89f22ff62..033532e04 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -361,7 +361,7 @@ public function testNewConcepts() { "@language": "en", "prefLabel": "skos:prefLabel", "xsd": "http://www.w3.org/2001/XMLSchema#", - "date": { "@id":"http://purl.org/dc/terms/date","@type":"http://www.w3.org/2001/XMLSchema#date" } + "date": { "@id":"http://purl.org/dc/terms/date","@type":"http://www.w3.org/2001/XMLSchema#dateTime" } }, "changeList": [ { "uri":"http://www.skosmos.skos/test/ta123", "prefLabel":"multiple broaders", "date":"2014-10-01T16:29:03+0000" } ] } diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index 86dadd2ec..1ed1e0171 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -433,7 +433,7 @@ public function testGetTopConcepts() { */ public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); - $changeList = $vocab->getChangeList('dc11:created','en', 0); + $changeList = $vocab->getChangeList('dc11:created','en', 0, 5); $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))); $this->assertEquals($expected, $changeList[1]); } From 2b5a423a58e0d6d67d10fdd4b370e7ab765fd0f2 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Wed, 10 Jun 2020 09:17:08 +0300 Subject: [PATCH 19/24] Refactored methods, added swagger documentation --- controller/RestController.php | 19 +++-- controller/WebController.php | 16 ++-- model/Vocabulary.php | 4 +- swagger.json | 144 ++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 16 deletions(-) diff --git a/controller/RestController.php b/controller/RestController.php index fb5602459..f9366cfcf 100644 --- a/controller/RestController.php +++ b/controller/RestController.php @@ -1071,7 +1071,10 @@ public function related($request) */ public function newConcepts($request) { - return $this->changedConcepts($request, 'dc:created'); + $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); } /** @@ -1081,20 +1084,22 @@ public function newConcepts($request) */ public function modifiedConcepts($request) { - return $this->changedConcepts($request, 'dc:modified'); + $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) + private function changedConcepts($request, $prop, $offset, $limit) { - $vocab = $request->getVocab(); - $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; - $changeList = $vocab->getChangeList($prop, $request->getLang(), $offset, $limit); + $changeList = $request->getVocab()->getChangeList($prop, $request->getLang(), $offset, $limit); $simpleChangeList = array(); foreach($changeList as $conceptInfo) { diff --git a/controller/WebController.php b/controller/WebController.php index 4ffb3e1b8..8b066bc00 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -577,19 +577,16 @@ public function invokeChangeList($request, $prop='dc:created') * 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 */ - private function getChangeList($request, $prop) + private function getChangeList($request, $prop, $offset=0, $limit=200) { // 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; - $limit = ($request->getQueryParam('limit') && is_numeric($request->getQueryParam('limit')) && $request->getQueryParam('limit') >= 0) ? $request->getQueryParam('limit') : 200; - - - return $vocab->getChangeList($prop, $request->getContentLang(), $offset, $limit); + return $request->getVocab()->getChangeList($prop, $request->getContentLang(), $offset, $limit); } /** @@ -600,7 +597,10 @@ private function getChangeList($request, $prop) */ public function formatChangeList($request, $prop) { - $changeList = $this->getChangeList($request, $prop); + $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; + + $changeList = $this->getChangeList($request, $prop, $offset, $limit); $formatByDate = array(); foreach($changeList as $concept) { $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); diff --git a/model/Vocabulary.php b/model/Vocabulary.php index c9a0c2a8d..d2e310b3f 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -615,8 +615,10 @@ 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, $offset, $limit) diff --git a/swagger.json b/swagger.json index 37e43070c..c191747cd 100644 --- a/swagger.json +++ b/swagger.json @@ -1121,6 +1121,116 @@ ] } }, + "/{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" + } + }, + "304": { + "description": "the resource was not modified, so there is no need to retransmit the requested resources" + }, + "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" + } + }, + "304": { + "description": "the resource was not modified, so there is no need to retransmit the requested resources" + }, + "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", @@ -2281,6 +2391,40 @@ "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" + } } } } \ No newline at end of file From a171d68ff71d8daaa0e34d743272c5836bae11c8 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 12 Jun 2020 11:44:54 +0300 Subject: [PATCH 20/24] cleaning up the code --- controller/WebController.php | 21 ++++++++++----------- model/Vocabulary.php | 2 +- model/sparql/GenericSparql.php | 12 ++++++++---- swagger.json | 18 ++++++++---------- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/controller/WebController.php b/controller/WebController.php index 8b066bc00..49019681e 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -559,7 +559,11 @@ public function invokeGenericErrorPage($request, $message = null) */ public function invokeChangeList($request, $prop='dc:created') { - $bydate = $this->formatChangeList($request, $prop); + $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; + + $changeList = $this->getChangeList($request, $prop, $offset, $limit); + $bydate = $this->formatChangeList($changeList, $request->getLang()); // load template $template = $this->twig->loadTemplate('changes.twig'); @@ -591,20 +595,15 @@ private function getChangeList($request, $prop, $offset=0, $limit=200) /** * Formats the list of concepts as labels arranged by modification month - * @param Request $request - * @param string $prop the name of the property for a time stamp - * @return Array list of concept labels + * @param Array $changeList + * @param string $lang the language for displaying dates in the change list */ - public function formatChangeList($request, $prop) + public function formatChangeList($changeList, $lang) { - $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; - - $changeList = $this->getChangeList($request, $prop, $offset, $limit); $formatByDate = array(); foreach($changeList as $concept) { - $concept['datestring'] = Punic\Calendar::formatDate($concept['date'], 'medium', $request->getLang()); - $formatByDate[Punic\Calendar::getMonthName($concept['date'], 'wide', $request->getLang(), true) . Punic\Calendar::format($concept['date'], ' y', $request->getLang()) ][strtolower($concept['prefLabel'])] = $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; } diff --git a/model/Vocabulary.php b/model/Vocabulary.php index d2e310b3f..abd25df95 100644 --- a/model/Vocabulary.php +++ b/model/Vocabulary.php @@ -623,7 +623,7 @@ public function verifyVocabularyLanguage($lang) */ public function getChangeList($prop, $clang, $offset, $limit) { - return $this->getSparql()->queryChangeList($clang, $offset, $prop, $limit); + return $this->getSparql()->queryChangeList($prop, $clang, $offset, $limit); } public function getTitle($lang=null) { diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 34b58396b..a2e536de1 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -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, $limit=200) { + private function generateChangeListQuery($prop, $lang, $offset, $limit=200) { $fcl = $this->generateFromClause(); $offset = ($offset) ? 'OFFSET ' . $offset : ''; @@ -2257,12 +2259,14 @@ 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, $limit) { - $query = $this->generateChangeListQuery($lang, $offset, $prop, $limit); + public function queryChangeList($prop, $lang, $offset, $limit) { + $query = $this->generateChangeListQuery($prop, $lang, $offset, $limit); $result = $this->query($query); return $this->transformChangeListResults($result); } diff --git a/swagger.json b/swagger.json index c191747cd..7bfbe25ee 100644 --- a/swagger.json +++ b/swagger.json @@ -1164,9 +1164,6 @@ "$ref": "#/definitions/changedConceptsResult" } }, - "304": { - "description": "the resource was not modified, so there is no need to retransmit the requested resources" - }, "404": { "description": "no vocabulary could be found with the requested id" } @@ -1219,9 +1216,6 @@ "$ref": "#/definitions/changedConceptsResult" } }, - "304": { - "description": "the resource was not modified, so there is no need to retransmit the requested resources" - }, "404": { "description": "no vocabulary could be found with the requested id" } @@ -2421,10 +2415,14 @@ "date": { "type": "string", "format": "date-time", - "description": "time stamp" - }, - "required": "-uri -prefLabel -date" - } + "description": "Time stamp" + } + }, + "required": [ + "uri", + "prefLabel", + "date" + ] } } } \ No newline at end of file From 4d84b21b3520d81acdd37463694b6e1e45b6e1d4 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 12 Jun 2020 14:04:12 +0300 Subject: [PATCH 21/24] Added tests. Fixed abiguity between the namespace prefixes dc, dct, dc11. --- controller/WebController.php | 6 +-- model/sparql/GenericSparql.php | 2 + tests/GenericSparqlTest.php | 2 +- tests/RestControllerTest.php | 71 ++++++++++++++++++++++++++----- tests/WebControllerTest.php | 3 +- tests/test-vocab-data/changes.ttl | 2 +- 6 files changed, 70 insertions(+), 16 deletions(-) diff --git a/controller/WebController.php b/controller/WebController.php index 49019681e..37ed988b2 100644 --- a/controller/WebController.php +++ b/controller/WebController.php @@ -585,7 +585,7 @@ public function invokeChangeList($request, $prop='dc:created') * @param int $limit maximum number of concepts to return * @return Array list of concepts */ - private function getChangeList($request, $prop, $offset=0, $limit=200) + public function getChangeList($request, $prop, $offset=0, $limit=200) { // set language parameters for gettext $this->setLanguageProperties($request->getLang()); @@ -602,8 +602,8 @@ 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; + $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; } diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index a2e536de1..f91c00621 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2228,6 +2228,7 @@ private function generateChangeListQuery($prop, $lang, $offset, $limit=200) { ORDER BY DESC(YEAR(?date)) DESC(MONTH(?date)) LCASE(?label) LIMIT $limit $offset EOQ; + return $query; } @@ -2267,6 +2268,7 @@ private function transformChangeListResults($result) { */ public function queryChangeList($prop, $lang, $offset, $limit) { $query = $this->generateChangeListQuery($prop, $lang, $offset, $limit); + $result = $this->query($query); return $this->transformChangeListResults($result); } diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index d654bd24d..965a5b8a6 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -1098,7 +1098,7 @@ public function testQueryChangeList() $voc = $this->model->getVocabulary('changes'); $graph = $voc->getGraph(); $sparql = new GenericSparql('http://localhost:13030/skosmos-test/sparql', $graph, $this->model); - $actual = $sparql->queryChangeList('en', 0, 'dc11:created', 10); + $actual = $sparql->queryChangeList('dc11:created', 'en', 0, 10); $order = array(); foreach($actual as $concept) { array_push($order, $concept['prefLabel']); diff --git a/tests/RestControllerTest.php b/tests/RestControllerTest.php index 033532e04..fbcb2ae9f 100644 --- a/tests/RestControllerTest.php +++ b/tests/RestControllerTest.php @@ -344,16 +344,16 @@ public function testLabelNoConcept() { * @covers RestController::newConcepts */ public function testNewConcepts() { - $request = new Request($this->model); - $request->setVocab('test'); - $request->setLang('en'); - $request->setContentLang('en'); - $request->setQueryParam('offset', '0'); + $request = new Request($this->model); + $request->setVocab('changes'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); - $this->controller->modifiedConcepts($request); - $changeList = $this->getActualOutput(); + $this->controller->newConcepts($request); + $changeList = $this->getActualOutput(); - $expected = <<assertJsonStringEqualsJsonString($changeList, $expected); + $this->assertJsonStringEqualsJsonString($changeList, $expected); } + + /** + * @covers RestController::modifiedConcepts + */ + public function testModifiedConcepts() { + $request = new Request($this->model); + $request->setVocab('test'); + $request->setLang('en'); + $request->setContentLang('en'); + $request->setQueryParam('offset', '0'); + + $this->controller->modifiedConcepts($request); + $changeList = $this->getActualOutput(); + + $expected = <<assertJsonStringEqualsJsonString($changeList, $expected); + + } } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index 58a6cc336..d7f2c5e5c 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -218,7 +218,8 @@ public function testFormatChangeList() { $request->setContentLang('en'); $request->setQueryParam('offset', '0'); - $months =$this->webController->formatChangeList($request, 'dc11:created'); + $changeList = $this->webController->getChangeList($request, 'dc11:created'); + $months =$this->webController->formatChangeList($changeList, 'en'); $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); diff --git a/tests/test-vocab-data/changes.ttl b/tests/test-vocab-data/changes.ttl index d171d51dd..2ba70c3f6 100644 --- a/tests/test-vocab-data/changes.ttl +++ b/tests/test-vocab-data/changes.ttl @@ -1,4 +1,4 @@ -@prefix dc: . +@prefix dc: . @prefix changes: . @prefix meta: . @prefix owl: . From e5c649d666e6ca3c3421ae25110097ad162bb872 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 12 Jun 2020 14:28:45 +0300 Subject: [PATCH 22/24] created & modified properties moved to the correct namespace --- tests/GenericSparqlTest.php | 2 +- tests/VocabularyTest.php | 2 +- tests/WebControllerTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index 965a5b8a6..125e2413d 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -1098,7 +1098,7 @@ public function testQueryChangeList() $voc = $this->model->getVocabulary('changes'); $graph = $voc->getGraph(); $sparql = new GenericSparql('http://localhost:13030/skosmos-test/sparql', $graph, $this->model); - $actual = $sparql->queryChangeList('dc11:created', 'en', 0, 10); + $actual = $sparql->queryChangeList('dc:created', 'en', 0, 10); $order = array(); foreach($actual as $concept) { array_push($order, $concept['prefLabel']); diff --git a/tests/VocabularyTest.php b/tests/VocabularyTest.php index 1ed1e0171..1c1decaa2 100644 --- a/tests/VocabularyTest.php +++ b/tests/VocabularyTest.php @@ -433,7 +433,7 @@ public function testGetTopConcepts() { */ public function testGetChangeList() { $vocab = $this->model->getVocabulary('changes'); - $changeList = $vocab->getChangeList('dc11:created','en', 0, 5); + $changeList = $vocab->getChangeList('dc:created','en', 0, 5); $expected = array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))); $this->assertEquals($expected, $changeList[1]); } diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index d7f2c5e5c..6396c3354 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -218,7 +218,7 @@ public function testFormatChangeList() { $request->setContentLang('en'); $request->setQueryParam('offset', '0'); - $changeList = $this->webController->getChangeList($request, 'dc11:created'); + $changeList = $this->webController->getChangeList($request, 'dc:created'); $months =$this->webController->formatChangeList($changeList, 'en'); $expected = array ('hurr durr' => array ('uri' => 'http://www.skosmos.skos/changes/d3', 'prefLabel' => 'Hurr Durr', 'date' => DateTime::__set_state(array('date' => '2010-02-12 10:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010'), 'second date' => array ('uri' => 'http://www.skosmos.skos/changes/d2', 'prefLabel' => 'Second date', 'date' => DateTime::__set_state(array('date' => '2010-02-12 15:26:39.000000', 'timezone_type' => 3, 'timezone' => 'UTC')), 'datestring' => 'Feb 12, 2010')); From 053b065219cb4016e3bd77751d2155adfe941297 Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Fri, 12 Jun 2020 19:54:42 +0300 Subject: [PATCH 23/24] Handling and tests for malformed dates --- model/sparql/GenericSparql.php | 3 ++- tests/GenericSparqlTest.php | 17 +++++++++++++++++ tests/WebControllerTest.php | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index f91c00621..d333a6d8f 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2249,7 +2249,8 @@ private function transformChangeListResults($result) { try { $concept['date'] = $row->date->getValue(); } catch (Exception $e) { - //don't do anything to malformed dates e.g. 1986-21-00 + //don't record concepts with malformed dates e.g. 1986-21-00 + continue; } } diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index 125e2413d..15d0ec97d 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -1107,6 +1107,23 @@ public function testQueryChangeList() $this->assertEquals(array('Fourth date', 'Hurr Durr', 'Second date', 'A date'), $order); } + /** + * @covers GenericSparql::queryChangeList + * @covers GenericSparql::generateChangeListQuery + * @covers GenericSparql::transFormChangeListResults + */ + public function testMalformedDates() { + $voc = $this->model->getVocabulary('test'); + $graph = $voc->getGraph(); + $sparql = new GenericSparql('http://localhost:13030/skosmos-test/sparql', $graph, $this->model); + $result = $sparql->queryChangeList('dc:modified', 'en', 0, 10); + $uris = array(); + foreach($result as $concept) { + $uris[] = $concept['uri']; + } + $this->assertNotContains('http://www.skosmos.skos/test/ta114', $uris); + } + /** * @covers GenericSparql::formatTypes * @covers GenericSparql::queryConcepts diff --git a/tests/WebControllerTest.php b/tests/WebControllerTest.php index 6396c3354..1a9bfcbaf 100644 --- a/tests/WebControllerTest.php +++ b/tests/WebControllerTest.php @@ -209,6 +209,7 @@ public function testGetModifiedDate($concept, $git, $config, $modifiedDate) } /** + * @covers WebController::getChangeList * @covers WebController::formatChangeList */ public function testFormatChangeList() { @@ -225,5 +226,4 @@ public function testFormatChangeList() { $this->assertEquals(array('December 2011', 'February 2010', 'January 2000'), array_keys($months)); $this->assertEquals($expected, $months['February 2010']); } - } From a907434b350c658f4585d2640bcc9cc86595146b Mon Sep 17 00:00:00 2001 From: Joeli Takala Date: Mon, 15 Jun 2020 10:28:15 +0300 Subject: [PATCH 24/24] Fixed PHPDoc comments --- model/sparql/GenericSparql.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index d333a6d8f..dde59fd40 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -2207,7 +2207,7 @@ public function listConceptGroupContents($groupClass, $group, $lang,$showDepreca /** * Generates the sparql query for queryChangeList. - * @param string $property the property uri pointing to timestamps, eg. 'dc:modified' + * @param string $prop 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 @@ -2261,7 +2261,7 @@ 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 $prop 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