*/ class RdsStorage extends ConfigurableService implements RevisionStorageInterface, SchemaProviderInterface { public const REVISION_TABLE_NAME = 'revision'; public const REVISION_RESOURCE = 'resource'; public const REVISION_VERSION = 'version'; public const REVISION_USER = 'user'; public const REVISION_CREATED = 'created'; public const REVISION_MESSAGE = 'message'; public const DATA_TABLE_NAME = 'revision_data'; public const DATA_RESOURCE = 'resource'; public const DATA_VERSION = 'version'; public const DATA_SUBJECT = 'subject'; public const DATA_PREDICATE = 'predicate'; public const DATA_OBJECT = 'object'; public const DATA_LANGUAGE = 'language'; /** @var common_persistence_SqlPersistence */ private $persistence; /** * @return common_persistence_SqlPersistence */ protected function getPersistence() { if ($this->persistence === null) { $this->persistence = $this->getServiceLocator() ->get(PersistenceManager::SERVICE_ID) ->getPersistenceById($this->getPersistenceId()); } return $this->persistence; } /** * @param Revision $revision * @param Triple[] $data * * @return Revision */ public function addRevision(Revision $revision, array $data) { $this->getPersistence()->insert( self::REVISION_TABLE_NAME, [ self::REVISION_RESOURCE => $revision->getResourceId(), self::REVISION_VERSION => $revision->getVersion(), self::REVISION_USER => $revision->getAuthorId(), self::REVISION_MESSAGE => $revision->getMessage(), self::REVISION_CREATED => $revision->getDateCreated(), ] ); if (!empty($data)) { $this->saveData($revision, $data); } return $revision; } /** * * @param string $resourceId * @param int $version * * @return Revision * @throws RevisionNotFoundException */ public function getRevision(string $resourceId, int $version) { $queryBuilder = $this->getQueryBuilder() ->select('*') ->from(self::REVISION_TABLE_NAME) ->where(sprintf('%s = ?', self::REVISION_RESOURCE)) ->andWhere(sprintf('%s = ?', self::REVISION_VERSION)); $variables = $this->getPersistence() ->query($queryBuilder->getSQL(), [$resourceId, $version]) ->fetchAll(); if (count($variables) !== 1) { throw new RevisionNotFoundException($resourceId, $version); } $variable = reset($variables); return new Revision( $variable[self::REVISION_RESOURCE], $variable[self::REVISION_VERSION], $variable[self::REVISION_CREATED], $variable[self::REVISION_USER], $variable[self::REVISION_MESSAGE] ); } /** * @param string $resourceId * * @return Revision[] */ public function getAllRevisions(string $resourceId) { $queryBuilder = $this->getQueryBuilder() ->select('*') ->from(self::REVISION_TABLE_NAME) ->where(sprintf('%s = ?', self::REVISION_RESOURCE)); $variables = $this->getPersistence() ->query($queryBuilder->getSQL(), [$resourceId]) ->fetchAll(); return $this->buildRevisionCollection($variables); } /** * @param array $variables * @return Revision[] */ public function buildRevisionCollection(array $variables) { $revisions = []; foreach ($variables as $variable) { $revisions[] = new Revision( $variable[self::REVISION_RESOURCE], $variable[self::REVISION_VERSION], $variable[self::REVISION_CREATED], $variable[self::REVISION_USER], $variable[self::REVISION_MESSAGE] ); } return $revisions; } /** * @param Revision $revision * * @return TriplesCollection */ public function getData(Revision $revision) { $queryBuilder = $this->getQueryBuilder() ->select('*') ->from(self::DATA_TABLE_NAME) ->where(sprintf('%s = ?', self::DATA_RESOURCE)) ->andWhere(sprintf('%s = ?', self::DATA_VERSION)); $result = $this->getPersistence() ->query($queryBuilder->getSQL(), [$revision->getResourceId(), $revision->getVersion()]); $triples = new TriplesCollection(new common_Object()); while ($statement = $result->fetch()) { $triples->add($this->prepareDataObject($statement, $this->getLocalModel()->getModelId())); } return $triples; } /** * * @param Revision $revision * @param Triple[] $data * * @return bool */ protected function saveData(Revision $revision, array $data) { $dataToSave = []; foreach ($data as $triple) { $dataToSave[] = [ self::DATA_RESOURCE => $revision->getResourceId(), self::DATA_VERSION => $revision->getVersion(), self::DATA_SUBJECT => $triple->subject, self::DATA_PREDICATE => $triple->predicate, self::DATA_OBJECT => $triple->object, self::DATA_LANGUAGE => $triple->lg, ]; } return $this->getPersistence()->insertMultiple(self::DATA_TABLE_NAME, $dataToSave); } /** * @deprecated * @see getResourcesDataByQuery * @param string $query * @param array $options * @param string $predicate * @return array */ public function getResourcesUriByQuery(string $query, array $options = [], string $predicate = OntologyRdfs::RDFS_LABEL) { $result = $this->getSelectedResourcesDataByQuery( [self::DATA_RESOURCE], $query, $options, $predicate ); $resourcesUri = []; while ($statement = $result->fetch()) { $resourcesUri[] = $statement[self::DATA_RESOURCE]; } return $resourcesUri; } public function getResourcesDataByQuery(string $query, array $options = [], string $predicate = OntologyRdfs::RDFS_LABEL): array { $result = $this->getSelectedResourcesDataByQuery( [self::DATA_RESOURCE, self::DATA_OBJECT], $query, $options, $predicate ); $resourcesData= []; /** @var Revision $statement */ while ($statement = $result->fetch()) { $resourcesData[] = [ 'id' => $statement[self::DATA_RESOURCE], 'label' => $statement[self::DATA_OBJECT], ]; } return $resourcesData; } /** * @param string[] $selectedFields */ private function getSelectedResourcesDataByQuery( array $selectedFields, string $query, array $options, string $predicate ): Statement { $queryBuilder = $this->getQueryBuilder(); foreach ($selectedFields as $selectedField) { $queryBuilder->addSelect('rd.'.$selectedField); } $queryBuilder->from(self::DATA_TABLE_NAME, 'rd'); $queryBuilder->join('rd', 'statements', 'st', 'st.subject = rd.'.self::DATA_RESOURCE); $fieldName = self::DATA_OBJECT; $condition = "rd.$fieldName {$this->getLike()} '%$query%'"; $queryBuilder->where($condition); $queryBuilder->andWhere(sprintf('rd.%s = \'%s\'', self::DATA_PREDICATE, $predicate)); if (isset($options['limit'])) { $queryBuilder->setMaxResults((int)$options['limit']); } if (isset($options['offset'])) { $queryBuilder->setFirstResult((int)$options['offset']); } $sort = isset($options['sort']) ? $options['sort'] : self::DATA_RESOURCE; $order = isset($options['order']) ? strtoupper($options['order']) : ' ASC'; $queryBuilder->addOrderBy($sort, $order); foreach ($selectedFields as $selectedField) { $queryBuilder->addGroupBy('rd.'.$selectedField); } return $this->getPersistence()->query($queryBuilder->getSQL()); } /** * @param array $statement * @param string $modelId * * @return Triple */ private function prepareDataObject(array $statement, string $modelId) { $triple = new Triple(); $triple->modelid = $modelId; $triple->subject = $statement[self::DATA_SUBJECT]; $triple->predicate = $statement[self::DATA_PREDICATE]; $triple->object = $statement[self::DATA_OBJECT]; $triple->lg = $statement[self::DATA_LANGUAGE]; return $triple; } /** * @return QueryBuilder */ protected function getQueryBuilder() { return $this->getPersistence()->getPlatForm()->getQueryBuilder(); } /** * @return common_ext_Namespace */ protected function getLocalModel() { return common_ext_NamespaceManager::singleton()->getLocalNamespace(); } /** * @return string */ protected function getLike() { return (new TaoSearchDriver())->like(); } /** * @inheritDoc */ public function getSchema(Schema $schema) { return $this->getServiceLocator()->get(RdsSqlSchema::class)->getSchema($schema); } public function getPersistenceId() { return $this->getOption(self::OPTION_PERSISTENCE); } /** * {@inheritDoc} * @see \oat\generis\persistence\sql\SchemaProviderInterface::provideSchema() */ public function provideSchema(SchemaCollection $schemaCollection) { $schema = $schemaCollection->getSchema($this->getPersistenceId()); $this->getSchema($schema); } }