diff --git a/common/class.Utils.php b/common/class.Utils.php index e357fa9b9..b63584369 100644 --- a/common/class.Utils.php +++ b/common/class.Utils.php @@ -1,7 +1,4 @@ installLoadDefaultConfig(); + + // Id of the writable model. + $modelFactory = $this->getServiceManager()->get(ModelFactory::SERVICE_ID); + $writableModelId = $modelFactory->getModelId(LOCAL_NAMESPACE); $model = new \core_kernel_persistence_smoothsql_SmoothModel(array( \core_kernel_persistence_smoothsql_SmoothModel::OPTION_PERSISTENCE => 'default', - \core_kernel_persistence_smoothsql_SmoothModel::OPTION_READABLE_MODELS => array('1'), - \core_kernel_persistence_smoothsql_SmoothModel::OPTION_WRITEABLE_MODELS => array('1'), - \core_kernel_persistence_smoothsql_SmoothModel::OPTION_NEW_TRIPLE_MODEL => '1', + \core_kernel_persistence_smoothsql_SmoothModel::OPTION_READABLE_MODELS => [$writableModelId], + \core_kernel_persistence_smoothsql_SmoothModel::OPTION_WRITEABLE_MODELS => [$writableModelId], + \core_kernel_persistence_smoothsql_SmoothModel::OPTION_NEW_TRIPLE_MODEL => $writableModelId, \core_kernel_persistence_smoothsql_SmoothModel::OPTION_SEARCH_SERVICE => ComplexSearchService::SERVICE_ID, \core_kernel_persistence_smoothsql_SmoothModel::OPTION_CACHE_SERVICE => common_cache_Cache::SERVICE_ID )); - $model->setServiceLocator(ServiceManager::getServiceManager()); + $model->setServiceLocator($this->getServiceManager()); ModelManager::setModel($model); $this->installOntology(); diff --git a/common/ext/class.Namespace.php b/common/ext/class.Namespace.php index 280670955..9e35ed12f 100644 --- a/common/ext/class.Namespace.php +++ b/common/ext/class.Namespace.php @@ -1,23 +1,23 @@ - - * @param int id - * @param string uri - * @return mixed + * @param string|int id + * @param string uri */ - public function __construct($id = 0, $uri = '') + public function __construct($id, $uri = '') { - - - if($id > 0){ - $this->modelId = $id; - } - if(!empty($uri)){ - $this->uri = $uri; - } - - + $this->modelId = $id; + $this->uri = $uri; } /** * Get the identifier of the namespace instance * - * @access public - * @author Jerome Bogaerts, - * @return int + * @return string|int */ public function getModelId() { - $returnValue = (int) 0; - - - - $returnValue = $this->modelId; - - - - return (int) $returnValue; + return $this->modelId; } /** * Get the namespace URI * - * @access public - * @author Jerome Bogaerts, * @return string */ public function getUri() { - $returnValue = (string) ''; - - - - $returnValue = $this->uri; - - - - return (string) $returnValue; + return $this->uri; } /** * Magic method, return the Namespace URI * - * @access public - * @author Jerome Bogaerts, * @return string */ public function __toString() { - $returnValue = (string) ''; - - - - $returnValue = $this->getUri(); - - - - return (string) $returnValue; + return $this->getUri(); } /** * Remove a namespace from the ontology. All triples bound to the model will * be removed. * - * @access public - * @author Jerome Bogaerts, * @return boolean */ public function remove() { - $returnValue = (bool) false; - - $db = core_kernel_classes_DbWrapper::singleton(); + + // TODO refactor this to use triple store abstraction. if (false === $db->exec("DELETE FROM statements WHERE modelid = ?", array($this->getModelId()))){ - $returnValue = false; + return false; } - else{ - if (false === $db->exec("DELETE FROM models WHERE modelid = ?", array($this->getModelId()))){ - $returnValue = false; - } - else{ - $returnValue = true; - } + + // TODO refactor this to use triple store abstraction. + if (false === $db->exec("DELETE FROM models WHERE modelid = ?", array($this->getModelId()))){ + return false; } - - - return (bool) $returnValue; + return true; } -} \ No newline at end of file +} diff --git a/common/persistence/class.Persistence.php b/common/persistence/class.Persistence.php index e888c4943..1d5c333ee 100755 --- a/common/persistence/class.Persistence.php +++ b/common/persistence/class.Persistence.php @@ -21,6 +21,7 @@ * @package generis * */ + abstract class common_persistence_Persistence { /** @@ -102,15 +103,5 @@ protected function getParams(){ protected function setParams($params){ $this->params = $params; } - - /** - * Generates a unique, not auto-increment based, primary key. - * - * @return string - */ - public function getUniquePrimaryKey() - { - return strrev(uniqid('', true)); - } } diff --git a/common/persistence/class.SqlPersistence.php b/common/persistence/class.SqlPersistence.php index 41ced2b3d..5519fc18c 100755 --- a/common/persistence/class.SqlPersistence.php +++ b/common/persistence/class.SqlPersistence.php @@ -15,36 +15,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); - * - * + * + * @author Lionel Lecaque + * @author Jerome Bogaerts, + * @author */ - +use Doctrine\DBAL\DBALException; /** * Persistence base on SQL - * - * @author Lionel Lecaque - * @license GPLv2 - * @package generis - * */ class common_persistence_SqlPersistence extends common_persistence_Persistence { /** - * - * @author "Lionel Lecaque, " * @param string $statement * @param array $params + * @param array $types + * @return int number of updated rows + * @throws DBALException */ - public function exec($statement,$params = array()) + public function exec($statement, array $params = [], array $types = []) { - return $this->getDriver()->exec($statement,$params); + return $this->getDriver()->exec($statement, $params, $types); } /** - * @author "Lionel Lecaque, " * @return common_persistence_sql_SchemaManager */ public function getSchemaManager(){ @@ -52,27 +49,37 @@ public function getSchemaManager(){ } /** - * @author Lionel Lecaque, * @return common_persistence_sql_Platform */ public function getPlatForm(){ return $this->getDriver()->getPlatform(); } - + /** - * - * @author "Lionel Lecaque, " + * Inserts one row. + * * @param string $tableName * @param array $data + * @param array $types + * @return int number of updated rows + * @throws DBALException */ - public function insert($tableName, array $data) + public function insert($tableName, array $data, array $types = []) { - return $this->getDriver()->insert($tableName, $data); + return $this->getDriver()->insert($tableName, $data, $types); } - - public function insertMultiple($tableName, array $data) + + /** + * Inserts one row. + * + * @param string $tableName + * @param array $data + * @param array $types + * @return int number of updated rows + */ + public function insertMultiple($tableName, array $data, array $types = []) { - return $this->getDriver()->insertMultiple($tableName, $data); + return $this->getDriver()->insertMultiple($tableName, $data, $types); } /** @@ -87,22 +94,22 @@ public function updateMultiple($table, array $data) } /** + * Executes parameterized query. * - * @author "Lionel Lecaque, " * @param string $statement * @param array $params * @return \Doctrine\DBAL\Driver\Statement + * @throws DBALException */ - public function query($statement,$params= array()) + public function query($statement, $params = [], array $types = []) { - return $this->getDriver()->query($statement,$params); + return $this->getDriver()->query($statement, $params, $types); } /** * Convenience access to quote. * - * @author Jerome Bogaerts, * @param string $parameter The parameter to quote. * @param int $parameter_type A PDO PARAM_XX constant. * @return string The quoted string. @@ -115,7 +122,6 @@ public function quote($parameter, $parameter_type = PDO::PARAM_STR){ /** * Convenience access to lastInsertId. * - * @author Jerome Bogaerts, * @param string $name * @return string The quoted string. */ diff --git a/common/persistence/sql/SetupDb.php b/common/persistence/sql/SetupDb.php index 626cd6c9d..c0e557f43 100644 --- a/common/persistence/sql/SetupDb.php +++ b/common/persistence/sql/SetupDb.php @@ -22,14 +22,15 @@ */ namespace oat\generis\persistence\sql; +use Doctrine\DBAL\Exception\ConnectionException; use Doctrine\DBAL\Schema\AbstractSchemaManager; -use oat\oatbox\log\LoggerAwareTrait; -use Psr\Log\LoggerAwareInterface; use Doctrine\DBAL\Schema\Schema; use oat\generis\model\kernel\persistence\smoothsql\install\SmoothRdsModel; -use Doctrine\DBAL\Exception\ConnectionException; +use oat\oatbox\log\LoggerAwareTrait; +use oat\oatbox\service\ConfigurableService; +use Psr\Log\LoggerAwareInterface; -class SetupDb implements LoggerAwareInterface +class SetupDb extends ConfigurableService implements LoggerAwareInterface { use LoggerAwareTrait; @@ -78,8 +79,9 @@ private function setupTables(\common_persistence_SqlPersistence $p) */ public function getSchema(\common_persistence_SqlPersistence $p) { + $smoothRdsModel = $this->getServiceLocator()->get(SmoothRdsModel::class); $schema = $p->getSchemaManager()->createSchema(); - SmoothRdsModel::addSmoothTables($schema); + $smoothRdsModel->addSmoothTables($schema); $this->addKeyValueStoreTable($schema); return $schema; } diff --git a/common/persistence/sql/dbal/class.Driver.php b/common/persistence/sql/dbal/class.Driver.php index ab363a9aa..2107fc099 100755 --- a/common/persistence/sql/dbal/class.Driver.php +++ b/common/persistence/sql/dbal/class.Driver.php @@ -17,6 +17,8 @@ * Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); */ +use Doctrine\DBAL\DBALException; + /** * Dbal Driver * @@ -45,7 +47,7 @@ class common_persistence_sql_dbal_Driver implements common_persistence_sql_Drive * @param string $id * @param array $params * @return common_persistence_Persistence|common_persistence_SqlPersistence - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ public function connect($id, array $params) { @@ -71,7 +73,7 @@ public function connect($id, array $params) * Endless connection * * @param $connectionParams - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ protected function persistentConnect($connectionParams) { @@ -106,7 +108,7 @@ protected function persistentConnect($connectionParams) * @param $config * @return \Doctrine\DBAL\Connection * - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException * */ private function getConnection($params, $config) @@ -150,31 +152,32 @@ public function getSchemaManager() return new common_persistence_sql_dbal_SchemaManager($this->connection->getSchemaManager()); } - /** * Execute the statement with provided params * - * @author "Lionel Lecaque, " * @param mixed $statement * @param array $params + * @param array $types * @return integer number of affected row + * @throws DBALException; */ - public function exec($statement,$params = array()) + public function exec($statement, $params = [], array $types = []) { - return $this->connection->executeUpdate($statement,$params); + return $this->connection->executeUpdate($statement, $params, $types); } - /** * Query the statement with provided params * - * @author "Lionel Lecaque, " * @param mixed $statement + * @param array $params + * @param array $types * @return \Doctrine\DBAL\Driver\Statement + * @throws DBALException; */ - public function query($statement,$params = array()) + public function query($statement, $params = [], array $types = []) { - return $this->connection->executeQuery($statement,$params); + return $this->connection->executeQuery($statement, $params, $types); } /** @@ -189,18 +192,18 @@ public function quote($parameter, $parameter_type = PDO::PARAM_STR){ return $this->connection->quote($parameter, $parameter_type); } - - /** * (non-PHPdoc) * @see common_persistence_sql_Driver::insert() + * @throws DBALException; */ - public function insert($tableName, array $data){ + public function insert($tableName, array $data, array $types = []) + { $cleanColumns = array(); foreach ($data as $columnName => $value) { $cleanColumns[$this->getPlatForm()->quoteIdentifier($columnName)] = $value; } - return $this->connection->insert($tableName, $cleanColumns); + return $this->connection->insert($tableName, $cleanColumns, $types); } /** diff --git a/common/persistence/sql/interface.Driver.php b/common/persistence/sql/interface.Driver.php index d9171cb56..4791c1dc0 100644 --- a/common/persistence/sql/interface.Driver.php +++ b/common/persistence/sql/interface.Driver.php @@ -21,12 +21,22 @@ * @package generis * */ + +use Doctrine\DBAL\DBALException; + interface common_persistence_sql_Driver extends common_persistence_Driver { - - public function query($statement,$params); - - public function exec($statement,$params); + /** + * @inheritdoc + * @throws DBALException; + */ + public function query($statement,$params, array $types = []); + + /** + * @inheritdoc + * @throws DBALException; + */ + public function exec($statement,$params, array $types = []); /** * Insert a single row into the database. @@ -35,9 +45,10 @@ public function exec($statement,$params); * * @param string $tableName name of the table * @param array $data An associative array containing column-value pairs. - * @return integer The number of affected rows. + * @return integer The number of affected rows. + * @throws DBALException */ - public function insert($tableName, array $data); + public function insert($tableName, array $data, array $types = []); public function insertMultiple($tableName, array $data); diff --git a/common/persistence/sql/trait.MultipleOperations.php b/common/persistence/sql/trait.MultipleOperations.php index 537d8d1c2..384676e95 100644 --- a/common/persistence/sql/trait.MultipleOperations.php +++ b/common/persistence/sql/trait.MultipleOperations.php @@ -27,7 +27,7 @@ trait common_persistence_sql_MultipleOperations /** @var common_persistence_sql_UpdateMultiple */ private $updateMultiple = null; - public function insertMultiple($tableName, array $data) + public function insertMultiple($tableName, array $data, array $types = []) { if (is_array($data) && count($data) > 0) { @@ -51,7 +51,7 @@ function ($value) use ($platform) { $query .= implode(', ', $valuesQueries); - return $this->exec($query, $allValues); + return $this->exec($query, $allValues, $types); } else { return 0; } diff --git a/composer.json b/composer.json index fb675162a..8ec2b59dd 100755 --- a/composer.json +++ b/composer.json @@ -67,7 +67,8 @@ "monolog/monolog": "^1.23.0", "fluent/logger": "^1.0.1", "symfony/lock": "^3.4", - "psr/container": "^1.0.0" + "psr/container": "^1.0.0", + "ramsey/uuid": "^3.8" }, "require-dev": { "mikey179/vfsstream": "1.4.0", diff --git a/core/kernel/api/NewSqlModelFactory.php b/core/kernel/api/NewSqlModelFactory.php new file mode 100644 index 000000000..1a83af04c --- /dev/null +++ b/core/kernel/api/NewSqlModelFactory.php @@ -0,0 +1,120 @@ +getPersistence()->insert('models', ['modelid' => $modelId, 'modeluri' => $namespace]) === 0) { + throw new RuntimeException('A problem occurred while creating a new model.'); + } + return $modelId; + } + + /** + * @inheritdoc + */ + public function prepareStatement($modelId, $subject, $predicate, $object, $lang, $author) + { + return [ + 'id' => $this->getUniquePrimaryKey(), + 'modelid' => $modelId, + 'subject' => $subject, + 'predicate' => $predicate, + 'object' => $object, + 'l_language' => $lang, + 'author' => $author ?? '', + 'epoch' => $this->getPersistence()->getPlatForm()->getNowExpression(), + ]; + } + + /** + * @inheritdoc + */ + public function buildModelSqlCondition(array $models) + { + $models = array_map( + function ($a) { + return "'" . $a . "'"; + }, + $models + ); + return parent::buildModelSqlCondition($models); + } + + /** + * @inheritdoc + */ + public function getPropertySortingField() + { + return 'epoch'; + } + + /** + * @inheritdoc + */ + public function createModelsTable(Schema $schema) + { + $table = $schema->createTable('models'); + + $table->addColumn('modelid', 'string', ['length' => 36, 'notnull' => true]); + $table->addColumn('modeluri', 'string', ['length' => 255]); + + $table->setPrimaryKey(['modelid']); + + return $table; + } + + /** + * @inheritdoc + */ + public function createStatementsTable(Schema $schema) + { + $table = $schema->createTable('statements'); + + $table->addColumn('id', 'string', ['length' => 36, 'notnull' => true]); + $table->addColumn('modelid', 'string', ['length' => 23, 'notnull' => true]); + $table->addColumn('subject', 'string', ['length' => 255]); + $table->addColumn('predicate', 'string', ['length' => 255]); + $table->addColumn('object', 'text', []); + $table->addColumn('l_language', 'string', ['length' => 255]); + $table->addColumn('author', 'string', ['length' => 255]); + $table->addColumn('epoch', 'string', ['notnull' => true]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['subject', 'predicate'], 'k_sp'); + $table->addIndex(['predicate', 'object'], 'k_po'); + + return $table; + } +} diff --git a/core/kernel/api/RdsModelFactory.php b/core/kernel/api/RdsModelFactory.php new file mode 100644 index 000000000..f649fdadc --- /dev/null +++ b/core/kernel/api/RdsModelFactory.php @@ -0,0 +1,109 @@ +getPersistence(); + if ($persistence->insert('models', ['modeluri' => $namespace]) === 0) { + throw new RuntimeException('A problem occurred while creating a new model.'); + } + + // Retrieving the inserted modelid (auto-increment). + $result = $persistence->query('select modelid from models where modeluri = ?', [$namespace]); + $modelId = $result->fetch(); + return $modelId['modelid']; + } + + /** + * @inheritdoc + */ + public function prepareStatement($modelId, $subject, $predicate, $object, $lang, $author) + { + return [ + 'modelid' => $modelId, + 'subject' => $subject, + 'predicate' => $predicate, + 'object' => $object, + 'l_language' => $lang, + 'author' => $author ?? '', + 'epoch' => $this->getPersistence()->getPlatForm()->getNowExpression(), + ]; + } + + /** + * @inheritdoc + */ + public function getPropertySortingField() + { + return 'id'; + } + + /** + * @inheritdoc + */ + public function createModelsTable(Schema $schema) + { + // Models table. + $table = $schema->createTable('models'); + + $table->addColumn('modelid', 'integer', ['notnull' => true, 'autoincrement' => true]); + $table->addColumn('modeluri', 'string', ['length' => 255, 'default' => null]); + + $table->setPrimaryKey(['modelid']); + $table->addOption('engine', 'MyISAM'); + + return $table; + } + + /** + * @inheritdoc + */ + public function createStatementsTable(Schema $schema) + { + $table = $schema->createTable('statements'); + + $table->addColumn('id', 'integer', ['notnull' => true, 'autoincrement' => true]); + $table->addColumn('modelid', 'integer', ['notnull' => true, 'default' => 0]); + $table->addColumn('subject', 'string', ['length' => 255, 'default' => null]); + $table->addColumn('predicate', 'string', ['length' => 255, 'default' => null]); + $table->addColumn('object', 'text', ['default' => null, 'notnull' => false]); + $table->addColumn('l_language', 'string', ['length' => 255, 'default' => null, 'notnull' => false]); + $table->addColumn('author', 'string', ['length' => 255, 'default' => null, 'notnull' => false]); + $table->addColumn('epoch', 'string', ['notnull' => null]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['subject', 'predicate'], 'k_sp', [], ['lengths' => [164, 164]]); + $table->addIndex(['predicate', 'object'], 'k_po', [], ['lengths' => [164, 164]]); + $table->addOption('engine', 'MyISAM'); + + return $table; + } +} diff --git a/core/kernel/api/class.ModelFactory.php b/core/kernel/api/class.ModelFactory.php index c47d2dd0d..0879f204a 100644 --- a/core/kernel/api/class.ModelFactory.php +++ b/core/kernel/api/class.ModelFactory.php @@ -22,48 +22,61 @@ * */ -class core_kernel_api_ModelFactory{ - - + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Table; +use common_persistence_SqlPersistence as Persistence; +use oat\generis\persistence\PersistenceManager; +use oat\oatbox\log\LoggerAwareTrait; +use oat\oatbox\service\ConfigurableService; + +abstract class core_kernel_api_ModelFactory extends ConfigurableService { + + use LoggerAwareTrait; + + const SERVICE_ID = 'generis/modelFactory'; + const OPTION_PERSISTENCE = 'persistence'; + const DEFAULT_AUTHOR = 'http://www.tao.lu/Ontologies/TAO.rdf#installator'; + /** * @author "Lionel Lecaque, " * @param string $namespace * @return string */ - private function getModelId($namespace){ - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); + public function getModelId($namespace){ + if (substr($namespace, -1) !== '#') { + $namespace .= '#'; + } $query = 'SELECT modelid FROM models WHERE (modeluri = ?)'; - $results = $dbWrapper->query($query, array($namespace)); + $results = $this->getPersistence()->query($query, array($namespace)); return $results->fetchColumn(0); } /** + * Creates a new model in the ontology. * @author "Lionel Lecaque, " * @param string $namespace + * @return string|int new added model id + * @throws RuntimeException when a problem occurs when creating the new model in db. */ - private function addNewModel($namespace){ - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $results = $dbWrapper->insert('models', array('modeluri' =>$namespace)); - - - } + abstract public function addNewModel($namespace); /** + * Creates a new model. * @author "Lionel Lecaque, " * @param string $namespace * @param string $data xml content + * @return bool Were triples added? */ public function createModel($namespace, $data){ $modelId = $this->getModelId($namespace); if($modelId === false){ - common_Logger::d('modelId not found, need to add namespace '. $namespace); - $this->addNewModel($namespace); - //TODO bad way, need to find better - $modelId = $this->getModelId($namespace); + // $this->logInfo('modelId not found, need to add namespace '. $namespace); + $modelId = $this->addNewModel($namespace); } $modelDefinition = new EasyRdf_Graph($namespace); if(is_file($data)){ @@ -77,51 +90,119 @@ public function createModel($namespace, $data){ $data = $modelDefinition->serialise($format); + $returnValue = false; foreach ($data as $subjectUri => $propertiesValues){ foreach ($propertiesValues as $prop=>$values){ foreach ($values as $k => $v) { - $this->addStatement($modelId, $subjectUri, $prop, $v['value'], isset($v['lang']) ? $v['lang'] : null); + $returnValue |= $this->addStatement($modelId, $subjectUri, $prop, $v['value'], $v['lang'] ?? null); } } } - return true; + return $returnValue; } /** * Adds a statement to the ontology if it does not exist yet * * @author "Joel Bout, " - * @param int $modelId + * @param string|int $modelId * @param string $subject * @param string $predicate * @param string $object * @param string $lang + * @param string $author + * @return bool Was a row added? */ - private function addStatement($modelId, $subject, $predicate, $object, $lang = null) { - $result = core_kernel_classes_DbWrapper::singleton()->query( + public function addStatement($modelId, $subject, $predicate, $object, $lang = null, $author = self::DEFAULT_AUTHOR) { + // Casting values and types. + $object = (string)$object; + if (is_null($lang)) { + $lang = ''; + } + + // TODO: refactor this to use a triple store abstraction. + $result = $this->getPersistence()->query( 'SELECT count(*) FROM statements WHERE modelid = ? AND subject = ? AND predicate = ? AND object = ? AND l_language = ?', - array($modelId, $subject, $predicate, $object, (is_null($lang)) ? '' : $lang) + array($modelId, $subject, $predicate, $object, $lang) ); - if (intval($result->fetchColumn()) === 0) { - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $date = $dbWrapper->getPlatForm()->getNowExpression(); + if ((int)$result->fetchColumn() > 0) { + return false; + } + + return (bool)$this->getPersistence()->insert( + 'statements', + $this->prepareStatement($modelId, $subject, $predicate, $object, $lang, is_null($author) ? '' : $author) + ); + } + + /** + * Prepares a statement to be inserted in the ontology. + * @param string|int $modelId + * @param string $subject + * @param string $predicate + * @param string $object + * @param string $lang + * @param string $author + * @return array + */ + abstract public function prepareStatement($modelId, $subject, $predicate, $object, $lang, $author); - $dbWrapper->insert( - 'statements', - array( - 'modelid' => $modelId, - 'subject' =>$subject, - 'predicate'=> $predicate, - 'object' => $object, - 'l_language' => is_null($lang) ? '' : $lang, - 'author' => 'http://www.tao.lu/Ontologies/TAO.rdf#installator', - 'epoch' => $date - ) - ); + /** + * Creates a query for iterator on selected statements. + * @param $modelIds + * @return string + */ + public function getIteratorQuery($modelIds) + { + $where = ''; + if ($modelIds !== null) { + $where = 'WHERE ' . $this->buildModelSqlCondition($modelIds); } + return sprintf('SELECT * FROM statements %s ORDER BY %s', $where, $this->getPropertySortingField()); } - -} \ No newline at end of file + /** + * Prepares parameters for statement selection. + * @param array $models + * + * @return string + */ + public function buildModelSqlCondition(array $models) + { + return 'modelid IN (' . implode(',', $models) . ')'; + } + + /** + * Returns the property to sort the statements on. + * @return string + */ + abstract public function getPropertySortingField(); + /** + * Creates table schema for models. + * + * @param Schema $schema + * + * @return Table + */ + abstract public function createModelsTable(Schema $schema); + /** + * Creates table schema for statements. + * + * @param Schema $schema + * + * @return Table + */ + abstract public function createStatementsTable(Schema $schema); + /** + * @return Persistence + */ + public function getPersistence() + { + $persistenceId = $this->hasOption(self::OPTION_PERSISTENCE) ? + $this->getOption(self::OPTION_PERSISTENCE) + : 'default'; + return $this->getServiceLocator()->get(PersistenceManager::SERVICE_ID)->getPersistenceById($persistenceId); + } +} diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index 21996e8e8..ed913c023 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -22,9 +22,13 @@ ?> query('SELECT * FROM "models" WHERE "modeluri" = ?', array( + $result = $this->getPersistence()->query('SELECT * FROM "models" WHERE "modeluri" = ?', array( $namespace )); if ($row = $result->fetch(PDO::FETCH_ASSOC)){ @@ -104,8 +113,6 @@ public function exportXmlRdf($sourceNamespaces = array()) */ public function importXmlRdf($targetNameSpace, $fileLocation) { - $returnValue = (bool) false; - if(!file_exists($fileLocation) || !is_readable($fileLocation)){ throw new common_Exception("Unable to load ontology : $fileLocation"); } @@ -113,12 +120,7 @@ public function importXmlRdf($targetNameSpace, $fileLocation) if(!preg_match("/#$/", $targetNameSpace)){ $targetNameSpace .= '#'; } - $modFactory = new core_kernel_api_ModelFactory(); - $returnValue = $modFactory->createModel($targetNameSpace, file_get_contents($fileLocation)); - - - - return (bool) $returnValue; + return $this->modelFactory->createModel($targetNameSpace, file_get_contents($fileLocation)); } @@ -134,14 +136,11 @@ public function importXmlRdf($targetNameSpace, $fileLocation) */ public function getResourceDescriptionXML($uriResource) { - $returnValue = (string) ''; + $returnValue = ''; - - - - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $subject = $dbWrapper->quote($uriResource); + $persistence = $this->getPersistence(); + $subject = $persistence->quote($uriResource); $baseNs = array( 'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', @@ -150,8 +149,8 @@ public function getResourceDescriptionXML($uriResource) $query = 'SELECT "models"."modelid", "models"."modeluri" FROM "models" INNER JOIN "statements" ON "statements"."modelid" = "models"."modelid" WHERE "statements"."subject" = ' . $subject; - $query = $dbWrapper->limitStatement($query, 1); - $result = $dbWrapper->query($query); + $query = $persistence->limitStatement($query, 1); + $result = $persistence->query($query); if($row = $result->fetch()){ $modelId = $row['modelid']; $modelUri = $row['modeluri']; @@ -166,7 +165,7 @@ public function getResourceDescriptionXML($uriResource) $allModels = array(); - $result = $dbWrapper->query('SELECT * FROM "models"'); + $result = $persistence->query('SELECT * FROM "models"'); while($row = $result->fetch(PDO::FETCH_ASSOC)){ $allModels[] = $row; } @@ -194,7 +193,7 @@ public function getResourceDescriptionXML($uriResource) $description = $dom->createElement('rdf:Description'); $description->setAttribute('rdf:about', $uriResource); - $result = $dbWrapper->query('SELECT * FROM "statements" WHERE "subject" = ' . $subject); + $result = $persistence->query('SELECT * FROM "statements" WHERE "subject" = ' . $subject); while($row = $result->fetch()){ $predicate = trim($row['predicate']); @@ -252,7 +251,7 @@ public function getResourceDescriptionXML($uriResource) $description->appendChild($node); } catch(DOMException $de){ - //print $de; + $this->logError($de); } } } @@ -260,13 +259,13 @@ public function getResourceDescriptionXML($uriResource) $returnValue = $dom->saveXml(); } catch(DomException $e){ - print $e; + $this->logError($e); } - return (string) $returnValue; + return $returnValue; } /** @@ -278,9 +277,6 @@ public function getResourceDescriptionXML($uriResource) */ public function getMetaClasses() { - $returnValue = null; - - $returnValue = new core_kernel_classes_ContainerCollection(new core_kernel_classes_Container(__METHOD__),__METHOD__); $classClass = new core_kernel_classes_Class(OntologyRdfs::RDFS_CLASS); @@ -301,17 +297,11 @@ public function getMetaClasses() */ public function getRootClasses() { - $returnValue = null; - - - $returnValue = new core_kernel_classes_ContainerCollection(new core_kernel_classes_Container(__METHOD__),__METHOD__); - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $query = "SELECT DISTINCT subject FROM statements WHERE (predicate = ? AND object = ?) AND subject NOT IN (SELECT subject FROM statements WHERE predicate = ?)"; - $result = $dbWrapper->query($query, array( + $result = $this->getPersistence()->query($query, array( OntologyRdf::RDF_TYPE, OntologyRdfs::RDFS_CLASS, OntologyRdfs::RDFS_SUBCLASSOF @@ -339,37 +329,16 @@ public function getRootClasses() */ public function setStatement($subject, $predicate, $object, $language) { - $returnValue = (bool) false; - - - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $platform = $dbWrapper->getPlatForm(); - $localNs = common_ext_NamespaceManager::singleton()->getLocalNamespace(); - $mask = 'yyy[admin,administrators,authors]'; //now it's the default right mode - $query = 'INSERT INTO statements (modelid,subject,predicate,object,l_language,author,epoch) - VALUES (?, ?, ?, ?, ?, ? , ?);'; - - try{ - $returnValue = $dbWrapper->exec($query, array( - $localNs->getModelId(), - $subject, - $predicate, - $object, - $language, - \common_session_SessionManager::getSession()->getUserUri(), - $platform->getNowExpression() - - )); - } - catch (DBALException $e){ - if($e->getCode() !== '00000'){ - throw new common_Exception ("Unable to setStatement (SPO) {$subject}, {$predicate}, {$object} : " . $e->getMessage()); - } - } - - - - return (bool) $returnValue; + $modelId = common_ext_NamespaceManager::singleton()->getLocalNamespace()->getModelId(); + $currentUser = common_session_SessionManager::getSession()->getUserUri(); + return $this->modelFactory->addStatement( + $modelId, + $subject, + $predicate, + $object, + $language, + $currentUser + ); } /** @@ -381,16 +350,10 @@ public function setStatement($subject, $predicate, $object, $language) */ public function getAllClasses() { - $returnValue = null; - - - $returnValue = new core_kernel_classes_ContainerCollection(new core_kernel_classes_Container(__METHOD__),__METHOD__); - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $query = "SELECT DISTINCT subject FROM statements WHERE (predicate = ? AND object = ?) OR predicate = ?"; - $result = $dbWrapper->query($query, array( + $result = $this->getPersistence()->query($query, array( OntologyRdf::RDF_TYPE, OntologyRdfs::RDFS_CLASS, OntologyRdfs::RDFS_SUBCLASSOF @@ -416,17 +379,14 @@ public function getAllClasses() */ public function getSubject($predicate, $object) { - $returnValue = null; - + $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__)); $sqlQuery = "SELECT subject FROM statements WHERE predicate = ? AND object= ? "; - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $sqlResult = $dbWrapper->query($sqlQuery, array ( + $sqlResult = $this->getPersistence()->query($sqlQuery, array ( $predicate, $object )); - $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__)); while ($row = $sqlResult->fetch()){ $container = new core_kernel_classes_Resource($row['subject'], __METHOD__); $container->debug = __METHOD__ ; @@ -451,16 +411,11 @@ public function getSubject($predicate, $object) */ public function removeStatement($subject, $predicate, $object, $language) { - $returnValue = (bool) false; - - - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $query = "DELETE FROM statements WHERE subject = ? AND predicate = ? AND object = ? AND (l_language = ? OR l_language = '')"; - $returnValue = $dbWrapper->exec($query, array( + $returnValue = $this->getPersistence()->exec($query, array( $subject, $predicate, $object, @@ -483,16 +438,14 @@ public function removeStatement($subject, $predicate, $object, $language) */ public function getObject($subject, $predicate) { - $returnValue = null; - + $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__)); $sqlQuery = "SELECT object FROM statements WHERE subject = ? AND predicate = ?"; - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); - $sqlResult = $dbWrapper->query($sqlQuery, array ( + $sqlResult = $this->getPersistence()->query($sqlQuery, array ( $subject, $predicate )); - $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__)); + while ($row = $sqlResult->fetch()){ $value = $row['object']; @@ -541,8 +494,17 @@ public static function singleton() */ private function __construct() { - - + $serviceManager = ServiceManager::getServiceManager(); + $this->modelFactory = $serviceManager->get(ModelFactory::SERVICE_ID); } -} \ No newline at end of file + /** + * @return DbWrapper + * @throws PersistenceException + */ + public function getPersistence() + { + // @TODO: inject dbWrapper as a dependency. + return DbWrapper::singleton(); + } +} diff --git a/core/kernel/persistence/file/FileModel.php b/core/kernel/persistence/file/FileModel.php index 45df79eaf..c19c7fcc9 100755 --- a/core/kernel/persistence/file/FileModel.php +++ b/core/kernel/persistence/file/FileModel.php @@ -19,10 +19,12 @@ */ namespace oat\generis\model\kernel\persistence\file; +use common_exception_Error; +use common_exception_MissingParameter; +use common_ext_NamespaceManager; +use core_kernel_api_ModelFactory as ModelFactory; +use oat\oatbox\service\ServiceManager; use oat\generis\model\data\Model; -use \common_ext_NamespaceManager; -use \common_exception_MissingParameter; -use \common_exception_Error; use oat\generis\model\kernel\persistence\file\FileRdf; /** @@ -114,6 +116,8 @@ public function getSearchInterface() { * @throws common_exception_Error */ public static function getModelIdFromXml($file) { + $serviceManager = ServiceManager::getServiceManager(); + $xml = simplexml_load_file($file); $attrs = $xml->attributes('xml', true); if(!isset($attrs['base']) || empty($attrs['base'])){ @@ -121,22 +125,21 @@ public static function getModelIdFromXml($file) { } $namespaceUri = (string) $attrs['base']; $modelId = null; - foreach (common_ext_NamespaceManager::singleton()->getAllNamespaces() as $namespace) { + + $namespaceManager = common_ext_NamespaceManager::singleton(); + foreach ($namespaceManager->getAllNamespaces() as $namespace) { if ($namespace->getUri() == $namespaceUri) { $modelId = $namespace->getModelId(); } } if (is_null($modelId)) { \common_Logger::d('modelId not found, need to add namespace '. $namespaceUri); - - //TODO bad way, need to find better - $dbWrapper = \core_kernel_classes_DbWrapper::singleton(); - $results = $dbWrapper->insert('models', array('modeluri' =>$namespaceUri)); - $result = $dbWrapper->query('select modelid from models where modeluri = ?', array($namespaceUri)); - $modelId = $result->fetch()['modelid']; - common_ext_NamespaceManager::singleton()->reset(); - + + /** @var ModelFactory $modelFactory */ + $modelFactory = $serviceManager->get(ModelFactory::SERVICE_ID); + $modelId = $modelFactory->addNewModel($namespaceUri); + $namespaceManager->reset(); } return $modelId; } -} \ No newline at end of file +} diff --git a/core/kernel/persistence/smoothsql/class.Resource.php b/core/kernel/persistence/smoothsql/class.Resource.php index 6e2c6695c..2d624073d 100644 --- a/core/kernel/persistence/smoothsql/class.Resource.php +++ b/core/kernel/persistence/smoothsql/class.Resource.php @@ -20,6 +20,7 @@ * 2017 (update and modification) Open Assessment Technologies SA (under the project TAO-PRODUCT); */ +use core_kernel_api_ModelFactory as ModelFactory; use oat\generis\model\OntologyRdf; use oat\oatbox\session\SessionService; use oat\oatbox\user\UserLanguageServiceInterface; @@ -36,19 +37,39 @@ class core_kernel_persistence_smoothsql_Resource implements core_kernel_persistence_ResourceInterface { + /** @var ModelFactory */ + protected $modelFactory; /** * @var core_kernel_persistence_smoothsql_SmoothModel */ private $model; + /** + * core_kernel_persistence_smoothsql_Resource constructor. + * + * @param core_kernel_persistence_smoothsql_SmoothModel $model + */ public function __construct(core_kernel_persistence_smoothsql_SmoothModel $model) { $this->model = $model; } + /** + * @return core_kernel_persistence_smoothsql_SmoothModel + */ protected function getModel() { return $this->model; } + + /** + * @return ModelFactory + */ + protected function getModelFactory() { + if ($this->modelFactory === null) { + $this->modelFactory = $this->getServiceLocator()->get(ModelFactory::SERVICE_ID); + } + return $this->modelFactory; + } /** * @return common_persistence_SqlPersistence @@ -58,11 +79,11 @@ protected function getPersistence() { } protected function getModelReadSqlCondition() { - return 'modelid IN ('.implode(',', $this->model->getReadableModels()).')'; + return $this->getModelFactory()->buildModelSqlCondition($this->model->getReadableModels()); } protected function getModelWriteSqlCondition() { - return 'modelid IN ('.implode(',',$this->model->getWritableModels()).')'; + return $this->getModelFactory()->buildModelSqlCondition($this->model->getWritableModels()); } protected function getNewTripleModelId() { @@ -105,6 +126,7 @@ public function getTypes( core_kernel_classes_Resource $resource) * @param Property property * @param array options * @return array + * @throws core_kernel_persistence_Exception */ public function getPropertyValues( core_kernel_classes_Resource $resource, core_kernel_classes_Property $property, $options = array()) { @@ -118,7 +140,6 @@ public function getPropertyValues( core_kernel_classes_Resource $resource, core $platform = $this->getPersistence()->getPlatForm(); // Define language if required - $lang = ''; $defaultLg = ''; if (isset($options['lg'])) { $lang = $options['lg']; @@ -137,14 +158,11 @@ public function getPropertyValues( core_kernel_classes_Resource $resource, core if ($one) { - // Select first - $query .= ' ORDER BY id DESC'; + // Select first only + $query .= ' ORDER BY ' . $this->getModelFactory()->getPropertySortingField() . ' DESC'; $query = $platform->limitStatement($query, 1, 0); - $result = $this->getPersistence()->query($query,array($resource->getUri(), $property->getUri(), $lang)); - } else { - // Select All - $result = $this->getPersistence()->query($query,array($resource->getUri(), $property->getUri(), $lang)); } + $result = $this->getPersistence()->query($query,array($resource->getUri(), $property->getUri(), $lang)); // Treat the query result if ($result == true) { @@ -207,33 +225,21 @@ public function setPropertyValue( core_kernel_classes_Resource $resource, core_ { $userId = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentUser()->getIdentifier(); $object = $object instanceof core_kernel_classes_Resource ? $object->getUri() : (string) $object; - $platform = $this->getPersistence()->getPlatForm(); - $lang = ""; + // Define language if required + $lang = ''; if ($property->isLgDependent()){ - if ($lg!=null){ - $lang = $lg; - } else { - $lang = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession()->getDataLanguage(); - } + $lang = $lg ?? $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession()->getDataLanguage(); } - $query = 'INSERT INTO statements (modelid, subject, predicate, object, l_language, author,epoch) - VALUES (?, ?, ?, ?, ?, ? , ?)'; - - $returnValue = $this->getPersistence()->exec($query, array( + return $this->getModelFactory()->addStatement( $this->getNewTripleModelId(), $resource->getUri(), $property->getUri(), $object, $lang, - $userId, - $platform->getNowExpression() - )); - - - - return (bool) $returnValue; + $userId + ); } /** @@ -247,52 +253,54 @@ public function setPropertyValue( core_kernel_classes_Resource $resource, core_ */ public function setPropertiesValues( core_kernel_classes_Resource $resource, $properties) { - $returnValue = (bool) false; + $returnValue = false; if (is_array($properties) && count($properties) > 0) { $session = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession(); - $platform = $this->getPersistence()->getPlatForm(); - $valuesToInsert = []; + $modelId = $this->getNewTripleModelId(); + $subject = $resource->getUri(); + $author = $session->getUser()->getIdentifier(); foreach ($properties as $propertyUri => $value) { $property = $this->getModel()->getProperty($propertyUri); $lang = ($property->isLgDependent() ? $session->getDataLanguage() : ''); - $formatedValues = []; - if ($value instanceof core_kernel_classes_Resource) { - $formatedValues[] = $value->getUri(); - - } elseif (is_array($value)) { - foreach($value as $val){ - $formatedValues[] = ($val instanceof core_kernel_classes_Resource) ? $val->getUri() : $val; - } - } else { - $formatedValues[] = ($value == null) ? '' : $value; - } + $formattedValues = $this->formatValue($value); - foreach ($formatedValues as $object) { - $valuesToInsert[] = [ - 'modelid' => $this->getNewTripleModelId(), - 'subject' => $resource->getUri(), - 'predicate' => $property->getUri(), - 'object' => $object, - 'l_language' => $lang, - 'author' => $session->getUser()->getIdentifier(), - 'epoch' => $platform->getNowExpression() - ]; + foreach ($formattedValues as $object) { + $returnValue |= $this->getModelFactory()->addStatement($modelId, $subject, $property->getUri(), $object, $lang, $author); } } - - $returnValue = $this->getPersistence()->insertMultiple('statements', $valuesToInsert); } - return (bool) $returnValue; + return $returnValue; } + /** + * Formats single or multiple value + * @param mixed $value + * @return array + */ + private function formatValue($value) + { + if (!is_array($value)) { + $value = [$value]; + } + + $formattedValues = []; + foreach ($value as $val) { + $formattedValues[] = $val instanceof core_kernel_classes_Resource + ? $val->getUri() + : ($val ?? ''); + } + + return $formattedValues; + } + /** * Short description of method setPropertyValueByLg * @@ -306,29 +314,16 @@ public function setPropertiesValues( core_kernel_classes_Resource $resource, $pr */ public function setPropertyValueByLg( core_kernel_classes_Resource $resource, core_kernel_classes_Property $property, $value, $lg) { - $returnValue = (bool) false; - - - - $platform = $this->getPersistence()->getPlatForm(); $userId = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentUser()->getIdentifier(); - - $query = 'INSERT INTO statements (modelid,subject,predicate,object,l_language,author,epoch) - VALUES (?, ?, ?, ?, ?, ?, ?)'; - - $returnValue = $this->getPersistence()->exec($query, array( - $this->getNewTripleModelId(), - $resource->getUri(), - $property->getUri(), - $value, - ($property->isLgDependent() ? $lg : ''), - $userId, - $platform->getNowExpression() - )); - - - return (bool) $returnValue; + return $this->getModelFactory()->addStatement( + $this->getNewTripleModelId(), + $resource->getUri(), + $property->getUri(), + $value, + ($property->isLgDependent() ? $lg : ''), + $userId + ); } /** @@ -343,8 +338,6 @@ public function setPropertyValueByLg( core_kernel_classes_Resource $resource, c */ public function removePropertyValues( core_kernel_classes_Resource $resource, core_kernel_classes_Property $property, $options = array()) { - $returnValue = (bool) false; - // Optional params $pattern = isset($options['pattern']) && !is_null($options['pattern']) ? $options['pattern'] : null; $like = isset($options['like']) && $options['like'] == true ? true : false; @@ -415,25 +408,15 @@ public function removePropertyValues( core_kernel_classes_Resource $resource, c */ public function removePropertyValueByLg( core_kernel_classes_Resource $resource, core_kernel_classes_Property $property, $lg, $options = array()) { - $returnValue = (bool) false; - $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, array ( + + return (bool) $this->getPersistence()->exec($sqlQuery, array ( $resource->getUri(), $property->getUri(), ($property->isLgDependent() ? $lg : '') )); - - if (!$returnValue){ - $returnValue = false; - } - - - - return (bool) $returnValue; } /** @@ -507,39 +490,39 @@ public function getUsedLanguages( core_kernel_classes_Resource $resource, core_ * @param Resource resource * @param array excludedProperties * @return core_kernel_classes_Resource + * @throws common_exception_Error */ public function duplicate( core_kernel_classes_Resource $resource, $excludedProperties = array()) { - $returnValue = null; - $newUri = $this->getServiceLocator()->get(UriProvider::SERVICE_ID)->provide(); $collection = $this->getRdfTriples($resource); - if ($collection->count() > 0) { - - $platform = $this->getPersistence()->getPlatForm(); - $user = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentUser()->getIdentifier(); - $valuesToInsert = []; + if ($collection->count() === 0) { + return null; + } + + $newUri = $this->getServiceLocator()->get(UriProvider::SERVICE_ID)->provide(); + $user = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentUser()->getIdentifier(); + $modelId = $this->getNewTripleModelId(); + $addedRows = false; - foreach ($collection->getIterator() as $triple) { - if (!in_array($triple->predicate, $excludedProperties)) { - $valuesToInsert[] = [ - 'modelid' => $this->getNewTripleModelId(), - 'subject' => $newUri, - 'predicate'=> $triple->predicate, - 'object' => ($triple->object == null) ? '' : $triple->object, - 'l_language' => ($triple->lg == null) ? '' : $triple->lg, - 'author' => $user, - 'epoch' => $platform->getNowExpression() - ]; - } - } - - if ($this->getPersistence()->insertMultiple('statements', $valuesToInsert)) { - $returnValue = $this->getModel()->getResource($newUri); - } - } + foreach ($collection->getIterator() as $triple) { + if (!in_array($triple->predicate, $excludedProperties)) { + $addedRows |= $this->getModelFactory()->addStatement( + $modelId, + $newUri, + $triple->predicate, + $triple->object ?? '', + $triple->lg ?? '', + $user + ); + } + } - return $returnValue; + if ($addedRows) { + return $this->getModel()->getResource($newUri); + } + + return null; } /** @@ -553,8 +536,6 @@ public function duplicate( core_kernel_classes_Resource $resource, $excludedProp */ public function delete( core_kernel_classes_Resource $resource, $deleteReference = false) { - $returnValue = (bool) false; - $query = 'DELETE FROM statements WHERE subject = ? AND '.$this->getModelWriteSqlCondition(); $returnValue = $this->getPersistence()->exec($query, array($resource->getUri())); @@ -662,10 +643,6 @@ public function setType( core_kernel_classes_Resource $resource, core_kernel_cl */ public function removeType( core_kernel_classes_Resource $resource, core_kernel_classes_Class $class) { - $returnValue = (bool) false; - - - $query = 'DELETE FROM statements WHERE subject = ? AND predicate = ? AND '. $this->getPersistence()->getPlatForm()->getObjectTypeCondition() .' = ?'; diff --git a/core/kernel/persistence/smoothsql/class.SmoothIterator.php b/core/kernel/persistence/smoothsql/class.SmoothIterator.php index 872e44146..d0a641e26 100644 --- a/core/kernel/persistence/smoothsql/class.SmoothIterator.php +++ b/core/kernel/persistence/smoothsql/class.SmoothIterator.php @@ -18,6 +18,9 @@ * */ +use core_kernel_api_ModelFactory as ModelFactory; +use Zend\ServiceManager\ServiceLocatorAwareTrait; + /** * Iterator over all triples * @@ -27,16 +30,18 @@ class core_kernel_persistence_smoothsql_SmoothIterator extends common_persistence_sql_QueryIterator { + use ServiceLocatorAwareTrait; + /** * Constructor of the iterator expecting the model ids * + * @param common_persistence_SqlPersistence $persistence * @param array $modelIds */ public function __construct(common_persistence_SqlPersistence $persistence, $modelIds = null) { - $query = 'SELECT * FROM statements ' - .(is_null($modelIds) ? '' : 'WHERE modelid IN ('.implode(',', $modelIds).') ') - .'ORDER BY id'; - parent::__construct($persistence, $query); + /** @var ModelFactory $modelFactory */ + $modelFactory = $this->getServiceLocator()->get(ModelFactory::SERVICE_ID); + parent::__construct($persistence, $modelFactory->getIteratorQuery($modelIds)); } /** @@ -46,7 +51,8 @@ public function __construct(common_persistence_SqlPersistence $persistence, $mod */ function current() { $statement = parent::current(); - + + // TODO: create a constructor $triple = new core_kernel_classes_Triple(); $triple->modelid = $statement["modelid"]; $triple->subject = $statement["subject"]; @@ -57,4 +63,4 @@ function current() { $triple->author = $statement["author"]; return $triple; } -} \ No newline at end of file +} diff --git a/core/kernel/persistence/smoothsql/class.SmoothRdf.php b/core/kernel/persistence/smoothsql/class.SmoothRdf.php index 8baa34e07..ef5147200 100644 --- a/core/kernel/persistence/smoothsql/class.SmoothRdf.php +++ b/core/kernel/persistence/smoothsql/class.SmoothRdf.php @@ -18,6 +18,7 @@ * */ +use core_kernel_api_ModelFactory as ModelFactory; use oat\generis\model\data\RdfInterface; use oat\generis\model\OntologyRdf; use oat\generis\model\OntologyRdfs; @@ -63,8 +64,18 @@ public function add(\core_kernel_classes_Triple $triple) { if (!in_array($triple->modelid, $this->model->getReadableModels())) { $this->model->addReadableModel($triple->modelid); } - $query = "INSERT INTO statements ( modelId, subject, predicate, object, l_language, epoch, author) VALUES ( ? , ? , ? , ? , ? , ?, ?);"; - $success = $this->getPersistence()->exec($query, array($triple->modelid, $triple->subject, $triple->predicate, $triple->object, is_null($triple->lg) ? '' : $triple->lg, $this->getPersistence()->getPlatForm()->getNowExpression(), is_null($triple->author) ? '' : $triple->author)); + + /** @var ModelFactory $modelFactory */ + $modelFactory = $this->getServiceManager()->get(ModelFactory::SERVICE_ID); + $success = $modelFactory->addStatement( + $triple->modelid, + $triple->subject, + $triple->predicate, + $triple->object, + $triple->lg ?? '', + $triple->author ?? '' + ); + if ($triple->predicate == OntologyRdfs::RDFS_SUBCLASSOF || $triple->predicate == OntologyRdf::RDF_TYPE) { $eventManager = $this->getServiceManager()->get(EventManager::CONFIG_ID); $eventManager->trigger(new ResourceCreated(new core_kernel_classes_Resource($triple->subject))); @@ -97,4 +108,4 @@ public function getServiceManager() { return ServiceManager::getServiceManager(); } -} \ No newline at end of file +} diff --git a/core/kernel/persistence/smoothsql/install/SmoothRdsModel.php b/core/kernel/persistence/smoothsql/install/SmoothRdsModel.php index ba3951414..dc050315f 100644 --- a/core/kernel/persistence/smoothsql/install/SmoothRdsModel.php +++ b/core/kernel/persistence/smoothsql/install/SmoothRdsModel.php @@ -19,40 +19,27 @@ */ namespace oat\generis\model\kernel\persistence\smoothsql\install; +use core_kernel_api_ModelFactory as ModelFactory; use Doctrine\DBAL\Schema\Schema; +use oat\oatbox\service\ConfigurableService; +use oat\oatbox\service\ServiceManager; + /** * Helper to setup the required tables for generis smoothsql */ -class SmoothRdsModel { - +class SmoothRdsModel extends ConfigurableService +{ /** * * @param Schema $schema * @return \Doctrine\DBAL\Schema\Schema */ - public static function addSmoothTables(Schema $schema) + public function addSmoothTables(Schema $schema) { - $table = $schema->createTable("models"); - $table->addColumn('modelid', "integer",["notnull" => true,"autoincrement" => true]); - $table->addColumn('modeluri', "string", ["length" => 255,"default" => null]); - $table->addOption('engine' , 'MyISAM'); - $table->setPrimaryKey(['modelid']); - - $table = $schema->createTable("statements"); - $table->addColumn("modelid", "integer",["notnull" => true,"default" => 0]); - $table->addColumn("subject", "string",["length" => 255,"default" => null]); - $table->addColumn("predicate", "string",["length" => 255,"default" => null]); - $table->addColumn("object", "text", ["default" => null,"notnull" => false]); - - $table->addColumn("l_language", "string",["length" => 255,"default" => null,"notnull" => false]); - $table->addColumn("id", "integer",["notnull" => true,"autoincrement" => true]); - $table->addColumn("author", "string",["length" => 255,"default" => null,"notnull" => false]); - $table->setPrimaryKey(["id"]); - $table->addOption('engine' , 'MyISAM'); - $table->addColumn("epoch", "string" , ["notnull" => null]); - - $table->addIndex(["subject","predicate"],"k_sp", [], ['lengths' => [164,164]]); - $table->addIndex(["predicate","object"],"k_po", [], ['lengths' => [164,164]]); + /** @var ModelFactory $modelFactory */ + $modelFactory = ServiceManager::getServiceManager()->get(ModelFactory::SERVICE_ID); + $modelFactory->createModelsTable($schema); + $modelFactory->createStatementsTable($schema); return $schema; } } diff --git a/core/kernel/persistence/smoothsql/search/GateWay.php b/core/kernel/persistence/smoothsql/search/GateWay.php index b5e4f03f5..3fbbc4eb2 100644 --- a/core/kernel/persistence/smoothsql/search/GateWay.php +++ b/core/kernel/persistence/smoothsql/search/GateWay.php @@ -98,11 +98,9 @@ public function search(QueryBuilderInterface $Builder) { } /** - * - * @param \PDOStatement $statement * @return array */ - protected function statementToArray(\PDOStatement $statement) { + protected function statementToArray($statement) { $result = []; while($row = $statement->fetch(\PDO::FETCH_OBJ)) { $result[] = $row; diff --git a/core/kernel/persistence/smoothsql/search/driver/TaoSearchDriver.php b/core/kernel/persistence/smoothsql/search/driver/TaoSearchDriver.php index db7c6aedf..c2f104f83 100644 --- a/core/kernel/persistence/smoothsql/search/driver/TaoSearchDriver.php +++ b/core/kernel/persistence/smoothsql/search/driver/TaoSearchDriver.php @@ -96,6 +96,7 @@ public function like() { $like = [ 'mysql' => 'LIKE', 'postgresql' => 'ILIKE', + 'gcp-spanner' => 'LIKE', ]; $name = $this->persistence->getPlatForm()->getName(); diff --git a/helpers/UuidPrimaryKeyTrait.php b/helpers/UuidPrimaryKeyTrait.php new file mode 100644 index 000000000..68a1bd570 --- /dev/null +++ b/helpers/UuidPrimaryKeyTrait.php @@ -0,0 +1,39 @@ +" + */ + +namespace oat\generis\Helper; + +use Exception; +use Ramsey\Uuid\Uuid; + +trait UuidPrimaryKeyTrait +{ + /** + * Generates a unique, not auto-increment based, primary key. + * + * @return string + * @throws Exception + */ + public function getUniquePrimaryKey() + { + return (string)Uuid::uuid4(); + } +} diff --git a/manifest.php b/manifest.php index c491310fb..f1447b793 100755 --- a/manifest.php +++ b/manifest.php @@ -32,7 +32,7 @@ 'label' => 'Generis Core', 'description' => 'Core extension, provide the low level framework and an API to manage ontologies', 'license' => 'GPL-2.0', - 'version' => '12.5.2', + 'version' => '12.6.0', 'author' => 'Open Assessment Technologies, CRP Henri Tudor', 'requires' => array(), 'models' => array( diff --git a/scripts/update/Updater.php b/scripts/update/Updater.php index 935e9c62e..4a8d6f2f3 100644 --- a/scripts/update/Updater.php +++ b/scripts/update/Updater.php @@ -476,5 +476,10 @@ public function update($initialVersion) $this->setVersion('12.4.1'); } $this->skip('12.4.1', '12.5.2'); + if ($this->isVersion('12.5.2')) { + // not sure about what to do in here. + + $this->setVersion('12.6.0'); + } } } diff --git a/test/GenerisTestCase.php b/test/GenerisTestCase.php index a8d2353ce..3f6e5659b 100755 --- a/test/GenerisTestCase.php +++ b/test/GenerisTestCase.php @@ -19,6 +19,8 @@ */ namespace oat\generis\test; +use core_kernel_api_ModelFactory as ModelFactory; +use oat\generis\model\kernel\api\RdsModelFactory; use oat\generis\model\kernel\persistence\smoothsql\install\SmoothRdsModel; use oat\oatbox\user\UserLanguageServiceInterface; use oat\oatbox\session\SessionService; @@ -39,14 +41,11 @@ class GenerisTestCase extends TestCase */ protected function getOntologyMock() { + $smoothRdsModel = new SmoothRdsModel(); $pm = $this->getSqlMock('mockSql'); $rds = $pm->getPersistenceById('mockSql'); $schema = $rds->getSchemaManager()->createSchema(); - $schema = SmoothRdsModel::addSmoothTables($schema); - $queries = $rds->getPlatform()->schemaToSql($schema); - foreach ($queries as $query){ - $rds->query($query); - } + $schema = $smoothRdsModel->addSmoothTables($schema); $session = new \common_session_AnonymousSession(); $sl = $this->getServiceLocatorMock([ @@ -56,6 +55,7 @@ protected function getOntologyMock() EventManager::SERVICE_ID => new EventManager(), LoggerService::SERVICE_ID => $this->prophesize(LoggerInterface::class)->reveal(), UriProvider::SERVICE_ID => new Bin2HexUriProvider([Bin2HexUriProvider::OPTION_NAMESPACE => 'http://ontology.mock/bin2hex#']), + ModelFactory::SERVICE_ID => new RdsModelFactory(), 'smoothcache' => new \common_cache_NoCache() ]); $session->setServiceLocator($sl); @@ -67,7 +67,13 @@ protected function getOntologyMock() 'cache' => 'smoothcache' ]); $model->setServiceLocator($sl); - + $smoothRdsModel->setServiceLocator($sl); + $schema = $smoothRdsModel->addSmoothTables($schema); + $queries = $rds->getPlatform()->schemaToSql($schema); + foreach ($queries as $query){ + $rds->query($query); + } + return $model; } diff --git a/test/unit/model/persistence/smoothsql/SmoothModelIteratorTest.php b/test/integration/model/persistence/smoothsql/SmoothModelIteratorTest.php similarity index 98% rename from test/unit/model/persistence/smoothsql/SmoothModelIteratorTest.php rename to test/integration/model/persistence/smoothsql/SmoothModelIteratorTest.php index ae50e901b..f7847fa7c 100644 --- a/test/unit/model/persistence/smoothsql/SmoothModelIteratorTest.php +++ b/test/integration/model/persistence/smoothsql/SmoothModelIteratorTest.php @@ -17,7 +17,8 @@ * Copyright (c) (original work) 2015 Open Assessment Technologies SA * */ -namespace oat\generis\test\unit\model\persistence\smoothsql; + +namespace oat\generis\test\integration\model\persistence\smoothsql; use Prophecy\Promise\ReturnPromise; use Prophecy\Argument; diff --git a/test/unit/model/persistence/smoothsql/SmoothRdfTest.php b/test/integration/model/persistence/smoothsql/SmoothRdfTest.php similarity index 98% rename from test/unit/model/persistence/smoothsql/SmoothRdfTest.php rename to test/integration/model/persistence/smoothsql/SmoothRdfTest.php index b2b5128bf..22b370796 100644 --- a/test/unit/model/persistence/smoothsql/SmoothRdfTest.php +++ b/test/integration/model/persistence/smoothsql/SmoothRdfTest.php @@ -17,7 +17,8 @@ * Copyright (c) (original work) 2015 Open Assessment Technologies SA * */ -namespace oat\generis\test\unit\model\persistence\smoothsql; + +namespace oat\generis\test\integration\model\persistence\smoothsql; use \core_kernel_persistence_smoothsql_SmoothRdf; use Prophecy\Prophet; @@ -171,4 +172,4 @@ public function testRemove() } } -?> \ No newline at end of file +?>