From b2161380811bc6e57d50ac4303dc8c2c341a895e Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 3 Feb 2022 13:06:17 +0100 Subject: [PATCH 1/6] feat: add capability to check if a RDF resource is writable --- core/kernel/classes/class.Resource.php | 11 ++++ .../persistence/smoothsql/class.Resource.php | 61 ++++++++++--------- .../smoothsql/class.SmoothModel.php | 26 +++++--- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/core/kernel/classes/class.Resource.php b/core/kernel/classes/class.Resource.php index e29bcb459..142a930ed 100644 --- a/core/kernel/classes/class.Resource.php +++ b/core/kernel/classes/class.Resource.php @@ -150,6 +150,17 @@ public function isClass() return (bool) $returnValue; } + public function isWritable(): bool + { + $implementation = $this->getImplementation(); + + if ($implementation instanceof core_kernel_persistence_smoothsql_Resource) { + return $implementation->isWritable($this); + } + + return true; + } + /** * returns true if the resource is a valid property (using facts or * rules) diff --git a/core/kernel/persistence/smoothsql/class.Resource.php b/core/kernel/persistence/smoothsql/class.Resource.php index 8e8113324..94ab4182c 100644 --- a/core/kernel/persistence/smoothsql/class.Resource.php +++ b/core/kernel/persistence/smoothsql/class.Resource.php @@ -42,17 +42,17 @@ class core_kernel_persistence_smoothsql_Resource implements core_kernel_persiste * @var core_kernel_persistence_smoothsql_SmoothModel */ private $model; - + public function __construct(core_kernel_persistence_smoothsql_SmoothModel $model) { $this->model = $model; } - + protected function getModel() { return $this->model; } - + /** * @return common_persistence_SqlPersistence */ @@ -60,17 +60,17 @@ protected function getPersistence() { return $this->model->getPersistence(); } - + protected function getModelReadSqlCondition() { return 'modelid IN (' . implode(',', $this->model->getReadableModels()) . ')'; } - + protected function getModelWriteSqlCondition() { return 'modelid IN (' . implode(',', $this->model->getWritableModels()) . ')'; } - + protected function getNewTripleModelId() { return $this->model->getNewTripleModelId(); @@ -96,7 +96,7 @@ public function getTypes(core_kernel_classes_Resource $resource) $uri = $this->getPersistence()->getPlatForm()->getPhpTextValue($row['object']); $returnValue[$uri] = $this->getModel()->getClass($uri); } - + return (array) $returnValue; } @@ -121,7 +121,7 @@ public function getPropertyValues(core_kernel_classes_Resource $resource, core_k throw new core_kernel_persistence_Exception('Option \'last\' no longer supported'); } $platform = $this->getPersistence()->getPlatForm(); - + // Define language if required $defaultLg = ''; if (isset($options['lg'])) { @@ -139,7 +139,7 @@ public function getPropertyValues(core_kernel_classes_Resource $resource, core_k AND predicate = ? AND (l_language = ? OR l_language = ' . $this->getPersistence()->quote('') . $defaultLg . ') AND ' . $this->getModelReadSqlCondition(); - + if ($one) { // Select first $query .= ' ORDER BY id DESC'; @@ -149,7 +149,7 @@ public function getPropertyValues(core_kernel_classes_Resource $resource, core_k // Select All $result = $this->getPersistence()->query($query, [$resource->getUri(), $property->getUri(), $lang]); } - + // Treat the query result if ($result == true) { if (isset($options['lg'])) { @@ -162,7 +162,7 @@ public function getPropertyValues(core_kernel_classes_Resource $resource, core_k $returnValue = core_kernel_persistence_smoothsql_Utils::filterByLanguage($this->getPersistence(), $result->fetchAll(), 'l_language', $lang, $default); } } - + return (array) $returnValue; } @@ -180,12 +180,12 @@ public function getPropertyValues(core_kernel_classes_Resource $resource, core_k public function getPropertyValuesByLg(core_kernel_classes_Resource $resource, core_kernel_classes_Property $property, $lg) { $options = ['lg' => $lg]; - + $returnValue = new core_kernel_classes_ContainerCollection($resource); foreach ($this->getPropertyValues($resource, $property, $options) as $value) { $returnValue->add(common_Utils::toResource($value)); } - + return $returnValue; } @@ -316,14 +316,14 @@ public function removePropertyValues(core_kernel_classes_Resource $resource, cor $conditions[] = "{$multiCondition} ) "; } } - + foreach ($conditions as $i => $additionalCondition) { $query .= " AND ( {$additionalCondition} ) "; } - + //be sure the property we try to remove is included in an updatable model $query .= ' AND ' . $this->getModelWriteSqlCondition(); - + if ($property->isLgDependent()) { $query .= ' AND (l_language = ? OR l_language = ?) '; $returnValue = $this->getPersistence()->exec($query, [ @@ -338,11 +338,11 @@ public function removePropertyValues(core_kernel_classes_Resource $resource, cor $property->getUri() ]); } - + if (!$returnValue) { $returnValue = false; } - + return (bool) $returnValue; } @@ -362,13 +362,13 @@ public function removePropertyValueByLg(core_kernel_classes_Resource $resource, $sqlQuery = 'DELETE FROM statements WHERE subject = ? and predicate = ? and l_language = ?'; //be sure the property we try to remove is included in an updatable model $sqlQuery .= ' AND ' . $this->getModelWriteSqlCondition(); - + $returnValue = $this->getPersistence()->exec($sqlQuery, [ $resource->getUri(), $property->getUri(), ($property->isLgDependent() ? $lg : ''), ]); - + if (!$returnValue) { $returnValue = false; } @@ -389,7 +389,7 @@ public function getRdfTriples(core_kernel_classes_Resource $resource) // TODO: refactor this to use a triple store abstraction $query = 'SELECT * FROM statements WHERE subject = ? AND ' . $this->getModelReadSqlCondition() . ' ORDER BY predicate'; $result = $this->getPersistence()->query($query, [$resource->getUri()]); - + $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__)); while ($statement = $result->fetch()) { $triple = new core_kernel_classes_Triple(); @@ -407,6 +407,11 @@ public function getRdfTriples(core_kernel_classes_Resource $resource) return $returnValue; } + public function isWritable(core_kernel_classes_Resource $resource): bool + { + return $this->model->isWritable($resource); + } + /** * Short description of method getUsedLanguages * @@ -495,12 +500,12 @@ public function delete(core_kernel_classes_Resource $resource, $deleteReference } elseif ($deleteReference) { $sqlQuery = 'DELETE FROM statements WHERE ' . $this->getPersistence()->getPlatForm()->getObjectTypeCondition() . ' = ? AND ' . $this->getModelWriteSqlCondition(); $return = $this->getPersistence()->exec($sqlQuery, [$resource->getUri()]); - + if ($return !== false) { $returnValue = true; } } - + return (bool) $returnValue; } @@ -522,7 +527,7 @@ public function getPropertiesValues(core_kernel_classes_Resource $resource, $pro if (count($properties) == 0) { return []; } - + $predicatesQuery = ''; //build the predicate query //$predicatesQuery = implode(',', $properties); @@ -549,7 +554,7 @@ public function getPropertiesValues(core_kernel_classes_Resource $resource, $pro ' OR l_language = ' . $this->getPersistence()->quote($lang) . ') AND ' . $this->getModelReadSqlCondition(); $result = $this->getPersistence()->query($query); - + $rows = $result->fetchAll(); foreach ($rows as $row) { $value = $platform->getPhpTextValue($row['object']); @@ -588,16 +593,16 @@ public function removeType(core_kernel_classes_Resource $resource, core_kernel_c { $query = 'DELETE FROM statements WHERE subject = ? AND predicate = ? AND ' . $this->getPersistence()->getPlatForm()->getObjectTypeCondition() . ' = ?'; - + //be sure the property we try to remove is included in an updatable model $query .= ' AND ' . $this->getModelWriteSqlCondition(); - + $returnValue = $this->getPersistence()->exec($query, [ $resource->getUri(), OntologyRdf::RDF_TYPE, $class->getUri() ]); - + $returnValue = true; return $returnValue; diff --git a/core/kernel/persistence/smoothsql/class.SmoothModel.php b/core/kernel/persistence/smoothsql/class.SmoothModel.php index 6109188d2..2393caba7 100755 --- a/core/kernel/persistence/smoothsql/class.SmoothModel.php +++ b/core/kernel/persistence/smoothsql/class.SmoothModel.php @@ -51,7 +51,7 @@ class core_kernel_persistence_smoothsql_SmoothModel extends ConfigurableService * @var common_persistence_SqlPersistence */ private $persistence; - + function getResource($uri) { $resource = new \core_kernel_classes_Resource($uri); @@ -73,6 +73,18 @@ function getProperty($uri) return $property; } + public function isWritable(core_kernel_classes_Resource $resource): bool + { + /** @var core_kernel_classes_Triple $triple */ + foreach ($resource->getRdfTriples() as $triple) { + if (!in_array((int)$triple->modelid, $this->getWritableModels(), true)) { + return false; + } + } + + return true; + } + /** * @return common_persistence_SqlPersistence */ @@ -99,7 +111,7 @@ public function getRdfInterface() { return new core_kernel_persistence_smoothsql_SmoothRdf($this); } - + /** * (non-PHPdoc) * @see \oat\generis\model\data\Model::getRdfsInterface() @@ -108,7 +120,7 @@ public function getRdfsInterface() { return new core_kernel_persistence_smoothsql_SmoothRdfs($this); } - + /** * @return ComplexSearchService */ @@ -120,7 +132,7 @@ public function getSearchInterface() } // Manage the sudmodels of the smooth mode - + /** * Returns the id of the model to add to * @@ -130,7 +142,7 @@ public function getNewTripleModelId() { return $this->getOption(self::OPTION_NEW_TRIPLE_MODEL); } - + public function getReadableModels() { return $this->getOption(self::OPTION_READABLE_MODELS); @@ -140,7 +152,7 @@ public function getWritableModels() { return $this->getOption(self::OPTION_WRITEABLE_MODELS); } - + // // Deprecated functions // @@ -176,7 +188,7 @@ public static function getReadableModelIds() } return $model->getReadableModels(); } - + /** * Returns the submodel ids that are updatable * From 26fdb7e308eff4a7b23f8055f759d310fd28bf08 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 3 Feb 2022 14:11:36 +0100 Subject: [PATCH 2/6] chore: remove double lines --- core/kernel/persistence/smoothsql/class.Resource.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/kernel/persistence/smoothsql/class.Resource.php b/core/kernel/persistence/smoothsql/class.Resource.php index 94ab4182c..bf96ea7b7 100644 --- a/core/kernel/persistence/smoothsql/class.Resource.php +++ b/core/kernel/persistence/smoothsql/class.Resource.php @@ -97,7 +97,6 @@ public function getTypes(core_kernel_classes_Resource $resource) $returnValue[$uri] = $this->getModel()->getClass($uri); } - return (array) $returnValue; } @@ -506,7 +505,6 @@ public function delete(core_kernel_classes_Resource $resource, $deleteReference } } - return (bool) $returnValue; } From 96053c76afac2972abdc3c990bba9c72d1541a7f Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 3 Feb 2022 14:14:21 +0100 Subject: [PATCH 3/6] chore: avoiding calling same method twice --- core/kernel/persistence/smoothsql/class.SmoothModel.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/kernel/persistence/smoothsql/class.SmoothModel.php b/core/kernel/persistence/smoothsql/class.SmoothModel.php index 2393caba7..cb4a6e39c 100755 --- a/core/kernel/persistence/smoothsql/class.SmoothModel.php +++ b/core/kernel/persistence/smoothsql/class.SmoothModel.php @@ -75,9 +75,11 @@ function getProperty($uri) public function isWritable(core_kernel_classes_Resource $resource): bool { + $writableModels = $this->getWritableModels(); + /** @var core_kernel_classes_Triple $triple */ foreach ($resource->getRdfTriples() as $triple) { - if (!in_array((int)$triple->modelid, $this->getWritableModels(), true)) { + if (!in_array((int)$triple->modelid, $writableModels, true)) { return false; } } From aa7c056eb84eb64da02419b9e88b3afa1c5d4ae0 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 3 Feb 2022 14:38:06 +0100 Subject: [PATCH 4/6] choire: add unit tests for isWritable --- .../unit/core/kernel/classes/ResourceTest.php | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 test/unit/core/kernel/classes/ResourceTest.php diff --git a/test/unit/core/kernel/classes/ResourceTest.php b/test/unit/core/kernel/classes/ResourceTest.php new file mode 100644 index 000000000..bfc73ae90 --- /dev/null +++ b/test/unit/core/kernel/classes/ResourceTest.php @@ -0,0 +1,95 @@ +model = $this->createMock(Ontology::class); + $this->rdfs = $this->createMock(RdfsInterface::class); + $this->smoothSqlResource = $this->createMock(core_kernel_persistence_smoothsql_Resource::class); + + $this->model->method('getRdfsInterface') + ->willReturn($this->rdfs); + + $this->subject = new core_kernel_classes_Resource('uri'); + $this->subject->setModel($this->model); + } + + public function testIsWritableByDefault(): void + { + $this->rdfs->method('getResourceImplementation') + ->willReturn($this->createMock(core_kernel_persistence_ResourceInterface::class)); + + $this->smoothSqlResource + ->method('isWritable') + ->willReturn(true); + + $this->assertTrue($this->subject->isWritable()); + } + + public function testIsWritable(): void + { + $this->rdfs->method('getResourceImplementation') + ->willReturn($this->smoothSqlResource); + + $this->smoothSqlResource + ->method('isWritable') + ->willReturn(true); + + $this->assertTrue($this->subject->isWritable()); + } + + public function testIsNotWritable(): void + { + $this->rdfs->method('getResourceImplementation') + ->willReturn($this->smoothSqlResource); + + $this->smoothSqlResource + ->method('isWritable') + ->willReturn(false); + + $this->assertFalse($this->subject->isWritable()); + } +} From 651d017e21729ec27ccb307b0a9440ca2c9b046c Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 3 Feb 2022 15:30:54 +0100 Subject: [PATCH 5/6] choire: add unit tests for isWritable --- .../persistence/smoothsql/SmoothModelTest.php | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100755 test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php diff --git a/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php b/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php new file mode 100755 index 000000000..752298273 --- /dev/null +++ b/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php @@ -0,0 +1,96 @@ +sut = new core_kernel_persistence_smoothsql_SmoothModel(); + $this->sut->setOption( + core_kernel_persistence_smoothsql_SmoothModel::OPTION_WRITEABLE_MODELS, + [ + core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL, + ] + ); + } + + public function testIsWritableByDefault(): void + { + $this->assertTrue( + $this->sut->isWritable( + $this->createResourceWithTriples([]) + ) + ); + } + + public function testIsWritable(): void + { + $this->assertTrue( + $this->sut->isWritable( + $this->createResourceWithTriples( + [ + core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL, + ] + ) + ) + ); + } + + public function testIsNotWritable(): void + { + $this->assertFalse( + $this->sut->isWritable( + $this->createResourceWithTriples( + [ + core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL, + core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_READ_ONLY_MODEL + ] + ) + ) + ); + } + + private function createResourceWithTriples(array $modelIds): core_kernel_classes_Resource + { + $triples = []; + + foreach ($modelIds as $modelId) { + $triple = $this->createMock(core_kernel_classes_Triple::class); + $triple->modelid = $modelId; + + $triples[] = $triple; + } + + $resource = $this->createMock(core_kernel_classes_Resource::class); + $resource->method('getRdfTriples') + ->willReturn($triples); + + return $resource; + } +} From 0c1a0ef6cdb4603bde1277e2cf16c4ce3bef9888 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 4 Feb 2022 08:45:08 +0100 Subject: [PATCH 6/6] chore: add unit test for isWritable --- .../persistence/smoothsql/ResourceTest.php | 52 +++++++++++++++++++ .../persistence/smoothsql/SmoothModelTest.php | 3 ++ 2 files changed, 55 insertions(+) create mode 100755 test/unit/core/kernel/persistence/smoothsql/ResourceTest.php diff --git a/test/unit/core/kernel/persistence/smoothsql/ResourceTest.php b/test/unit/core/kernel/persistence/smoothsql/ResourceTest.php new file mode 100755 index 000000000..f89aa7eaf --- /dev/null +++ b/test/unit/core/kernel/persistence/smoothsql/ResourceTest.php @@ -0,0 +1,52 @@ +model = $this->createMock(core_kernel_persistence_smoothsql_SmoothModel::class); + $this->sut = new core_kernel_persistence_smoothsql_Resource($this->model); + } + + public function testIsWritable(): void + { + $this->model->method('isWritable') + ->willReturn(true); + + $this->assertTrue($this->sut->isWritable($this->createMock(core_kernel_classes_Resource::class))); + } +} diff --git a/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php b/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php index 752298273..a2d466c52 100755 --- a/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php +++ b/test/unit/core/kernel/persistence/smoothsql/SmoothModelTest.php @@ -29,6 +29,9 @@ class SmoothModelTest extends GenerisTestCase { + /** @var core_kernel_persistence_smoothsql_SmoothModel */ + private $sut; + public function setUp(): void { $this->sut = new core_kernel_persistence_smoothsql_SmoothModel();