diff --git a/sparql_entity_storage/API.md b/sparql_entity_storage/API.md deleted file mode 100644 index 50589122..00000000 --- a/sparql_entity_storage/API.md +++ /dev/null @@ -1,98 +0,0 @@ -# SPARQL Storage Entity API - -## SPARQL Graphs - -Entities using the SPARQL storage can be stored in different graphs. Graphs can -be used to store different versions or states of the same entity. Depending on -the use case you can use graphs to store a draft version of the entity. - -### SPARQL graphs storage - -Graphs are handled by the `sparql.graph_handler` service which is injected in -the `Query` and the `SparqlEntityStorage` classes. There are a number of -methods offered to handle the graphs. - -### Graphs CRUD - -Graphs are config entities of type `sparql_graph` and are supported by the -Drupal API. You can add, edit, delete graphs also by using the UI provided at -`/admin/config/sparql/graph`. The `default` graph, shipped with -`sparql_entity_storage` module cannot be deleted or restricted to specific -entity types. However, you can still edit its name and description. Only enabled -graphs are taken into account by the SPARQL backend. - -The order of graph entities is important. You can configure a priority by -settings the `weight` property. Also this could be done in the UI. - -### Handling entities and graphs - -#### Entity creation - -Set a specific graph to a new entity: - -```php -// We're using the `sparql_test` testing module & entity: -$storage = \Drupal::entityTypeManager()->getStorage('sparql_test'); -$entity = $storage->create([ - 'id' => 'http://example.com', - 'type' => 'fruit', - 'graph' => 'draft', -]); -$entity->save(); -``` - -If no `'graph'` is set, the entity will be saved in the topmost graph. The -topmost graph is the graph witch has the lowest `weight` property. - -#### Reading the graph of an entity - -```php -$graph_id = $entity->get('graph')->target_id; -// or... -$graph_id = $entity->graph->target_id; - -``` - -#### Loading an entity from a specific graph - -```php -$storage = \Drupal::entityTypeManager()->getStorage('sparql_test'); - -// Load from the default graph (the tompost graph in the list). -$entity = $storage->load($id); - -// Load from the 'draft' graph. -$entity = $storage->load($id, ['draft']); - -// Load from the first graph where the entity exists. First, the storage will -// attempt to load the entity from the 'draft' graph. If this entity doesn't -// exist in the 'draft' graph, will fallback to the next one which is 'sync' and -// so on. If the entity is not found in any of the graphs, normal behaviour is -// in place: will return NULL. -$entity = $storage->load($id, ['draft', 'sync', 'obsolete', ...]); - -// Load multiple entities using a graph candidate list. -$entities = $storage->loadMultiple($ids, ['draft', 'sync', 'obsolete', ...]); -``` - -__Note__: When the list of graph candidates is not specified (first example), -the candidates are all enabled graph entities, ordered by the weight property. - -#### Saving in a different graph - -```php -$storage = \Drupal::entityTypeManager()->getStorage('sparql_test'); -$entity = $storage->load($id, ['draft']); -$entity->set('graph', 'default')->save(); -``` - -#### Using graphs with entity query - -```php -$storage = \Drupal::entityTypeManager()->getStorage('sparql_test'); -$query = $storage->getQuery; -$ids = $query - ->condition('type', 'fruit') - ->graphs(['default', 'draft']) - ->execute(); -``` diff --git a/sparql_entity_storage/README.md b/sparql_entity_storage/README.md deleted file mode 100644 index c9b85a53..00000000 --- a/sparql_entity_storage/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# Description - -The __SPARQL Entity Storage__ module offers a -[SPARQL](https://en.wikipedia.org/wiki/SPARQL) backend for Drupal entities. The -module provides an entity storage and query. Simply enabling the module, doesn't -bring any user visible new feature, the module is a prerequisite for other -modules that are defining Drupal entities that requires a SPARQL triple-store -backend. A very simple example of such an entity is the `sparql_test` entity -provided in the __SPARQL Test__ testing module, included in this package (see -the [SparqlTest](./tests/modules/sparql_test/src/Entity/SparqlTest.php) class). -A more sophisticated module that uses the SPARQL backend, and runs already in -the wild, is the [RDF Entity](https://www.drupal.org/project/rdf_entity) module. -The entity provided there (`rdf_entity`) can be used as it is, can be extended -or, simply, used as an example when designing a new entity type. - -# Getting started - -A working SPARQL endpoint is needed. You could either use a remote SPARQL -endpoint, or you could set one up locally. Virtuoso is one of the more robust -triple store solutions available, but any solution would do. - -@todo Create an example module that uses -[http://dbpedia.org/sparql](http://dbpedia.org/sparql) - -## Setting up Virtuoso - -### On a Debian based system - -`apt-cache search "^virtuoso"` will show you available packages. - -``` -$ apt-get install virtuoso-opensource -$ service virtuoso-opensource-6.1 start -``` - -(Set the password during installation) - -### On a MacOS system - -- Install Homebrew (see http://brew.sh) -- `$ brew install virtuoso` -- Start Virtuoso - ``` - # The version might be differnet than 7.2.4.2. - $ cd /usr/local/Cellar/virtuoso/7.2.4.2/var/lib/virtuoso/db - $ virtuoso-t -f & - ``` -- Administer at -[http://localhost:8890/conductor/](http://localhost:8890/conductor/). Login with dba/dba. - -### On an Arch Linux based system - -- Install the - [Virtuoso AUR package](https://aur.archlinux.org/packages/virtuoso/). -- `# systemctl start virtuoso` - -Go to -[http://localhost:8890/conductor/](http://localhost:8890/conductor/) -and login in with: dba - yourpass. - -- Grant 'update' rights to the SPARQL user: -- System admin -> Users -> SPARQL (edit) -- Account roles -> Put SPARQL_UPDATE in 'Selected' - -## Connecting Drupal to the SPARQL endpoint - -The following example demonstrates the use with a local Virtuoso installation. To connect Drupal to the endpoint, the db connection should be added to the settings.php file. - -```php -$databases['sparql_default']['sparql'] = [ - 'prefix' => '', - 'host' => '127.0.0.1', - 'port' => '8890', - 'namespace' => 'Drupal\\Driver\\Database\\sparql', - 'driver' => 'sparql', - // Optional. This is actually the endpoint path. If omitted, 'sparql' will - // be used. - 'database' => 'data/endpoint', - // If the connection to the endpoint should be HTTPS secured. If omitted, - // FALSE is assumed. - 'https' => FALSE, -]; -``` - -## Content translation -Entities using SPARQL storage support basic content translations. This is still WIP. - -_Note:_ If content translations are enabled, the 'langcode' property _must_ be mapped, otherwise entity reference fields will not store information. diff --git a/sparql_entity_storage/composer.json b/sparql_entity_storage/composer.json deleted file mode 100644 index ab4b9225..00000000 --- a/sparql_entity_storage/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "drupal/sparql_entity_storage", - "description": "Provides SPARQL entity storage and query for Drupal entities.", - "type": "drupal-module", - "homepage": "https://drupal.org/project/sparql_entity_storage", - "support": { - "issues": "https://drupal.org/project/issues/sparql_entity_storage", - "source": "https://cgit.drupalcode.org/sparql_entity_storage" - }, - "license": "GPL-2.0+", - "require": { - "php": ">=7.1", - "easyrdf/easyrdf": "0.10.0-alpha.1 as 0.9.2", - "ml/json-ld": "^1.0" - }, - "require-dev": { - "minimaxir/big-list-of-naughty-strings": "dev-master" - }, - "autoload": { - "classmap": [ - "driver/sparql/Connection.php" - ] - } -} diff --git a/sparql_entity_storage/config/install/sparql_entity_storage.graph.default.yml b/sparql_entity_storage/config/install/sparql_entity_storage.graph.default.yml deleted file mode 100644 index 6772c5ce..00000000 --- a/sparql_entity_storage/config/install/sparql_entity_storage.graph.default.yml +++ /dev/null @@ -1,7 +0,0 @@ -langcode: en -status: true -id: default -weight: 0 -name: Default -description: 'Default graph. This is available for all entity types and bundles.' -entity_types: null diff --git a/sparql_entity_storage/config/schema/sparql_entity_storage.schema.yml b/sparql_entity_storage/config/schema/sparql_entity_storage.schema.yml deleted file mode 100644 index 61bf1e45..00000000 --- a/sparql_entity_storage/config/schema/sparql_entity_storage.schema.yml +++ /dev/null @@ -1,81 +0,0 @@ -# Schema for sparql_entity_storage module configuration. - -field.storage.*.*.third_party.sparql_entity_storage: - type: mapping - mapping: - 'mapping': - type: sequence - label: 'Column' - sequence: - type: mapping - mapping: - predicate: - type: string - label: 'Predicate' - format: - type: string - label: 'Value format' - -sparql_entity_storage.graph.*: - type: config_entity - label: 'SPARQL graph' - mapping: - id: - type: string - label: ID - weight: - type: integer - label: Weight - name: - type: label - label: Name - description: - type: text - label: Description - entity_types: - type: sequence - nullable: true - label: 'Entity types' - sequence: - type: string - label: 'Entity type' - -sparql_entity_storage.mapping.*: - type: config_entity - label: 'Stores the mapping between Drupal bundle settings and RDF representation' - mapping: - id: - type: string - label: ID - entity_type_id: - type: string - label: 'Referred entity type' - bundle: - type: string - label: 'Referred bundle' - rdf_type: - type: string - label: 'RDF type mapping' - graph: - type: sequence - sequence: - type: string - label: 'The mapping of a graph definition to a graph URI.' - base_fields_mapping: - type: sequence - label: 'The base fields mapping' - sequence: - type: sequence - label: 'Column' - sequence: - type: mapping - mapping: - predicate: - type: string - label: 'Predicate' - format: - type: string - label: 'Value format' - entity_id_plugin: - type: string - label: 'The plugin that generates the entity ID' diff --git a/sparql_entity_storage/driver/sparql/Connection.php b/sparql_entity_storage/driver/sparql/Connection.php deleted file mode 100644 index 0f51389d..00000000 --- a/sparql_entity_storage/driver/sparql/Connection.php +++ /dev/null @@ -1,435 +0,0 @@ -easyRdfClient = $easy_rdf_client; - $this->connectionOptions = $connection_options; - } - - /** - * {@inheritdoc} - */ - public function getSparqlClient(): Client { - return $this->easyRdfClient; - } - - /** - * {@inheritdoc} - */ - public function query(string $query, array $args = [], array $options = []): Result { - return $this->doQuery($query, $args, $options); - } - - /** - * {@inheritdoc} - */ - public function constructQuery(string $query, array $args = [], array $options = []): Graph { - return $this->doQuery($query, $args, $options); - } - - /** - * Execute the query against the endpoint. - * - * @param string $query - * The string query to execute. - * @param array $args - * An array of arguments for the query. - * @param array $options - * An associative array of options to control how the query is run. - * - * @return \EasyRdf\Sparql\Result|\EasyRdf\Graph - * The query result. - * - * @throws \InvalidArgumentException - * If $args value is passed but arguments replacement is not yet - * supported. To be removed in #55. - * @throws SparqlQueryException - * Exception during query execution, e.g. timeout. - * - * @see https://github.com/ec-europa/sparql_entity_storage/issues/1 - */ - protected function doQuery(string $query, array $args = [], array $options = []) { - // @todo Remove this in #1. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/1 - if ($args) { - throw new \InvalidArgumentException('Replacement arguments are not yet supported.'); - } - - if ($this->logger) { - $query_start = microtime(TRUE); - } - - try { - // @todo Implement argument replacement in #1. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/1 - $results = $this->easyRdfClient->query($query); - } - catch (EasyRdfException $exception) { - // Re-throw the exception, but with the query as message. - throw new SparqlQueryException('Execution of query failed: ' . $query); - } - - if ($this->logger) { - $query_end = microtime(TRUE); - $this->log($query, $args, $query_end - $query_start); - } - - return $results; - } - - /** - * {@inheritdoc} - */ - public function update(string $query, array $args = [], array $options = []): Result { - // @todo Remove this in #1. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/1 - if ($args) { - throw new \InvalidArgumentException('Replacement arguments are not yet supported.'); - } - - if ($this->logger) { - $query_start = microtime(TRUE); - } - - try { - // @todo Implement argument replacement in #1. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/1 - $result = $this->easyRdfClient->update($query); - } - catch (EasyRdfException $exception) { - // Re-throw the exception, but with the query as message. - throw new SparqlQueryException('Execution of query failed: ' . $query); - } - - if ($this->logger) { - $query_end = microtime(TRUE); - $this->log($query, $args, $query_end - $query_start); - } - - return $result; - } - - /** - * {@inheritdoc} - */ - public function getQueryUri(): string { - return $this->easyRdfClient->getQueryUri(); - } - - /** - * {@inheritdoc} - */ - public function setLogger(Log $logger): void { - $this->logger = $logger; - } - - /** - * {@inheritdoc} - */ - public function getLogger(): ?Log { - return $this->logger; - } - - /** - * {@inheritdoc} - */ - public static function open(array &$connection_options = []): Client { - $enpoint_path = !empty($connection_options['database']) ? trim($connection_options['database'], ' /') : ''; - // After trimming the value might be ''. Testing again. - $enpoint_path = $enpoint_path ?: 'sparql'; - $protocol = empty($connection_options['https']) ? 'http' : 'https'; - - $connect_string = "{$protocol}://{$connection_options['host']}:{$connection_options['port']}/{$enpoint_path}"; - - return new Client($connect_string); - } - - /** - * {@inheritdoc} - */ - public function setTarget(string $target = NULL): void { - if (!isset($this->target)) { - $this->target = $target; - } - } - - /** - * {@inheritdoc} - */ - public function getTarget(): ?string { - return $this->target; - } - - /** - * {@inheritdoc} - */ - public function setKey(string $key): void { - if (!isset($this->key)) { - $this->key = $key; - } - } - - /** - * {@inheritdoc} - */ - public function getKey(): ?string { - return $this->key; - } - - /** - * {@inheritdoc} - */ - public function getConnectionOptions(): array { - return $this->connectionOptions; - } - - /** - * {@inheritdoc} - */ - public function destroy():void {} - - /** - * Logs a query duration in the DB logger. - * - * @param string $query - * The query to be logged. - * @param array $args - * Arguments passed to the query. - * @param float $duration - * The duration of the query run. - * - * @throws \RuntimeException - * If an attempt to log was made but the logger is not started. - */ - protected function log(string $query, array $args, float $duration): void { - if (!$this->logger) { - throw new \RuntimeException('Cannot log query as the logger is not started.'); - } - $this->logger->log($this->getStatement()->setQuery($query), $args, $duration); - } - - /** - * Returns and statically caches a DB statement stub used to log a query. - * - * The Drupal core database logger cannot be swapped because, instead of being - * injected, is hardcoded in \Drupal\Core\Database\Database::startLog(). But - * the \Drupal\Core\Database\Log::log() is expecting a database statement of - * type \Drupal\Core\Database\StatementInterface as first argument and the - * SPARQL database driver uses no StatementInterface class. We workaround this - * limitation by faking a database statement object just to honour the logger - * requirement. We use a statement stub that only stores the connection and - * the query to be used when logging the event. - * - * @return \Drupal\sparql_entity_storage\Database\Driver\sparql\StatementStub - * A faked statement object. - * - * @see \Drupal\Core\Database\Database::startLog() - * @see \Drupal\Core\Database\Log - * @see \Drupal\Core\Database\StatementInterface - * @see \Drupal\sparql_entity_storage\Database\Driver\sparql\StatementStub - * @see \Drupal\Driver\Database\sparql\Connection::log() - */ - protected function getStatement(): StatementStub { - if (!isset($this->statementStub)) { - $this->statementStub = (new StatementStub())->setDatabaseConnection($this); - } - return $this->statementStub; - } - - /** - * Creates an array of database connection options from a URL. - * - * @param string $url - * The URL. - * @param string $root - * The root directory of the Drupal installation. Some database drivers, - * like for example SQLite, need this information. - * - * @return array - * The connection options. - * - * @throws \InvalidArgumentException - * Exception thrown when the provided URL does not meet the minimum - * requirements. - * - * @see \Drupal\Core\Database\Database::convertDbUrlToConnectionInfo() - * - * @internal - * This method should not be called. Use - * \Drupal\Core\Database\Database::convertDbUrlToConnectionInfo() instead. - */ - public static function createConnectionOptionsFromUrl($url, $root) { - $url_components = parse_url($url); - if (!isset($url_components['scheme'], $url_components['host'], $url_components['path'])) { - throw new \InvalidArgumentException('Minimum requirement: driver://host/database'); - } - - $url_components += [ - 'user' => '', - 'pass' => '', - 'fragment' => '', - ]; - - // Remove leading slash from the URL path. - if ($url_components['path'][0] === '/') { - $url_components['path'] = substr($url_components['path'], 1); - } - - // Use reflection to get the namespace of the class being called. - $reflector = new \ReflectionClass(get_called_class()); - - $database = [ - 'driver' => $url_components['scheme'], - 'username' => $url_components['user'], - 'password' => $url_components['pass'], - 'host' => $url_components['host'], - 'database' => $url_components['path'], - 'namespace' => $reflector->getNamespaceName(), - ]; - - if (isset($url_components['port'])) { - $database['port'] = $url_components['port']; - } - - if (!empty($url_components['fragment'])) { - $database['prefix']['default'] = $url_components['fragment']; - } - - return $database; - } - - /** - * Creates a URL from an array of database connection options. - * - * @param array $connection_options - * The array of connection options for a database connection. - * - * @return string - * The connection info as a URL. - * - * @throws \InvalidArgumentException - * Exception thrown when the provided array of connection options does not - * meet the minimum requirements. - * - * @see \Drupal\Core\Database\Database::getConnectionInfoAsUrl() - * - * @internal - * This method should not be called. Use - * \Drupal\Core\Database\Database::getConnectionInfoAsUrl() instead. - */ - public static function createUrlFromConnectionOptions(array $connection_options) { - if (!isset($connection_options['driver'], $connection_options['database'])) { - throw new \InvalidArgumentException("As a minimum, the connection options array must contain at least the 'driver' and 'database' keys"); - } - - $user = ''; - if (isset($connection_options['username'])) { - $user = $connection_options['username']; - if (isset($connection_options['password'])) { - $user .= ':' . $connection_options['password']; - } - $user .= '@'; - } - - $host = empty($connection_options['host']) ? 'localhost' : $connection_options['host']; - - $db_url = $connection_options['driver'] . '://' . $user . $host; - - if (isset($connection_options['port'])) { - $db_url .= ':' . $connection_options['port']; - } - - $db_url .= '/' . $connection_options['database']; - - if (isset($connection_options['prefix']['default']) && $connection_options['prefix']['default'] !== '') { - $db_url .= '#' . $connection_options['prefix']['default']; - } - - return $db_url; - } - -} - -/** - * @} End of "addtogroup database". - */ diff --git a/sparql_entity_storage/sparql_entity_storage.api.php b/sparql_entity_storage/sparql_entity_storage.api.php deleted file mode 100644 index 8b2b7389..00000000 --- a/sparql_entity_storage/sparql_entity_storage.api.php +++ /dev/null @@ -1,24 +0,0 @@ -getType() == 'text_long') { - // Handle multiple values in a field. - foreach ($values as &$value) { - $value['format'] == 'my_custom_persistent_filter'; - } - } -} diff --git a/sparql_entity_storage/sparql_entity_storage.info.yml b/sparql_entity_storage/sparql_entity_storage.info.yml deleted file mode 100644 index 769d6498..00000000 --- a/sparql_entity_storage/sparql_entity_storage.info.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: 'SPARQL Entity Storage' -type: module -description: 'Provides SPARQL entity storage and query for Drupal entities.' -package: Custom -php: 7.1 -core: 8.x -dependencies: -- options diff --git a/sparql_entity_storage/sparql_entity_storage.install b/sparql_entity_storage/sparql_entity_storage.install deleted file mode 100644 index d1cc501a..00000000 --- a/sparql_entity_storage/sparql_entity_storage.install +++ /dev/null @@ -1,27 +0,0 @@ -getStorageClass()))) { - return; - } - - $fields['graph'] = BaseFieldDefinition::create('entity_reference') - ->setName('graph') - ->setLabel(t('The graph where the entity is stored.')) - ->setTargetEntityTypeId($entity_type->id()) - ->setCustomStorage(TRUE) - ->setSetting('target_type', 'sparql_graph'); -} - -/** - * Implements hook_form_alter(). - */ -function sparql_entity_storage_form_field_storage_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) { - // Only add mapping form element to fields of entities implementing - // SparqlEntityStorageInterface. - $id = $form_state->get('entity_type_id'); - if (!$id) { - return; - } - $storage = \Drupal::entityTypeManager()->getStorage($id); - if (!$storage instanceof SparqlEntityStorageInterface) { - return; - } - - $form_obj = $form_state->getFormObject(); - /** @var \Drupal\field\Entity\FieldStorageConfig $entity */ - $entity = $form_obj->getEntity(); - $schema = $entity->getSchema(); - $form['sparql_mapping'] = [ - '#type' => 'details', - '#title' => t('SPARQL field mapping'), - '#description' => t('This field uses a SPARQL backend. Please map the fields to their corresponding RDF properties.'), - '#weight' => 99, - ]; - $form_state->set('sparql_mapping_columns', array_keys($schema['columns'])); - foreach ($schema['columns'] as $column => $column_desc) { - $description = isset($column_desc['description']) ? $column_desc['description'] . "
" : ''; - foreach (['type', 'length', 'size', 'serialize'] as $key) { - if (!empty($column_desc[$key])) { - $description .= '' . $key . ": " . $column_desc[$key] . ' '; - } - } - - $settings = sparql_entity_storage_get_mapping_property($entity, 'mapping', $column); - - $form['sparql_mapping'][$column] = [ - '#type' => 'details', - '#title' => $column, - '#description' => $description, - ]; - - $form['sparql_mapping'][$column]['predicate_' . $column] = [ - '#type' => 'url', - '#title' => t('Mapping'), - '#weight' => 150, - '#default_value' => isset($settings['predicate']) ? $settings['predicate'] : '', - ]; - - $form['sparql_mapping'][$column]['format_' . $column] = [ - '#type' => 'select', - '#title' => t('Value format'), - '#options' => SparqlEntityStorageFieldHandler::getSupportedDataTypes(), - '#empty_value' => 'no_format', - '#weight' => 151, - '#default_value' => isset($settings['format']) ? $settings['format'] : NULL, - ]; - } - - $form['#entity_builders'][] = 'sparql_entity_storage_form_alter_builder'; - $form['#validate'][] = 'sparql_entity_storage_field_storage_form_validate'; -} - -/** - * Validation callback for the field storage form. - * - * @param array $form - * Form definition. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * Form state. - */ -function sparql_entity_storage_field_storage_form_validate(array &$form, FormStateInterface $form_state) { - $cardinality = (int) $form_state->getValue('cardinality_number'); - if ($cardinality < 2 && (int) $form_state->getValue('cardinality') !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) { - return; - } - - $columns = $form_state->get('sparql_mapping_columns'); - - // We can only have 1 predicate mapped if the cardinality is higher than 1. - $predicate_count = 0; - foreach ($columns as $column) { - $predicate = $form_state->getValue('predicate_' . $column); - if ($predicate) { - $predicate_count++; - } - - if ($predicate_count > 1) { - $form_state->setErrorByName('sparql_mapping', t('Multiple SPARQL mapping predicates are not supported with a field cardinality higher than 1.')); - break; - } - } -} - -/** - * Retrieve nested third party settings from object. - * - * @param \Drupal\Core\Config\Entity\ConfigEntityInterface $object - * The object may be either a bundle entity or a field storage config entity. - * @param string $property - * The property for which to retrieve the mapping. - * @param string $column - * The field column. - * @param mixed $default - * (optional) The default value. Defaults to NULL. - * - * @return mixed - * The mapping. - * - * @todo Move this to a service (or to SPARQL storage?) - */ -function sparql_entity_storage_get_mapping_property(ConfigEntityInterface $object, string $property, string $column, $default = NULL) { - // Mapping data requested for a configurable field. - if ($object instanceof FieldStorageConfigInterface) { - $property_value = $object->getThirdPartySetting('sparql_entity_storage', $property, FALSE); - } - // Mapping data requested for a bundle entity. - else { - $entity_type_id = $object->getEntityType()->getBundleOf(); - $bundle = $object->id(); - $mapping = SparqlMapping::loadByName($entity_type_id, $bundle); - $property_value = $mapping->get($property) ?: FALSE; - } - if (!is_array($property_value) || !isset($property_value[$column])) { - return $default; - } - - return $property_value[$column]; -} - -/** - * Entity builder callback: Save the mapping. - */ -function sparql_entity_storage_form_alter_builder($entity_type, FieldStorageConfig $entity, array &$form, FormStateInterface $form_state) { - $schema = $entity->getSchema(); - $data = []; - foreach ($schema['columns'] as $column => $column_desc) { - $data[$column]['predicate'] = $form_state->getValue('predicate_' . $column); - $data[$column]['format'] = $form_state->getValue('format_' . $column); - - } - $entity->setThirdPartySetting('sparql_entity_storage', 'mapping', $data); -} - -/** - * Implements hook_form_alter(). - * - * Configurations for the entity bundle. - */ -function sparql_entity_storage_form_alter(&$form, FormStateInterface $form_state) { - $form_object = $form_state->getFormObject(); - if (!$form_object instanceof BundleEntityFormBase) { - return; - } - /** @var \Drupal\Core\Config\Entity\ConfigEntityBundleBase $bundle_entity */ - $bundle_entity = $form_object->getEntity(); - if (!$bundle_entity instanceof ConfigEntityBundleBase) { - return; - } - $entity_type_id = $bundle_entity->getEntityType()->getBundleOf(); - $form_state->set('entity_type_id', $entity_type_id); - - /** @var \Drupal\sparql_entity_storage\SparqlEntityStorageInterface $storage */ - $storage = \Drupal::entityTypeManager()->getStorage($entity_type_id); - if (!$storage instanceof SparqlEntityStorageInterface) { - return; - } - $base_fields = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions($entity_type_id); - $id_key = $storage->getEntityType()->getKey('id'); - $form_state->set('bundle_id_key', $storage->getEntityType()->getKey('bundle')); - - $form['sparql_entity_storage'] = [ - '#type' => 'details', - '#title' => t('SPARQL Entity Storage'), - '#description' => t('SPARQL entity storage configurations.'), - '#open' => TRUE, - '#weight' => 99, - '#tree' => TRUE, - ]; - - // When creating a new bundle we can't yet use it for creating a mapping. In - // this case we defer to the custom submit handler. - $mapping = NULL; - if (!$bundle_entity->isNew()) { - $mapping = SparqlMapping::loadByName($entity_type_id, $bundle_entity->id()); - if (!$mapping) { - $mapping = SparqlMapping::create([ - 'entity_type_id' => $entity_type_id, - 'bundle' => !$bundle_entity->isNew() ? $bundle_entity->id() : NULL, - ]); - } - $form_state->set('sparql_mapping', $mapping); - } - - $form['sparql_entity_storage']['rdf_type'] = [ - '#type' => 'textfield', - '#title' => t('RDF type mapping'), - '#default_value' => $mapping ? $mapping->getRdfType() : NULL, - ]; - - /** @var \Drupal\sparql_entity_storage\SparqlEntityStorageEntityIdPluginManager $id_plugin_manager */ - $id_plugin_manager = \Drupal::service('plugin.manager.sparql_entity_id'); - $plugins = array_map(function (array $definition) use ($id_plugin_manager) { - return $definition['name']; - }, $id_plugin_manager->getDefinitions()); - - $form['sparql_entity_storage']['entity_id_plugin'] = [ - '#type' => 'select', - '#title' => t('Entity ID generator'), - '#description' => t("The generator used to create IDs for new entities."), - '#options' => $plugins, - '#default_value' => $mapping && $mapping->getEntityIdPlugin() ? $mapping->getEntityIdPlugin() : $id_plugin_manager->getFallbackPluginId(NULL), - ]; - - $form['sparql_entity_storage']['graph'] = [ - '#type' => 'details', - '#title' => t('Graphs'), - '#description' => t('Graph URI mapping'), - ]; - - foreach ($storage->getGraphDefinitions() as $graph_id => $graph) { - $form['sparql_entity_storage']['graph'][$graph_id] = [ - '#type' => 'url', - '#title' => t('@title (@id)', ['@title' => $graph['title'], '@id' => $graph_id]), - '#description' => $graph['description'], - '#default_value' => $mapping ? $mapping->getGraphUri($graph_id) : NULL, - '#required' => $graph_id === SparqlGraphInterface::DEFAULT, - ]; - } - - $form['sparql_entity_storage']['base_fields_mapping'] = [ - '#type' => 'details', - '#title' => t('Field mapping'), - '#description' => t('This entity type uses a SPARQL backend. Please map the bundle base fields to their corresponding RDF properties.'), - ]; - - /** @var \Drupal\Core\Field\BaseFieldDefinition $base_field */ - foreach ($base_fields as $field_name => $base_field) { - // The entity id doesn't need a mapping as it's the subject of the triple. - if ($field_name === $id_key) { - continue; - } - $columns = $base_field->getColumns(); - foreach ($columns as $column_name => $column) { - $title = $base_field->getLabel(); - if (count($columns) > 1) { - $title .= ' (' . $column_name . ')'; - } - - $form['sparql_entity_storage']['base_fields_mapping'][$field_name] = [ - '#type' => 'details', - '#title' => $title, - '#description' => $base_field->getDescription(), - ]; - - $form['sparql_entity_storage']['base_fields_mapping'][$field_name][$column_name]['predicate'] = [ - '#type' => 'url', - '#title' => t('Mapping'), - '#description' => t('The RDF predicate.'), - '#weight' => 150, - '#default_value' => $mapping ? $mapping->getMapping($field_name, $column_name)['predicate'] : NULL, - ]; - - $form['sparql_entity_storage']['base_fields_mapping'][$field_name][$column_name]['format'] = [ - '#type' => 'select', - '#title' => t('Value format'), - '#description' => t('The RDF format. Required if format is filled.'), - '#options' => SparqlEntityStorageFieldHandler::getSupportedDataTypes(), - '#empty_value' => '', - '#weight' => 151, - '#default_value' => $mapping ? $mapping->getMapping($field_name, $column_name)['format'] : NULL, - ]; - } - } - - $form['actions']['submit']['#submit'][] = 'sparql_entity_storage_type_mapping_submit'; -} - -/** - * Stores the mapping of base fields and RDF properties. - * - * @param array $form - * The form API form render array. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state object. - * - * @throws \Exception - * If the mapping fails to save. - * - * @see sparql_entity_storage_form_alter() - */ -function sparql_entity_storage_type_mapping_submit(array &$form, FormStateInterface $form_state): void { - $values = $form_state->getValue('sparql_entity_storage'); - /** @var \Drupal\sparql_entity_storage\SparqlMappingInterface $mapping */ - $mapping = $form_state->get('sparql_mapping'); - if (!$mapping) { - /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $bundle_entity */ - $bundle_entity = $form_state->getFormObject()->getEntity(); - $mapping = SparqlMapping::create([ - 'entity_type_id' => $bundle_entity->getEntityType()->getBundleOf(), - 'bundle' => $form_state->getFormObject()->getEntity()->id(), - ]); - } - - $mapping - ->setRdfType($values['rdf_type']) - ->setEntityIdPlugin($values['entity_id_plugin']) - // Add only non-empty values. - ->setGraphs(array_filter($values['graph'])) - ->setMappings($values['base_fields_mapping']) - ->save(); -} - -/** - * Returns the requirements related to virtuoso version. - * - * @return array - * The virtuoso version requirements. - */ -function sparql_entity_storage_virtuoso_version_requirements() { - $minimum_version = '07.00.0000'; - $requirements = [ - 'sparql_endpoint' => [ - 'title' => t('Virtuoso endpoint availability'), - 'description' => t('Virtuoso endpoint is available.'), - ], - 'sparql_virtuoso_version' => [ - 'title' => t('Virtuoso version'), - 'description' => t('Virtuoso version meets minimum requirements.'), - ], - ]; - - /** @var \Drupal\sparql_entity_storage\Database\Driver\sparql\ConnectionInterface $connection */ - $connection = Database::getConnection('default', 'sparql_default'); - $client = Http::getDefaultHttpClient(); - $client->resetParameters(TRUE); - $client->setUri($connection->getQueryUri()); - $client->setMethod('GET'); - - try { - $response = $client->request(); - } - catch (Exception $e) { - // If the endpoint could not be reached, return early. - $requirements['sparql_endpoint']['description'] = t('Virtuoso endpoint could not be reached.'); - $requirements['sparql_endpoint']['severity'] = REQUIREMENT_ERROR; - return $requirements; - } - - $server_header = $response->getHeader('Server'); - preg_match('/Virtuoso\/(.*?)\s/', $server_header, $matches); - $version = (is_array($matches) && count($matches) === 2) ? $matches[1] : []; - if (version_compare($version, $minimum_version, 'lt')) { - $description = t('The minimum virtuoso version supported is :version', [ - ':version' => $minimum_version, - ]); - $requirements['sparql_virtuoso_version']['description'] = $description; - $requirements['sparql_virtuoso_version']['severity'] = REQUIREMENT_ERROR; - $requirements['sparql_virtuoso_version']['value'] = $version; - } - - return $requirements; -} - -/** - * Returns the requirements related to virtuoso query permissions. - * - * Since there is no direct way to draw information from the virtuoso instance - * the function simply tries to create a triple in a random graph and then - * delete the whole graph. - * - * @return array - * The virtuoso query requirements. - */ -function sparql_entity_storage_virtuoso_permission_requirements() { - $rand = random_int(10000, 50000); - $uri = 'http://example.com/id/' . $rand; - $query = << - INSERT { <{$uri}> "test value" } - CLEAR GRAPH <{$uri}> -QUERY; - - /** @var \Drupal\sparql_entity_storage\Database\Driver\sparql\ConnectionInterface $connection */ - $connection = Database::getConnection('default', 'sparql_default'); - $requirements = [ - 'sparql_virtuoso_query' => [ - 'title' => t('Virtuoso permissions'), - 'description' => t('Virtuoso update/delete permissions are properly set.'), - 'value' => $query, - ], - ]; - - try { - $connection->query($query); - } - catch (Exception $e) { - $requirements['sparql_virtuoso_query']['description'] = $e->getMessage(); - $requirements['sparql_virtuoso_query']['severity'] = REQUIREMENT_ERROR; - } - - return $requirements; -} - -/** - * Implements hook_cache_flush(). - */ -function sparql_entity_storage_cache_flush() { - \Drupal::service('sparql.graph_handler')->clearCache(); -} diff --git a/sparql_entity_storage/sparql_entity_storage.routing.yml b/sparql_entity_storage/sparql_entity_storage.routing.yml deleted file mode 100755 index 4e3258f8..00000000 --- a/sparql_entity_storage/sparql_entity_storage.routing.yml +++ /dev/null @@ -1,57 +0,0 @@ -sparql_entity_storage.settings: - path: '/admin/config/sparql' - defaults: - _controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' - _title: 'SPARQL Entity Storage' - requirements: - _permission: 'administer site configuration' - -entity.sparql_graph.collection: - path: '/admin/config/sparql/graph' - defaults: - _entity_list: 'sparql_graph' - _title: 'SPARQL Graphs' - requirements: - _permission: 'administer site configuration' - -sparql_graph.add: - path: '/admin/config/sparql/graph/add' - defaults: - _entity_form: 'sparql_graph.add' - _title: 'Add graph' - requirements: - _entity_create_access: sparql_graph - -entity.sparql_graph.edit_form: - path: '/admin/config/sparql/graph/manage/{sparql_graph}' - defaults: - _entity_form: 'sparql_graph.edit' - _title_callback: '\Drupal\Core\Entity\Controller\EntityController::title' - requirements: - _entity_access: sparql_graph.update - -entity.sparql_graph.delete_form: - path: '/admin/config/sparql/graph/manage/{sparql_graph}/delete' - defaults: - _entity_form: 'sparql_graph.delete' - _title: 'Delete' - requirements: - _entity_access: sparql_graph.delete - -entity.sparql_graph.enable: - path: '/admin/config/sparql/graph/manage/{sparql_graph}/enable' - defaults: - _controller: \Drupal\sparql_entity_storage\Controller\SparqlGraphToggle::toggle - _title: Enable - toggle_operation: enable - requirements: - _custom_access: \Drupal\sparql_entity_storage\Controller\SparqlGraphToggle::access - -entity.sparql_graph.disable: - path: '/admin/config/sparql/graph/manage/{sparql_graph}/disable' - defaults: - _controller: \Drupal\sparql_entity_storage\Controller\SparqlGraphToggle::toggle - _title: Disable - toggle_operation: disable - requirements: - _custom_access: \Drupal\sparql_entity_storage\Controller\SparqlGraphToggle::access diff --git a/sparql_entity_storage/sparql_entity_storage.services.yml b/sparql_entity_storage/sparql_entity_storage.services.yml deleted file mode 100644 index ff6a824d..00000000 --- a/sparql_entity_storage/sparql_entity_storage.services.yml +++ /dev/null @@ -1,89 +0,0 @@ -services: - entity.query.sparql: - class: Drupal\sparql_entity_storage\Entity\Query\Sparql\QueryFactory - arguments: ['@sparql.endpoint', '@entity_type.manager', '@sparql.graph_handler', '@sparql.field_handler'] - tags: - - { name: backend_overridable } - sparql.endpoint: - class: Drupal\Driver\Database\sparql\Connection - factory: ['Drupal\Core\Database\Database', getConnection] - arguments: [default, sparql_default] -# @todo: Move the webprofiler integration into a submodule. -# webprofiler.sparql: -# class: \Drupal\sparql_entity_storage\DataCollector\SparqlDataCollector -# arguments: ['@sparql.endpoint', '@config.factory'] -# tags: -# - name: data_collector -# template: "@rdf_entity/Collector/sparql.html.twig" -# id: sparql -# title: Sparql -# priority: 60 - sparql.paramconverter: - class: Drupal\sparql_entity_storage\ParamConverter\SparqlEntityStorageConverter - arguments: ['@entity.manager'] - tags: - # Use a higher priority than EntityConverter. - - { name: paramconverter, priority: 6 } - sparql.route_processor: - class: Drupal\sparql_entity_storage\RouteProcessor\SparqlEntityStorageRouteProcessor - arguments: ['@current_route_match'] - tags: - - { name: route_processor_outbound, priority: 200 } - sparql.graph_handler: - class: Drupal\sparql_entity_storage\SparqlEntityStorageGraphHandler - arguments: ['@entity_type.manager', '@event_dispatcher'] - sparql.field_handler: - class: Drupal\sparql_entity_storage\SparqlEntityStorageFieldHandler - arguments: ['@entity_type.manager', '@entity_field.manager', '@event_dispatcher'] - plugin.manager.sparql_entity_id: - class: Drupal\sparql_entity_storage\SparqlEntityStorageEntityIdPluginManager - arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@entity_type.manager'] - sparql.inbound_value.datetime.subscriber: - class: Drupal\sparql_entity_storage\EventSubscriber\InboundValueDateTimeSubscriber - tags: - - { name: event_subscriber } - sparql.outbound_value.datetime.subscriber: - class: Drupal\sparql_entity_storage\EventSubscriber\OutboundValueDateTimeSubscriber - tags: - - { name: event_subscriber } - sparql.inbound_value.translatable_literal.subscriber: - class: Drupal\sparql_entity_storage\EventSubscriber\InboundValueTranslatableLiteralSubscriber - arguments: ['@typed_data_manager'] - tags: - - { name: event_subscriber } - - sparql_entity.serializer: - class: Drupal\sparql_entity_storage\SparqlSerializer - arguments: ['@sparql.endpoint', '@sparql.graph_handler'] - sparql_entity.encoder_base: - abstract: true - class: Drupal\sparql_entity_storage\Encoder\SparqlEncoder - sparql_entity.encoder.jsonld: - parent: sparql_entity.encoder_base - tags: - - { name: encoder, format: jsonld } - sparql_entity.encoder.rdfxml: - parent: sparql_entity.encoder_base - tags: - - { name: encoder, format: rdfxml } - sparql_entity.encoder.ntriples: - parent: sparql_entity.encoder_base - tags: - - { name: encoder, format: ntriples } - sparql_entity.encoder.turtle: - parent: sparql_entity.encoder_base - tags: - - { name: encoder, format: turtle } - sparql_entity.encoder.n3: - parent: sparql_entity.encoder_base - tags: - - { name: encoder, format: n3 } - sparql.entity_normalizer: - class: Drupal\rdf_entity\Normalizer\SparqlEntityNormalizer - arguments: ['@sparql_entity.serializer', '@entity_type.manager'] - tags: - - { name: normalizer, priority: 10 } - sparql.content_type.subscriber: - class: Drupal\sparql_entity_storage\EventSubscriber\SparqlContentTypesSubscriber - tags: - - { name: event_subscriber } diff --git a/sparql_entity_storage/src/Annotation/SparqlEntityIdGenerator.php b/sparql_entity_storage/src/Annotation/SparqlEntityIdGenerator.php deleted file mode 100644 index db8b17f5..00000000 --- a/sparql_entity_storage/src/Annotation/SparqlEntityIdGenerator.php +++ /dev/null @@ -1,34 +0,0 @@ -status()) || - // The operation is 'disable' and the entity is already disabled. - ($toggle_operation === 'disable' && !$sparql_graph->status()) || - // This is the 'default' SPARQL graph. - ($sparql_graph->id() === SparqlGraphInterface::DEFAULT); - - return $forbidden ? AccessResult::forbidden() : AccessResult::allowed(); - } - - /** - * Toggles the SPARQL graph status. - * - * @param \Drupal\sparql_entity_storage\SparqlGraphInterface $sparql_graph - * The $sparql_graph entity. - * @param string $toggle_operation - * The operation: 'enable', 'disable'. - * - * @return \Symfony\Component\HttpFoundation\RedirectResponse - * A redirect response. - * - * @throws \Drupal\Core\Entity\EntityStorageException - * In case of failures on entity save. - */ - public function toggle(SparqlGraphInterface $sparql_graph, string $toggle_operation) { - $arguments = [ - '%name' => $sparql_graph->label(), - '%id' => $sparql_graph->id(), - ]; - - if ($toggle_operation === 'enable') { - $sparql_graph->enable()->save(); - $message = $this->t("The %name (%id) graph has been enabled.", $arguments); - } - else { - $sparql_graph->disable()->save(); - $message = $this->t("The %name (%id) graph has been disabled.", $arguments); - } - drupal_set_message($message); - - return $this->redirect('entity.sparql_graph.collection'); - } - -} diff --git a/sparql_entity_storage/src/DataCollector/SparqlDataCollector.php b/sparql_entity_storage/src/DataCollector/SparqlDataCollector.php deleted file mode 100644 index ff3ef26b..00000000 --- a/sparql_entity_storage/src/DataCollector/SparqlDataCollector.php +++ /dev/null @@ -1,257 +0,0 @@ -database = $database; - $this->configFactory = $config_factory; - } - - /** - * {@inheritdoc} - */ - public function collect(Request $request, Response $response, \Exception $exception = NULL) { - $queries = $this->database->getLogger()->get('webprofiler'); - - foreach ($queries as &$query) { - // Remove caller args. - unset($query['caller']['args']); - - // Remove query args element if empty. - if (empty($query['args'])) { - unset($query['args']); - } - - // Save time in milliseconds. - $query['time'] = $query['time'] * 1000; - } - - $query_sort = $this->configFactory->get('webprofiler.config')->get('query_sort'); - if ('duration' === $query_sort) { - usort($queries, [ - "\\Drupal\\sparql_entity_storage\\DataCollector\\SparqlDataCollector", - "orderQueryByTime", - ]); - } - - $this->data['queries'] = $queries; - - $options = $this->database->getConnectionOptions(); - - // Remove password for security. - unset($options['password']); - - $this->data['database'] = $options; - } - - /** - * Get database connection options. - * - * @return array - * Database connection options. - */ - public function getDatabase() { - return $this->data['database']; - } - - /** - * Return amount of queries ran. - * - * @return int - * Number of queries. - */ - public function getQueryCount() { - return count($this->data['queries']); - } - - /** - * Get all executed SPARQL queries. - * - * @return array - * List of SPARQL queries. - */ - public function getQueries() { - return $this->data['queries']; - } - - /** - * Returns the total execution time. - * - * @return float - * Time - */ - public function getTime() { - $time = 0; - - foreach ($this->data['queries'] as $query) { - $time += $query['time']; - } - - return $time; - } - - /** - * Returns a color based on the number of executed queries. - * - * @return string - * Color - */ - public function getColorCode() { - $count = $this->getQueryCount(); - $time = $this->getTime(); - if ($count < 10 && $time < 40) { - return 'green'; - } - if ($count < 20 && $time < 60) { - return 'yellow'; - } - - return 'red'; - } - - /** - * Returns the configured query highlight threshold. - * - * @return int - * Threshold - */ - public function getQueryHighlightThreshold() { - // When a profile is loaded from storage this object is deserialized and - // no constructor is called so we cannot use dependency injection. - return \Drupal::config('webprofiler.config')->get('query_highlight'); - } - - /** - * {@inheritdoc} - */ - public function getName() { - return 'sparql'; - } - - /** - * {@inheritdoc} - */ - public function getTitle() { - return $this->t('Sparql'); - } - - /** - * {@inheritdoc} - */ - public function getPanelSummary() { - return $this->t('Executed queries: @count', ['@count' => $this->getQueryCount()]); - } - - /** - * {@inheritdoc} - */ - public function getIcon() { - - return 'iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wseCQolVpASpQAAAc5JREFUSMe91jtoFFEYBeAvG3VFEwOi4KvSwifGQu3tglgoBC3UWmIKX62VTWzs1N7CgBC1tbCIoMX6CGiCiDZpLFRiQrCIht21+QPDshnuuhcvXAbmPzNn/sc5c8m7qriGGSzjJ8YxiEpmLrvwGs1V9oWcpFU8KSFb2YO5CE/hewLheK4U92NrAm4oF+H6RFx/LsI5NBJwn7ohWYOduI/fCf1r4krxBb3Yjr04gN0YWKV8e3A7smriDZ5ioYSsFtMM+nAZUwXAAh7geGDW4mgQrWT0ElexMTA38B5LEa/jGyaiGoQY75Z82SxGcAfzce85LmFbmwocxGjgpnAC64qAMwm1X47rJM5iR0J/m3jULjiZQFjHLWxKHKi+eG6iNVAp9KhsVaJvi93qJ7uDpxDWEnCNkMNADtLTHQzNC5wrjninQ9OLz9hS0stZ3AxbGsJFHMEGfMWvFvwhDOMk/uBL4OqtUzWCd4Ws5kP4x1qEP1YQ9itcR39B+B8K8Ub8th63q0qn1jYWX93E206trRvzvvev5t3NGi1kW7anc+lwc6Km9+UiXErELeYi/IgfCbhn//uYeDj3QbhWQnYePbm9uRqjPx12OIeHkVkP/AVSbdRhDiH9kwAAAABJRU5ErkJggg=='; - } - - /** - * {@inheritdoc} - */ - public function getLibraries() { - return [ - 'webprofiler/database', - ]; - } - - /** - * {@inheritdoc} - */ - public function getData() { - $data = $this->data; - $conn = Database::getConnection(); - foreach ($data['queries'] as &$query) { - $explain = TRUE; - $type = 'select'; - - if (strpos($query['query'], 'INSERT') !== FALSE) { - $explain = FALSE; - $type = 'insert'; - } - - if (strpos($query['query'], 'UPDATE') !== FALSE) { - $explain = FALSE; - $type = 'update'; - } - - if (strpos($query['query'], 'CREATE') !== FALSE) { - $explain = FALSE; - $type = 'create'; - } - - if (strpos($query['query'], 'DELETE') !== FALSE) { - $explain = FALSE; - $type = 'delete'; - } - - $query['explain'] = $explain; - $query['type'] = $type; - - $quoted = []; - foreach ((array) $query['args'] as $key => $val) { - $quoted[$key] = is_null($val) ? 'NULL' : $conn->quote($val); - } - - $query['query_args'] = strtr($query['query'], $quoted); - } - - $data['query_highlight_threshold'] = $this->getQueryHighlightThreshold(); - return $data; - } - - /** - * Sort callback. Sort queries by timing. - * - * @param array $a - * Query. - * @param array $b - * Query. - * - * @return int - * Sort for usort. - */ - private function orderQueryByTime(array $a, array $b) { - $at = $a['time']; - $bt = $b['time']; - - if ($at == $bt) { - return 0; - } - return ($at < $bt) ? 1 : -1; - } - -} diff --git a/sparql_entity_storage/src/Database/Driver/sparql/ConnectionInterface.php b/sparql_entity_storage/src/Database/Driver/sparql/ConnectionInterface.php deleted file mode 100644 index 963319f2..00000000 --- a/sparql_entity_storage/src/Database/Driver/sparql/ConnectionInterface.php +++ /dev/null @@ -1,180 +0,0 @@ -query = $query; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getQueryString(): string { - return $this->query; - } - - /** - * Sets the database connection. - * - * @param \Drupal\sparql_entity_storage\Database\Driver\sparql\ConnectionInterface $connection - * The SPARQL connection. - * - * @return $this - */ - public function setDatabaseConnection(ConnectionInterface $connection): self { - $this->dbh = $connection; - return $this; - } - - /** - * {@inheritdoc} - */ - public function execute($args = [], $options = []) {} - - /** - * {@inheritdoc} - */ - public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL) {} - - /** - * {@inheritdoc} - */ - public function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL) {} - - /** - * {@inheritdoc} - */ - public function fetchAllAssoc($key, $fetch = NULL) {} - - /** - * {@inheritdoc} - */ - public function fetchAllKeyed($key_index = 0, $value_index = 1) {} - - /** - * {@inheritdoc} - */ - public function fetchAssoc() {} - - /** - * {@inheritdoc} - */ - public function fetchCol($index = 0) {} - - /** - * {@inheritdoc} - */ - public function fetchField($index = 0) {} - - /** - * {@inheritdoc} - */ - public function fetchObject() {} - - /** - * {@inheritdoc} - */ - public function setFetchMode($mode, $a1 = NULL, $a2 = []) {} - - /** - * {@inheritdoc} - */ - public function rowCount() {} - - /** - * {@inheritdoc} - */ - public function next() {} - - /** - * {@inheritdoc} - */ - public function valid() {} - - /** - * {@inheritdoc} - */ - public function current() {} - - /** - * {@inheritdoc} - */ - public function rewind() {} - - /** - * {@inheritdoc} - */ - public function key() {} - -} diff --git a/sparql_entity_storage/src/Encoder/SparqlEncoder.php b/sparql_entity_storage/src/Encoder/SparqlEncoder.php deleted file mode 100644 index 1df385d1..00000000 --- a/sparql_entity_storage/src/Encoder/SparqlEncoder.php +++ /dev/null @@ -1,54 +0,0 @@ -getParameter('sparql_entity.encoders'); - $rdf_serializers = Format::getFormats(); - static::$supportedFormats = array_intersect_key($rdf_serializers, $container_registered_formats); - } - return static::$supportedFormats; - } - -} diff --git a/sparql_entity_storage/src/Entity/Query/Sparql/Query.php b/sparql_entity_storage/src/Entity/Query/Sparql/Query.php deleted file mode 100644 index 09e13c2d..00000000 --- a/sparql_entity_storage/src/Entity/Query/Sparql/Query.php +++ /dev/null @@ -1,351 +0,0 @@ -graphHandler = $sparql_graph_handler; - $this->fieldHandler = $sparql_field_handler; - $this->entityTypeManager = $entity_type_manager; - $this->connection = $connection; - parent::__construct($entity_type, $conjunction, $namespaces); - - // Set a unique tag for the SPARQL queries. - $this->addTag('sparql'); - $this->addMetaData('entity_type', $this->entityType); - } - - /** - * {@inheritdoc} - */ - public function getEntityType(): EntityTypeInterface { - return $this->entityType; - } - - /** - * {@inheritdoc} - */ - public function getEntityStorage(): SparqlEntityStorageInterface { - if (!isset($this->entityStorage)) { - $this->entityStorage = $this->entityTypeManager->getStorage($this->getEntityTypeId()); - } - return $this->entityStorage; - } - - /** - * {@inheritdoc} - */ - public function count($field = TRUE) { - $this->count = $field; - return $this; - } - - /** - * Implements \Drupal\Core\Entity\Query\QueryInterface::execute(). - */ - public function execute() { - return $this - ->prepare() - ->compile() - ->addSort() - ->addPager() - ->run() - ->result(); - } - - /** - * {@inheritdoc} - */ - public function graphs(array $graph_ids = NULL): SparqlQueryInterface { - $this->graphIds = $graph_ids; - return $this; - } - - /** - * Initialize the query. - * - * @return $this - */ - protected function prepare() { - // Running as count query? - if ($this->count) { - if (is_string($this->count)) { - $this->query = 'SELECT count(' . $this->count . ') AS ?count '; - } - else { - $this->query = 'SELECT count(?entity) AS ?count '; - } - } - else { - $this->query = 'SELECT DISTINCT(?entity) '; - } - $this->query .= "\n"; - - if (!$this->graphIds) { - // Allow all default graphs for this entity type. - $this->graphIds = $this->graphHandler->getEntityTypeDefaultGraphIds($this->getEntityTypeId()); - } - $graph_uris = $this->graphHandler->getEntityTypeGraphUrisFlatList($this->getEntityTypeId(), $this->graphIds); - foreach ($graph_uris as $graph_uri) { - $this->query .= "FROM <$graph_uri>\n"; - } - - return $this; - } - - /** - * Add the registered conditions to the WHERE clause. - * - * @return $this - */ - protected function compile() { - // Modules may alter all queries or only those having a particular tag. - if (isset($this->alterTags)) { - // Remap the entity reference default tag to the SPARQL entity reference - // because the first one requires that the query is an instance of the - // SelectInterface. - // @todo: Maybe overwrite the default selection class? - if (isset($this->alterTags['entity_reference'])) { - $this->alterTags['sparql_reference'] = $this->alterTags['entity_reference']; - unset($this->alterTags['entity_reference']); - } - $hooks = ['query']; - foreach ($this->alterTags as $tag => $value) { - $hooks[] = 'query_' . $tag; - } - \Drupal::moduleHandler()->alter($hooks, $this); - } - - $this->condition->compile($this); - $this->query .= "WHERE {\n" . $this->condition->toString() . "\n}"; - return $this; - } - - /** - * Adds the sort to the build query. - * - * @return \Drupal\sparql_entity_storage\Entity\Query\Sparql\Query - * Returns the called object. - */ - protected function addSort() { - if ($this->count) { - $this->sort = []; - } - // Simple sorting. For the POC, only uri's and bundles are supported. - // @todo Implement sorting on bundle fields? - if ($this->sort) { - // @todo Support multiple sort conditions. - $sort = array_pop($this->sort); - // @todo Can we use the field mapper here as well? - // Consider looping over the sort criteria in both the compile step and - // here: We can add ?entity ?sort_1 in the condition, and - // ORDER BY ASC ?sort_1 here (I think). - switch ($sort['field']) { - case 'id': - $this->query .= 'ORDER BY ' . $sort['direction'] . ' (?entity)'; - break; - - case 'rid': - $this->query .= 'ORDER BY ' . $sort['direction'] . ' (?bundle)'; - break; - } - } - return $this; - } - - /** - * Add pager to query. - */ - protected function addPager() { - $this->initializePager(); - if (!$this->count && $this->range) { - $this->query .= 'LIMIT ' . $this->range['length'] . "\n"; - $this->query .= 'OFFSET ' . $this->range['start'] . "\n"; - } - return $this; - } - - /** - * Commit the query to the backend. - */ - protected function run() { - /** @var \EasyRdf\Sparql\Result $results */ - $this->results = $this->connection->query($this->query); - return $this; - } - - /** - * Do the actual query building. - */ - protected function result() { - // Count query. - if ($this->count) { - foreach ($this->results as $result) { - return (string) $result->count; - } - } - $uris = []; - - // SELECT query. - foreach ($this->results as $result) { - // If the query does not return any results, EasyRdf\Sparql\Result still - // contains an empty result object. If this is the case, skip it. - if (!empty((array) $result)) { - $uri = (string) $result->entity; - $uris[$uri] = $uri; - } - } - return $uris; - } - - /** - * Returns the array of conditions. - * - * @return array - * The array of conditions. - */ - public function &conditions() { - return $this->condition->conditions(); - } - - /** - * {@inheritdoc} - */ - public function existsAggregate($field, $function, $langcode = NULL) { - return $this->conditionAggregate->exists($field, $function, $langcode); - } - - /** - * {@inheritdoc} - */ - public function notExistsAggregate($field, $function, $langcode = NULL) { - return $this->conditionAggregate->notExists($field, $function, $langcode); - } - - /** - * {@inheritdoc} - */ - public function conditionAggregateGroupFactory($conjunction = 'AND') { - return new ConditionAggregate($conjunction, $this); - } - - /** - * {@inheritdoc} - */ - protected function conditionGroupFactory($conjunction = 'AND') { - $class = static::getClass($this->namespaces, 'SparqlCondition'); - return new $class($conjunction, $this, $this->namespaces, $this->graphHandler, $this->fieldHandler); - } - - /** - * Return the query string for debugging help. - * - * @return string - * Query. - */ - public function __toString() { - return $this->query; - } - -} diff --git a/sparql_entity_storage/src/Entity/Query/Sparql/QueryFactory.php b/sparql_entity_storage/src/Entity/Query/Sparql/QueryFactory.php deleted file mode 100644 index ce8052b3..00000000 --- a/sparql_entity_storage/src/Entity/Query/Sparql/QueryFactory.php +++ /dev/null @@ -1,89 +0,0 @@ -connection = $connection; - $this->namespaces = QueryBase::getNamespaces($this); - $this->entityTypeManager = $entity_type_manager; - $this->graphHandler = $sparql_graph_handler; - $this->fieldHandler = $sparql_field_handler; - } - - /** - * {@inheritdoc} - */ - public function get(EntityTypeInterface $entity_type, $conjunction) { - $class = QueryBase::getClass($this->namespaces, 'Query'); - return new $class($entity_type, $conjunction, $this->connection, $this->namespaces, $this->entityTypeManager, $this->graphHandler, $this->fieldHandler); - } - - /** - * {@inheritdoc} - */ - public function getAggregate(EntityTypeInterface $entity_type, $conjunction) { - $class = QueryBase::getClass($this->namespaces, 'Query'); - return new $class($entity_type, $conjunction, $this->connection, $this->namespaces, $this->entityTypeManager, $this->graphHandler, $this->fieldHandler); - } - -} diff --git a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlArg.php b/sparql_entity_storage/src/Entity/Query/Sparql/SparqlArg.php deleted file mode 100644 index 02a9e8f2..00000000 --- a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlArg.php +++ /dev/null @@ -1,141 +0,0 @@ - $uri) { - $uris[$index] = self::uri($uri); - } - return $uris; - } - - /** - * URI Query argument. - * - * @param string $uri - * A valid URI to use as a query parameter. - * - * @return string - * Sparql validated URI. - */ - public static function uri($uri) { - // If the uri is already encapsulated with the '<>' symbols, remove these - // and re-serialize the uri. - if (preg_match('/^<(.+)>$/', $uri) !== NULL) { - $uri = trim($uri, '<>'); - } - return self::serialize($uri, SparqlEntityStorageFieldHandlerInterface::RESOURCE); - } - - /** - * URI Query argument. - * - * @param string $uri - * A string to be checked. - * - * @return bool - * Whether it is a valid RDF resource or not. The URI is a valid URI whether - * or not it is encapsulated with '<>'. - */ - public static function isValidResource($uri) { - return UrlHelper::isValid(trim($uri, '<>'), TRUE); - } - - /** - * URI Query argument. - * - * @param array $uris - * An array string to be checked. - * - * @return bool - * Whether the items in the array are valid RDF resource or not. The URI is - * a valid URI whether or not it is encapsulated with '<>'. If at least one - * URI is not a valid resource, FALSE will be returned. - */ - public static function isValidResources(array $uris) { - foreach ($uris as $uri) { - if (!SparqlArg::isValidResource($uri)) { - return FALSE; - } - } - return TRUE; - } - - /** - * Returns a serialized version of the given value of the given format. - * - * @param string $value - * The value to be serialized. - * @param string $format - * One of the formats defined in - * \Drupal\sparql_entity_storage\SparqlEntityStorageFieldHandler::getSupportedDatatypes(). - * @param string $lang - * The lang code. - * - * @return string - * The outcome of the serialization. - */ - public static function serialize($value, $format, $lang = NULL) { - $data['value'] = $value; - switch ($format) { - case SparqlEntityStorageFieldHandlerInterface::RESOURCE: - $data['type'] = 'uri'; - break; - - case SparqlEntityStorageFieldHandlerInterface::NON_TYPE: - $data['type'] = 'literal'; - break; - - case SparqlEntityStorageFieldHandlerInterface::TRANSLATABLE_LITERAL: - $data['lang'] = $lang; - $data['type'] = 'literal'; - break; - - default: - $data['type'] = 'literal'; - $data['datatype'] = $format; - - } - $serializer = new Ntriples(); - return $serializer->serialiseValue($data); - } - -} diff --git a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlCondition.php b/sparql_entity_storage/src/Entity/Query/Sparql/SparqlCondition.php deleted file mode 100644 index 56699ced..00000000 --- a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlCondition.php +++ /dev/null @@ -1,835 +0,0 @@ -', - '<=', - '>=', - '<>', - 'IN', - 'NOT IN', - ]; - - /** - * The SPARQL graph handler service object. - * - * @var \Drupal\sparql_entity_storage\SparqlEntityStorageGraphHandlerInterface - */ - protected $graphHandler; - - /** - * The SPARQL field mapping handler service. - * - * @var \Drupal\sparql_entity_storage\SparqlEntityStorageFieldHandlerInterface - */ - protected $fieldHandler; - - /** - * Provides a map of filter operators to operator options. - * - * @var array - */ - protected static $filterOperatorMap = [ - 'IN' => ['delimiter' => ' ', 'prefix' => '', 'suffix' => ''], - 'NOT IN' => ['delimiter' => ', ', 'prefix' => '', 'suffix' => ''], - 'IS NULL' => ['use_value' => FALSE], - 'IS NOT NULL' => ['use_value' => FALSE], - 'CONTAINS' => ['prefix' => 'FILTER(CONTAINS(', 'suffix' => '))'], - 'STARTS WITH' => ['prefix' => 'FILTER(STRSTARTS(', 'suffix' => '))'], - 'ENDS WITH' => ['prefix' => 'FILTER(STRENDS(', 'suffix' => '))'], - 'LIKE' => ['prefix' => 'FILTER(CONTAINS(', 'suffix' => '))'], - 'NOT LIKE' => ['prefix' => 'FILTER(!CONTAINS(', 'suffix' => '))'], - 'EXISTS' => ['prefix' => 'FILTER EXISTS {', 'suffix' => '}'], - 'NOT EXISTS' => ['prefix' => 'FILTER NOT EXISTS {', 'suffix' => '}'], - '<' => ['prefix' => '', 'suffix' => ''], - '>' => ['prefix' => '', 'suffix' => ''], - '>=' => ['prefix' => '', 'suffix' => ''], - '<=' => ['prefix' => '', 'suffix' => ''], - ]; - - /** - * The operators that require a default triple pattern to be added. - * - * In SPARQL, some of the conditions might need a combination of a pattern and - * a condition. Below are the operators that need a secondary condition. - * - * @var array - * An array of operators. - */ - protected $requiresDefaultPatternOperators = [ - 'IN', - 'NOT IN', - 'IS NULL', - 'IS NOT NULL', - 'CONTAINS', - 'LIKE', - 'NOT LIKE', - 'STARTS WITH', - 'ENDS WITH', - '<', - '>', - '<=', - '>=', - '!=', - '<>', - ]; - - /** - * Whether the conditions have been changed. - * - * TRUE if the condition has been changed since the last compile. - * FALSE if the condition has been compiled and not changed. - * - * @var bool - */ - protected $needsRecompile = TRUE; - - /** - * Whether the default triple pattern is required in the query. - * - * This will be turned to false if there is at least one condition that does - * not involve the id. - * - * @var bool - */ - protected $requiresDefaultPattern = TRUE; - - /** - * The default bundle predicate. - * - * @var array - */ - protected $typePredicate = ''; - - /** - * An array of triples in their string version. - * - * These are mainly fragments of the '=' operator because they can create - * triples that will greatly reduce the results. - * - * @var string[] - */ - protected $tripleFragments = []; - - /** - * An array of conditions in their string version. - * - * These are formed during the compilation phase. - * - * @var string[] - */ - protected $conditionFragments = []; - - /** - * An array of field names and their corresponding mapping. - * - * @var string[] - */ - protected $fieldMappings; - - /** - * An array of conditions regarding fields with multiple possible mappings. - * - * @var array - */ - protected $fieldMappingConditions; - - /** - * The entity type id key. - * - * @var string - */ - protected $idKey; - - /** - * The entity type bundle key. - * - * @var string - */ - protected $bundleKey; - - /** - * The entity type label key. - * - * @var string - */ - protected $labelKey; - - /** - * Whether the condition has been compiled. - * - * @var bool - */ - private $isCompiled; - - // @todo: Do we need this? - // @todo: This has to go to the interface. - const ID_KEY = '?entity'; - - /** - * {@inheritdoc} - */ - public function __construct($conjunction, SparqlQueryInterface $query, array $namespaces, SparqlEntityStorageGraphHandlerInterface $sparql_graph_handler, SparqlEntityStorageFieldHandlerInterface $sparql_field_handler) { - $conjunction = strtoupper($conjunction); - parent::__construct($conjunction, $query, $namespaces); - $this->graphHandler = $sparql_graph_handler; - $this->fieldHandler = $sparql_field_handler; - $this->typePredicate = $query->getEntityStorage()->getBundlePredicates(); - $this->bundleKey = $query->getEntityType()->getKey('bundle'); - $this->idKey = $query->getEntityType()->getKey('id'); - $this->labelKey = $query->getEntityType()->getKey('label'); - // Initialize variable to avoid warnings;. - $this->fieldMappingConditions = []; - $this->fieldMappings = [ - $this->idKey => self::ID_KEY, - $this->bundleKey => count($this->typePredicate) === 1 ? reset($this->typePredicate) : $this->toVar($this->bundleKey . '_predicate'), - ]; - } - - /** - * A list of properties regarding the query conjunction. - * - * @var array - */ - protected static $conjunctionMap = [ - 'AND' => ['delimeter' => " .\n", 'prefix' => '', 'suffix' => ''], - 'OR' => ['delimeter' => " UNION\n", 'prefix' => '{ ', 'suffix' => ' }'], - ]; - - /** - * {@inheritdoc} - * - * @todo: handle the lang. - */ - public function condition($field = NULL, $value = NULL, $operator = NULL, $lang = NULL) { - if ($this->conjunction == 'OR') { - $sub_condition = $this->query->andConditionGroup(); - $sub_condition->condition($field, $value, $operator, $lang); - $this->conditions[] = ['field' => $sub_condition]; - return $this; - } - - // If the field is a nested condition, simply add it to the list of - // conditions. - if ($field instanceof ConditionInterface) { - $this->conditions[] = ['field' => $field]; - return $this; - } - - if ($operator === NULL) { - $operator = '='; - } - - switch ($field) { - case $this->bundleKey: - // If a bundle filter is passed, then there is no need for a default - // condition. - $this->requiresDefaultPattern = FALSE; - - case $this->idKey: - $this->keyCondition($field, $value, $operator); - break; - - default: - // In case the field name includes the column, explode it. - // @see \Drupal\og\MembershipManager::getGroupContentIds - $field_name_parts = explode('.', $field); - $field = $field_name_parts[0]; - // Unmapped fields, such as fields without storage cannot be added as - // entity query conditions. - if (!$this->fieldHandler->fieldIsMapped($this->query->getEntityTypeId(), $field)) { - return $this; - } - $column = isset($field_name_parts[1]) ? $field_name_parts[1] : $this->fieldHandler->getFieldMainProperty($this->query->getEntityTypeId(), $field); - $this->conditions[] = [ - 'field' => $field, - 'value' => $value, - 'operator' => $operator, - 'lang' => $lang, - 'column' => $column, - ]; - - if (!in_array($operator, ['EXISTS', 'NOT EXISTS'])) { - $this->requiresDefaultPattern = FALSE; - } - } - - return $this; - } - - /** - * Handle the id and bundle keys. - * - * @param string $field - * The field name. Should be either the id or the bundle key. - * @param string|array $value - * A string or an array of strings. - * @param string $operator - * The operator. - * - * @return \Drupal\Core\Entity\Query\ConditionInterface - * The current object. - * - * @throws \Exception - * Thrown if the value is NULL or the operator is not allowed. - */ - public function keyCondition($field, $value, $operator) { - // @todo: Add support for loadMultiple with empty Id (load all). - if ($value == NULL) { - throw new \Exception('The value cannot be NULL for conditions related to the Id and bundle keys.'); - } - if (!in_array($operator, self::ID_BUNDLE_ALLOWED_OPERATORS)) { - throw new \Exception("Only '=', '!=', '<>', 'IN', 'NOT IN' operators are allowed for the Id and bundle keys."); - } - - switch ($operator) { - case '=': - $value = [$value]; - $operator = 'IN'; - - case 'IN': - $this->conditions[] = [ - 'field' => $field, - 'value' => $value, - 'operator' => $operator, - 'column' => NULL, - 'lang' => NULL, - ]; - - break; - - // Re-write '!=' and '<>' as 'NOT IN' operators as it can be handled - // in a generic way. - case '!=': - case '<>': - $value = [$value]; - $operator = 'NOT IN'; - - case '>': - case '<': - case '>=': - case '<=': - case 'NOT IN': - $this->conditions[] = [ - 'field' => $field, - 'value' => $value, - 'operator' => $operator, - 'column' => NULL, - 'lang' => NULL, - ]; - } - return $this; - } - - /** - * {@inheritdoc} - * - * Map the field names with the corresponding resource IDs. - * The predicate mapping can not added as a direct filter. It is being - * loaded from the database. There is no way that in a single request, the - * same predicate is found with a single and multiple mappings. - * There is no filter per bundle in the query. That makes it safe to not check - * on the predicate mappings that are already in the query. - */ - public function compile($query) { - $entity_type = $query->getEntityType(); - $condition_stack = array_merge($this->conditions, $this->fieldMappingConditions); - // The id and bundle keys do not need to be compiled as they were already - // handled in the keyCondition. - $condition_stack = array_filter($condition_stack, function ($condition) { - return !in_array($condition['field'], [$this->idKey, $this->bundleKey]); - }); - - foreach ($condition_stack as $index => $condition) { - if ($condition['field'] instanceof ConditionInterface) { - $condition['field']->compile($query); - } - else { - $mappings = $this->fieldHandler->getFieldPredicates($entity_type->id(), $condition['field'], $condition['column']); - $field_name = $condition['field'] . '__' . $condition['column']; - if (count($mappings) === 1) { - $this->fieldMappings[$field_name] = reset($mappings); - } - else { - if (!isset($this->fieldMappings[$field_name])) { - $this->fieldMappings[$field_name] = $field_name . '_predicate'; - } - // The predicate mapping is not added as a direct filter. It is being - // loaded by the database. There is no way that in a single request, - // the same predicate is found with a single and multiple mappings. - // There is no filter per bundle in the query. - $this->fieldMappingConditions[] = [ - 'field' => $condition['field'], - 'column' => $condition['column'], - 'value' => array_values($mappings), - 'operator' => 'IN', - ]; - } - } - } - } - - /** - * Returns the string version of the conditions. - * - * @return string - * The string version of the conditions. - */ - public function toString() { - // In case of re-compiling, remove previous fragments. This will ensure that - // not previous duplicates or leftovers remain. - $this->conditionFragments = []; - - // There are cases where not a single triple is formed. In these cases, a - // default condition has to be added in order to retrieve distinct Ids. - // Also, in case the query is an OR, it should not get the default condition - // because it will be added in every subquery which has an 'AND' conjuncion. - if (($this->requiresDefaultPattern && $this->conjunction === 'AND') || empty($this->conditions())) { - $this->addDefaultTriplePattern(); - } - - // The fieldMappingConditions are added first because they are converted - // into a 'VALUES' clause which increases performance. - $this->fieldMappingConditionsToString(); - - // Convert the conditions. - $this->conditionsToString(); - - // Put together everything. - $condition_fragments = array_merge($this->tripleFragments, $this->conditionFragments); - return implode(self::$conjunctionMap[$this->conjunction]['delimeter'], array_unique($condition_fragments)); - } - - /** - * Converts the field mapping conditions into string versions. - */ - private function fieldMappingConditionsToString() { - foreach ($this->fieldMappingConditions as $condition) { - $field_name = $condition['field'] . '__' . $condition['column']; - $field_predicate = $this->fieldMappings[$field_name]; - $this->addConditionFragment(self::ID_KEY . ' ' . $this->escapePredicate($field_predicate) . ' ' . $this->toVar($field_name)); - $condition['value'] = SparqlArg::toResourceUris($condition['value']); - $condition['field'] = $field_predicate; - $this->addConditionFragment($this->compileValuesFilter($condition)); - } - } - - /** - * Converts the conditions into string versions. - */ - private function conditionsToString() { - $filter_fragments = []; - - foreach ($this->conditions as $condition) { - if ($condition['field'] instanceof ConditionInterface) { - // Get the string version of a nested condition. - $this->addConditionFragment($condition['field']->toString()); - continue; - } - - // The id key only needs a conversion on the field to its corresponding - // variable version. - if ($condition['field'] === $this->idKey) { - $field_name = $this->fieldMappings[$condition['field']]; - $predicate = $this->fieldMappings[$condition['field']]; - } - // The bundle needs special handle as it might get a filter both in the - // predicate and the value. - elseif ($condition['field'] === $this->bundleKey) { - $this->compileBundleCondition($condition); - // This will be '{$bundle_key}' as it is always an 'IN' or a 'NOT IN' - // clause. - $field_name = $condition['field']; - $predicate = $this->fieldMappings[$condition['field']]; - } - // Implement the appropriate conversions. If the field has a single - // mapping, convert it into a triple. If field predicate is having more - // than one values, get the predicate variable and set it in the triple. - else { - $field_name = $condition['field'] . '__' . $condition['column']; - $predicate = $this->fieldMappings[$field_name]; - // In case the operator is not '=', add a support triple pattern. - if (in_array($condition['operator'], $this->requiresDefaultPatternOperators) && isset($this->fieldMappings[$field_name])) { - $this->addConditionFragment(self::ID_KEY . ' ' . $this->escapePredicate($this->fieldMappings[$field_name]) . ' ' . $this->toVar($field_name)); - } - } - - $condition['value'] = $this->escapeValue($condition['field'], $condition['value'], $condition['column'], $condition['lang']); - $condition['field'] = $field_name; - switch ($condition['operator']) { - case '=': - // The id is not going to end with an '=' operator so it is safe to - // use the $predicate variable. - $this->tripleFragments[] = self::ID_KEY . ' ' . $this->escapePredicate($predicate) . ' ' . $condition['value']; - break; - - case 'EXISTS': - case 'NOT EXISTS': - $this->addConditionFragment($this->compileExists($condition)); - break; - - case 'CONTAINS': - case 'LIKE': - case 'NOT LIKE': - case 'STARTS WITH': - case 'ENDS WITH': - $this->addConditionFragment($this->compileLike($condition)); - break; - - case 'IN': - $this->addConditionFragment($this->compileValuesFilter($condition)); - break; - - default: - $filter_fragments[] = $this->compileFilter($condition); - - } - } - - // Finally, bring the filters together. - if (!empty($filter_fragments)) { - $this->addConditionFragment($this->compileFilters($filter_fragments)); - } - } - - /** - * Adds a condition string to the condition fragments. - * - * The encapsulation of the condition according to the conjunction is taking - * place here. - * - * @param string $condition_string - * A string version of the condition. - */ - protected function addConditionFragment($condition_string) { - $prefix = self::$conjunctionMap[$this->conjunction]['prefix']; - $suffix = self::$conjunctionMap[$this->conjunction]['suffix']; - $this->conditionFragments[] = $prefix . $condition_string . $suffix; - } - - /** - * Adds a default condition to the condition class. - */ - protected function addDefaultTriplePattern() { - $this->compileBundleCondition(['field' => $this->bundleKey]); - } - - /** - * Adds a default bundle condition to the condition class. - * - * If the type predicates are more than one, this will result in - * { ?entity ?{$bundle_key}_predicate ?{$bundle_key} . - * VALUES ?{$bundle_key}_predicate { ... }}. - * - * If there is only one type predicate then it is added directly like - * { ?entity ? ?{$bundle_key} } - * - * This method simply adds the mapping condition for the bundle if needed - * otherwise, it simply adds a needed triple. - * - * @todo: This could work generically but currently the term storage has - * two possible predicates. This can be removed when we will be left with one - * predicate for the term storage. - */ - protected function compileBundleCondition($condition) { - if (count($this->typePredicate) > 1) { - $this->addConditionFragment(self::ID_KEY . ' ' . $this->escapePredicate($this->fieldMappings[$condition['field']]) . ' ' . $this->toVar($condition['field'])); - $this->addConditionFragment($this->compileValuesFilter([ - 'field' => $this->escapePredicate($this->fieldMappings[$condition['field']]), - 'value' => SparqlArg::toResourceUris($this->typePredicate), - 'operator' => 'IN', - ])); - } - else { - $this->addConditionFragment(self::ID_KEY . ' ' . $this->escapePredicate($this->fieldMappings[$condition['field']]) . ' ' . $this->toVar($condition['field'])); - $this->fieldMappings[$this->bundleKey] = reset($this->typePredicate); - } - } - - /** - * Compiles a filter exists (or not exists) condition. - * - * @param array $condition - * An array that contains the 'field', 'value', 'operator' values. - * - * @return string - * A condition fragment string. - */ - protected function compileExists(array $condition) { - $prefix = self::$filterOperatorMap[$condition['operator']]['prefix']; - $suffix = self::$filterOperatorMap[$condition['operator']]['suffix']; - return $prefix . self::ID_KEY . ' ' . $this->escapePredicate($this->fieldMappings[$condition['field']]) . ' ' . $this->toVar($condition['field']) . $suffix; - } - - /** - * Compiles a filter 'LIKE' condition using a regex. - * - * @param array $condition - * An array that contains the 'field', 'value', 'operator' values. - * - * @return string - * A condition fragment string. - */ - protected function compileLike(array $condition) { - $prefix = self::$filterOperatorMap[$condition['operator']]['prefix']; - $suffix = self::$filterOperatorMap[$condition['operator']]['suffix']; - $value = 'lcase(str(' . $this->toVar($condition['field']) . ')), lcase(str(' . $condition['value'] . '))'; - return $prefix . $value . $suffix; - } - - /** - * Compiles a filter condition. - * - * @param array $condition - * An array that contains the 'field', 'value', 'operator' values. - * - * @return string - * A condition fragment string. - * - * @throws \Exception - * Thrown when a value is an array but a string is expected. - */ - protected function compileFilter(array $condition) { - $prefix = self::$filterOperatorMap[$condition['operator']]['prefix']; - $suffix = self::$filterOperatorMap[$condition['operator']]['suffix']; - $condition['field'] = $this->toVar($condition['field']); - $operators = ['<', '>', '<=', '>=']; - // If the id is compared as a string, we need to convert it to one. - if ($condition['field'] === $this->fieldMappings[$this->idKey] && in_array($condition['operator'], $operators)) { - $condition['field'] = 'STR(' . $condition['field'] . ')'; - } - if (is_array($condition['value'])) { - if (!isset(self::$filterOperatorMap[$condition['operator']]['delimiter'])) { - throw new \Exception("An array value is not supported for this operator."); - } - $condition['value'] = '(' . implode(self::$filterOperatorMap[$condition['operator']]['delimiter'], $condition['value']) . ')'; - } - return $prefix . $condition['field'] . ' ' . $condition['operator'] . ' ' . $condition['value'] . $suffix; - } - - /** - * Compiles an 'IN' condition as a SPARQL 'VALUES'. - * - * 'VALUES' is preferred over 'FILTER IN' for performance. - * This should only be called for subject and predicate filter as it considers - * values to be resources. - * - * @param array $condition - * The condition array. - * - * @return string - * The string version of the condition. - */ - protected function compileValuesFilter(array $condition) { - if (is_string($condition['value'])) { - $value = [$condition['value']]; - } - else { - $value = $condition['value']; - } - return 'VALUES ' . $this->toVar($condition['field']) . ' {' . implode(' ', $value) . '}'; - } - - /** - * Compiles a filter condition. - * - * @param array $filter_fragments - * An array of filter strings. - * - * @return string - * A condition fragment string. - */ - protected function compileFilters(array $filter_fragments) { - // The delimiter is always a '&&' because otherwise it would be a separate - // condition class. - $delimiter = '&&'; - if (count($filter_fragments) > 1) { - $compiled_filter = '(' . implode(') ' . $delimiter . '(', $filter_fragments) . ')'; - } - else { - $compiled_filter = reset($filter_fragments); - } - - return 'FILTER (' . $compiled_filter . ')'; - } - - /** - * Calculates the langcode of the field if one exists. - * - * @param string $field - * The field name. - * @param string $column - * The column name. - * @param string $default_lang - * A default langcode to return. - * - * @return string - * The langcode to be used. - */ - protected function getLangCode($field, $column = NULL, $default_lang = NULL) { - $format = $this->fieldHandler->getFieldFormat($this->query->getEntityTypeId(), $field, $column); - $format = reset($format); - if ($format !== SparqlEntityStorageFieldHandlerInterface::TRANSLATABLE_LITERAL) { - return FALSE; - } - - $non_languages = [ - LanguageInterface::LANGCODE_NOT_SPECIFIED, - LanguageInterface::LANGCODE_DEFAULT, - LanguageInterface::LANGCODE_NOT_APPLICABLE, - LanguageInterface::LANGCODE_SITE_DEFAULT, - LanguageInterface::LANGCODE_SYSTEM, - ]; - - if (empty($default_lang) || in_array($default_lang, $non_languages)) { - return \Drupal::languageManager()->getCurrentLanguage()->getId(); - } - - return $default_lang; - } - - /** - * Implements \Drupal\Core\Entity\Query\ConditionInterface::exists(). - */ - public function exists($field, $lang = NULL) { - return $this->condition($field, NULL, 'EXISTS'); - } - - /** - * Implements \Drupal\Core\Entity\Query\ConditionInterface::notExists(). - */ - public function notExists($field, $lang = NULL) { - return $this->condition($field, NULL, 'NOT EXISTS'); - } - - /** - * Prefixes a keyword with a prefix in order to be treated as a variable. - * - * @param string $key - * The name of the variable. - * @param bool $blank - * Whether or not to be a blank note. - * - * @return string - * The variable. - */ - protected function toVar($key, $blank = FALSE) { - // Deal with field.property as dots are not allowed in var names. - $key = str_replace('.', '_', $key); - if (strpos($key, '?') === FALSE && strpos($key, '_:') === FALSE) { - return ($blank ? '_:' : '?') . $key; - } - - // Do not alter the string if it is already prefixed as a variable. - return $key; - } - - /** - * Escape the predicate. - * - * If the value is a uri, convert it to a resource. If it is not a uri, - * convert it to a variable. - * - * @param string $field_name - * The field machine name. - * - * @return string - * The altered $value. - */ - protected function escapePredicate($field_name) { - if (SparqlArg::isValidResource($field_name)) { - return SparqlArg::uri($field_name); - } - return $this->toVar($field_name); - } - - /** - * Handle the value according to their type. - * - * @param string $field - * The field name. - * @param mixed $value - * The value. - * @param string $column - * The column name. - * @param string|null $lang - * The langcode of the value. - * - * @return string|array - * The altered $value. - */ - protected function escapeValue($field, $value, $column = NULL, $lang = NULL) { - if (empty($value)) { - return $value; - } - - if ($field === $this->idKey) { - // If the field name is the id, and the operators are not among the '>', - // '<', '>=', '<=', then the value has already been converted in an array - // so escape it. - if (is_array($value)) { - return SparqlArg::toResourceUris($value); - } - // Convert the value to a string in order to perform the remaining - // comparisons. - elseif (is_string($value)) { - return 'STR("' . $value . '")'; - } - } - - // If the field name is the bundle key, convert the values to their - // corresponding mappings. The value is also an array. - elseif ($field === $this->bundleKey) { - $value = $this->fieldHandler->bundlesToUris($this->query->getEntityTypeId(), $value, TRUE); - return $value; - } - - $serializer = new Ntriples(); - $lang = $this->getLangCode($field, $column, $lang); - if (is_array($value)) { - foreach ($value as $i => $v) { - $outbound_value = $this->fieldHandler->getOutboundValue($this->query->getEntityTypeId(), $field, $v, $lang, $column); - $value[$i] = $serializer->serialiseValue($outbound_value); - } - } - else { - $outbound_value = $this->fieldHandler->getOutboundValue($this->query->getEntityTypeId(), $field, $value, $lang, $column); - $value = $serializer->serialiseValue($outbound_value); - } - return $value; - } - - /** - * {@inheritdoc} - */ - public function isCompiled() { - return (bool) $this->isCompiled; - } - - /** - * {@inheritdoc} - */ - public function __clone() {} - -} diff --git a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlQueryInterface.php b/sparql_entity_storage/src/Entity/Query/Sparql/SparqlQueryInterface.php deleted file mode 100644 index 59a6af2c..00000000 --- a/sparql_entity_storage/src/Entity/Query/Sparql/SparqlQueryInterface.php +++ /dev/null @@ -1,47 +0,0 @@ -name = $name; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setWeight(int $weight): SparqlGraphInterface { - $this->weight = $weight; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getWeight(): int { - return $this->weight; - } - - /** - * {@inheritdoc} - */ - public function setDescription(string $description): SparqlGraphInterface { - $this->description = $description; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getDescription(): ?string { - return $this->description; - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeIds(): ?array { - return $this->entity_types ?: NULL; - } - - /** - * {@inheritdoc} - */ - public function setEntityTypeIds(?array $entity_type_ids): SparqlGraphInterface { - if (empty($entity_type_ids)) { - $this->entity_types = NULL; - } - else { - foreach ($entity_type_ids as $entity_type_id) { - if (!$this->entityTypeManager()->getDefinition($entity_type_id, FALSE)) { - throw new \InvalidArgumentException("Invalid entity type: '$entity_type_id'."); - } - $storage = $this->entityTypeManager()->getStorage($entity_type_id); - if (!$storage instanceof SparqlEntityStorage) { - throw new \InvalidArgumentException("Entity type '$entity_type_id' doesn't have a SPARQL storage."); - } - } - $this->entity_types = $entity_type_ids; - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function delete() { - if (!$this->isUninstalling() && ($this->id() === static::DEFAULT)) { - throw new \RuntimeException("The '" . static::DEFAULT . "' graph cannot be deleted."); - } - parent::delete(); - } - - /** - * {@inheritdoc} - */ - public function preSave(EntityStorageInterface $storage) { - if ($this->entity_types === []) { - // Normalize 'entity_types' empty array to NULL. - $this->entity_types = NULL; - } - - if ($this->id() === static::DEFAULT) { - if (!$this->status()) { - throw new \RuntimeException("The '" . static::DEFAULT . "' graph cannot be disabled."); - } - if ($this->getEntityTypeIds()) { - throw new \RuntimeException("The '" . static::DEFAULT . "' graph cannot be limited to certain entity types."); - } - } - parent::preSave($storage); - } - - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - parent::postSave($storage, $update); - // Wipe out the static cache of the SPARQL graph handler. - \Drupal::service('sparql.graph_handler')->clearCache(); - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageInterface $storage, array $entities) { - parent::postDelete($storage, $entities); - \Drupal::service('sparql.graph_handler')->clearCache(); - } - -} diff --git a/sparql_entity_storage/src/Entity/SparqlMapping.php b/sparql_entity_storage/src/Entity/SparqlMapping.php deleted file mode 100644 index c2f02aa8..00000000 --- a/sparql_entity_storage/src/Entity/SparqlMapping.php +++ /dev/null @@ -1,356 +0,0 @@ - NULL, - ]; - - /** - * The base fields mapping. - * - * @var array - */ - protected $base_fields_mapping; - - /** - * The plugin that generates the entity ID. - * - * @var string - */ - protected $entity_id_plugin; - - /** - * {@inheritdoc} - */ - public function __construct(array $values, $entity_type) { - if (empty($values['entity_type_id'])) { - throw new \InvalidArgumentException('Missing required property: entity_type_id.'); - } - - // Valid entity type? - try { - $storage = $this->entityTypeManager()->getStorage($values['entity_type_id']); - } - catch (\Exception $exception) { - throw new \InvalidArgumentException("Invalid entity type: {$values['entity_type_id']}."); - } - - // Only entities with SPARQL storage are eligible. - if (!$storage instanceof SparqlEntityStorageInterface) { - throw new \InvalidArgumentException("Cannot handle non-SPARQL storage entity type: {$values['entity_type_id']}."); - } - - if ($storage->getEntityType()->hasKey('bundle') && $storage->getEntityType()->getBundleEntityType()) { - // If this entity type supports bundles as config entities, then the - // bundle should have been passed. - if (empty($values['bundle'])) { - throw new \InvalidArgumentException('Missing required property: bundle.'); - } - } - else { - // The bundle is the entity type ID, regardless of the passed value. - $values['bundle'] = $values['entity_type_id']; - } - - parent::__construct($values, $entity_type); - } - - /** - * {@inheritdoc} - */ - public function id() { - return "{$this->getTargetEntityTypeId()}.{$this->getTargetBundle()}"; - } - - /** - * {@inheritdoc} - */ - public function getTargetEntityTypeId(): string { - return $this->entity_type_id; - } - - /** - * {@inheritdoc} - */ - public function getTargetEntityType(): ?ContentEntityTypeInterface { - if (!$this->getTargetEntityTypeId()) { - return NULL; - } - return $this->entityTypeManager()->getDefinition($this->getTargetEntityTypeId()); - } - - /** - * {@inheritdoc} - */ - public function getTargetBundle(): string { - return $this->bundle; - } - - /** - * {@inheritdoc} - */ - public function setRdfType(string $rdf_type): SparqlMappingInterface { - $this->rdf_type = $rdf_type; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getRdfType(): ?string { - return $this->rdf_type; - } - - /** - * {@inheritdoc} - */ - public function setEntityIdPlugin(string $entity_id_plugin): SparqlMappingInterface { - $this->entity_id_plugin = $entity_id_plugin; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getEntityIdPlugin(): ?string { - return $this->entity_id_plugin; - } - - /** - * {@inheritdoc} - */ - public function addGraphs(array $graphs): SparqlMappingInterface { - $this->graph = $graphs + $this->graph; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setGraphs(array $graphs): SparqlMappingInterface { - if (!isset($graphs[SparqlGraphInterface::DEFAULT])) { - throw new \InvalidArgumentException("Passed graphs should include the '" . SparqlGraphInterface::DEFAULT . "' graph."); - } - $this->graph = $graphs; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getGraphs(): array { - return $this->graph; - } - - /** - * {@inheritdoc} - */ - public function getGraphUri(string $graph): ?string { - return $this->graph[$graph] ?? NULL; - } - - /** - * {@inheritdoc} - */ - public function unsetGraphs(array $graphs): SparqlMappingInterface { - $this->graph = array_diff_key($this->graph, array_flip($graphs)); - return $this; - } - - /** - * {@inheritdoc} - */ - public function addMappings(array $mappings): SparqlMappingInterface { - $this->base_fields_mapping = $mappings + $this->base_fields_mapping; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setMappings(array $mappings): SparqlMappingInterface { - $this->base_fields_mapping = $mappings; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getMappings(): array { - return $this->base_fields_mapping; - } - - /** - * {@inheritdoc} - */ - public function getMapping(string $field_name, string $column_name = 'value'): ?array { - return $this->base_fields_mapping[$field_name][$column_name] ?? NULL; - } - - /** - * {@inheritdoc} - */ - public function isMapped(string $field_name, string $column_name = 'value'): bool { - $mapping = $this->getMapping($field_name, $column_name); - return $mapping && !empty($mapping['predicate']) && !empty($mapping['format']); - } - - /** - * {@inheritdoc} - */ - public function unsetMappings(array $field_names): SparqlMappingInterface { - $this->base_fields_mapping = array_diff_key($this->base_fields_mapping, array_flip($field_names)); - return $this; - } - - /** - * {@inheritdoc} - */ - public static function loadByName(string $entity_type_id, string $bundle): ?SparqlMappingInterface { - return static::load("$entity_type_id.$bundle"); - } - - /** - * {@inheritdoc} - */ - public function calculateDependencies() { - parent::calculateDependencies(); - - /** @var \Drupal\sparql_entity_storage\SparqlGraphInterface $graph */ - foreach (SparqlGraph::loadMultiple(array_keys($this->getGraphs())) as $graph) { - // Add dependency to each graph. - $this->addDependency($graph->getConfigDependencyKey(), $graph->getConfigDependencyName()); - } - - // Add dependency to the paired bundle entity. - if ($entity_type = $this->getTargetEntityType()) { - if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) { - $bundle_storage = $this->entityTypeManager()->getStorage($bundle_entity_type_id); - if ($bundle_entity = $bundle_storage->load($this->getTargetBundle())) { - $this->addDependency($bundle_entity->getConfigDependencyKey(), $bundle_entity->getConfigDependencyName()); - } - } - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function onDependencyRemoval(array $dependencies) { - $changed = parent::onDependencyRemoval($dependencies); - - /** @var \Drupal\sparql_entity_storage\SparqlGraphInterface $graph */ - foreach ($dependencies['config'] as $graph) { - if ($graph->getEntityTypeId() === 'sparql_graph') { - // Normally we shouldn't be notified about 'default' graph deletion - // because this could never occur. However, we take this additional - // precaution to cover any accidental removal. - if ($graph->id() !== SparqlGraphInterface::DEFAULT) { - // Remove the reference to the deleted graph and flag this mapping - // entity to be re-saved. - $this->unsetGraphs([$graph->id()]); - $changed = TRUE; - } - } - // Don't react on paired bundle entity deletion (AKA remove this entity). - } - - return $changed; - } - - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - parent::postSave($storage, $update); - \Drupal::service('sparql.graph_handler')->clearCache(); - \Drupal::service('sparql.field_handler')->clearCache(); - \Drupal::entityTypeManager()->getStorage($this->entity_type_id)->resetCache(); - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageInterface $storage, array $entities) { - parent::postDelete($storage, $entities); - \Drupal::service('sparql.graph_handler')->clearCache(); - \Drupal::service('sparql.field_handler')->clearCache(); - /** @var \Drupal\sparql_entity_storage\SparqlMappingInterface $sparql_mapping */ - if ($sparql_mapping = reset($entities)) { - \Drupal::entityTypeManager()->getStorage($sparql_mapping->getTargetEntityTypeId())->resetCache(); - } - } - -} diff --git a/sparql_entity_storage/src/Event/ActiveGraphEvent.php b/sparql_entity_storage/src/Event/ActiveGraphEvent.php deleted file mode 100644 index 7b59b7c8..00000000 --- a/sparql_entity_storage/src/Event/ActiveGraphEvent.php +++ /dev/null @@ -1,151 +0,0 @@ -parameterName = $parameter_name; - $this->entityId = $entity_id; - $this->entityTypeId = $entity_type_id; - $this->parameterDefinition = $definition; - $this->routeDefaults = $route_defaults; - } - - /** - * The SPARQL entity value. - * - * @return string - * The SPARQL entity value. - */ - public function getEntityId(): string { - return $this->entityId; - } - - /** - * Returns the entity type ID. - * - * @return string - * The entity type ID. - */ - public function getEntityTypeId(): string { - return $this->entityTypeId; - } - - /** - * The parameter definition provided in the route options. - * - * @return mixed - * The parameter definition provided in the route options. - */ - public function getParameterDefinition() { - return $this->parameterDefinition; - } - - /** - * The name of the route parameter. - * - * @return string - * The parameter name. - */ - public function getParameterName(): string { - return $this->parameterName; - } - - /** - * The route defaults array. - * - * @return array - * The route defaults. - */ - public function getRouteDefaults(): array { - return $this->routeDefaults; - } - - /** - * Gets the list of graphs. - * - * @return string[]|null - * A list of graph IDs or NULL if none. - */ - public function getGraphs(): ?array { - return $this->graphs; - } - - /** - * The graphs used to load the entity. - * - * @param string[] $graphs - * The graphs used to load the entity. - * - * @return $this - */ - public function setGraphs(array $graphs): self { - $this->graphs = $graphs; - return $this; - } - -} diff --git a/sparql_entity_storage/src/Event/DefaultGraphsEvent.php b/sparql_entity_storage/src/Event/DefaultGraphsEvent.php deleted file mode 100644 index 916c398e..00000000 --- a/sparql_entity_storage/src/Event/DefaultGraphsEvent.php +++ /dev/null @@ -1,62 +0,0 @@ -entityTypeId = $entity_type_id; - $this->defaultGraphIds = $default_graph_ids; - } - - /** - * Sets the list of default graph IDs. - * - * @param array $default_graph_ids - * A list of graph IDs. - * - * @return $this - */ - public function setDefaultGraphIds(array $default_graph_ids): self { - $this->defaultGraphIds = $default_graph_ids; - return $this; - } - - /** - * Returns the list of default graph IDs. - * - * @return string[] - * A list of default graph IDs. - */ - public function getDefaultGraphIds(): array { - return $this->defaultGraphIds; - } - -} diff --git a/sparql_entity_storage/src/Event/InboundValueEvent.php b/sparql_entity_storage/src/Event/InboundValueEvent.php deleted file mode 100644 index 4a56f084..00000000 --- a/sparql_entity_storage/src/Event/InboundValueEvent.php +++ /dev/null @@ -1,8 +0,0 @@ -entityTypeId = $entity_type_id; - $this->field = $field; - $this->value = $value; - $this->lang = $lang; - $this->column = $column; - $this->bundle = $bundle; - $this->fieldMappingInfo = $field_mapping_info; - } - - /** - * Returns the entity type id. - * - * @return string - * The entity type id. - */ - public function getEntityTypeId() { - return $this->entityTypeId; - } - - /** - * Returns the field name. - * - * @return string - * The field name. - */ - public function getField() { - return $this->field; - } - - /** - * Returns the field column value. - * - * @return string - * The field column value. - */ - public function getValue() { - return $this->value; - } - - /** - * Sets the field column value. - * - * @param string $value - * The value to set. - */ - public function setValue($value) { - $this->value = $value; - } - - /** - * Returns an associative array with information on the mapping of the field. - * - * @return array - * The array filled with information about the field mappings. - */ - public function getFieldMappingInfo() { - return $this->fieldMappingInfo; - } - - /** - * Returns the field language. - * - * @return null|string - * The field language, or NULL if not available. - */ - public function getLang() { - return $this->lang; - } - - /** - * Returns the field column. - * - * @return null|string - * The field column, or NULL if not available. - */ - public function getColumn() { - return $this->column; - } - - /** - * Returns the entity bundle. - * - * @return null|string - * The entity bundle, or NULL if not available. - */ - public function getBundle() { - return $this->bundle; - } - -} diff --git a/sparql_entity_storage/src/EventSubscriber/DateTimeTrait.php b/sparql_entity_storage/src/EventSubscriber/DateTimeTrait.php deleted file mode 100644 index f87b1b71..00000000 --- a/sparql_entity_storage/src/EventSubscriber/DateTimeTrait.php +++ /dev/null @@ -1,38 +0,0 @@ -getDateDataTypes()); - } - - /** - * Returns the XML date data types and their format for the date() function. - * - * @return array - * The list of date data types. - */ - protected function getDateDataTypes() { - return [ - // \DateTime::ISO8601 is actually not compliant with ISO8601 at all. - // @see http://php.net/manual/en/class.datetime.php#datetime.constants.iso8601 - 'xsd:dateTime' => 'c', - 'xsd:date' => 'Y-m-d', - ]; - } - -} diff --git a/sparql_entity_storage/src/EventSubscriber/InboundValueDateTimeSubscriber.php b/sparql_entity_storage/src/EventSubscriber/InboundValueDateTimeSubscriber.php deleted file mode 100644 index 22ab36f0..00000000 --- a/sparql_entity_storage/src/EventSubscriber/InboundValueDateTimeSubscriber.php +++ /dev/null @@ -1,48 +0,0 @@ - 'massageInboundValue', - ]; - } - - /** - * Massages inbound values. - * - * Converts field properties with a "timestamp" data type that have been - * mapped to date formats (xsd:date or xsd:dateTime). - * - * @param \Drupal\sparql_entity_storage\Event\InboundValueEvent $event - * The inbound value event. - */ - public function massageInboundValue(InboundValueEvent $event) { - $mapping_info = $event->getFieldMappingInfo(); - - if ($this->isTimestampAsDateField($mapping_info)) { - // We cannot use DrupalDateTime::createFromFormat() as it relies on - // \DateTime::createFromFormat(), which has issues with ISO8601 dates. - // Instantiating a new object works instead. - // @see https://bugs.php.net/bug.php?id=51950 - $value = new DrupalDateTime($event->getValue()); - $event->setValue($value->getTimestamp()); - } - } - -} diff --git a/sparql_entity_storage/src/EventSubscriber/InboundValueTranslatableLiteralSubscriber.php b/sparql_entity_storage/src/EventSubscriber/InboundValueTranslatableLiteralSubscriber.php deleted file mode 100644 index 1c798f65..00000000 --- a/sparql_entity_storage/src/EventSubscriber/InboundValueTranslatableLiteralSubscriber.php +++ /dev/null @@ -1,65 +0,0 @@ -typedDataManager = $typed_data_manager; - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() { - return [ - SparqlEntityStorageEvents::INBOUND_VALUE => 'castTranslatableLiteralValue', - ]; - } - - /** - * Massages inbound translatable literal value value. - * - * @param \Drupal\sparql_entity_storage\Event\InboundValueEvent $event - * The inbound value event. - */ - public function castTranslatableLiteralValue(InboundValueEvent $event) { - $mapping_info = $event->getFieldMappingInfo(); - - // There's no way to store translated values other than with `t_literal' but - // in Drupal we might have other types of primitives that are translatable, - // like translated integers, booleans, etc. We cast the values here to get - // the correct primitive type. - if ($mapping_info['format'] === 't_literal' && $mapping_info['data_type'] !== 'string') { - $typed_data_plugin = $this->typedDataManager->create(DataDefinition::createFromDataType($mapping_info['data_type'])); - if ($typed_data_plugin instanceof PrimitiveInterface) { - $typed_data_plugin->setValue($event->getValue()); - $event->setValue($typed_data_plugin->getCastedValue()); - } - } - } - -} diff --git a/sparql_entity_storage/src/EventSubscriber/OutboundValueDateTimeSubscriber.php b/sparql_entity_storage/src/EventSubscriber/OutboundValueDateTimeSubscriber.php deleted file mode 100644 index 3d94efb8..00000000 --- a/sparql_entity_storage/src/EventSubscriber/OutboundValueDateTimeSubscriber.php +++ /dev/null @@ -1,44 +0,0 @@ - 'massageOutboundValue', - ]; - } - - /** - * Massages outbound values. - * - * Converts field properties with a "timestamp" data type that have been - * mapped to date formats (xsd:date or xsd:dateTime). - * - * @param \Drupal\sparql_entity_storage\Event\OutboundValueEvent $event - * The outbound value event. - */ - public function massageOutboundValue(OutboundValueEvent $event) { - $mapping_info = $event->getFieldMappingInfo(); - - if ($this->isTimestampAsDateField($mapping_info)) { - $value = DrupalDateTime::createFromTimestamp($event->getValue()); - $event->setValue($value->format($this->getDateDataTypes()[$mapping_info['format']])); - } - } - -} diff --git a/sparql_entity_storage/src/EventSubscriber/SparqlContentTypesSubscriber.php b/sparql_entity_storage/src/EventSubscriber/SparqlContentTypesSubscriber.php deleted file mode 100644 index 373f6c39..00000000 --- a/sparql_entity_storage/src/EventSubscriber/SparqlContentTypesSubscriber.php +++ /dev/null @@ -1,37 +0,0 @@ -getMimeTypes()); - $event->getRequest()->setFormat($format->getName(), $mime); - } - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() { - $events[KernelEvents::REQUEST][] = ['onKernelRequest']; - return $events; - } - -} diff --git a/sparql_entity_storage/src/Exception/DuplicatedIdException.php b/sparql_entity_storage/src/Exception/DuplicatedIdException.php deleted file mode 100644 index eeb82414..00000000 --- a/sparql_entity_storage/src/Exception/DuplicatedIdException.php +++ /dev/null @@ -1,8 +0,0 @@ -getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) { - $form_state->setError($element['cardinality_number'], $this->t('Number of values is required.')); - } - } - -} diff --git a/sparql_entity_storage/src/Form/SparqlGraphForm.php b/sparql_entity_storage/src/Form/SparqlGraphForm.php deleted file mode 100644 index b3b2c4c3..00000000 --- a/sparql_entity_storage/src/Form/SparqlGraphForm.php +++ /dev/null @@ -1,106 +0,0 @@ -getEntity(); - - $form['name'] = [ - '#title' => t('Name'), - '#type' => 'textfield', - '#default_value' => $graph->label(), - '#description' => $this->t('The human-readable name of this graph.'), - '#required' => TRUE, - '#size' => 30, - ]; - - $form['id'] = [ - '#type' => 'machine_name', - '#default_value' => $graph->id(), - '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH, - '#disabled' => !$graph->isNew(), - '#machine_name' => [ - 'exists' => [SparqlGraph::class, 'load'], - 'source' => ['name'], - ], - '#description' => $this->t('A unique machine-readable name for this graph. It must only contain lowercase letters, numbers, and underscores.'), - ]; - - $form['weight'] = [ - '#type' => 'value', - '#value' => $graph->getWeight(), - ]; - - $form['description'] = [ - '#title' => $this->t('Description'), - '#type' => 'textarea', - '#default_value' => $graph->getDescription(), - '#description' => $this->t('The description of this graph.'), - ]; - - $entity_types = []; - foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { - if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) { - if ($storage instanceof SparqlEntityStorage) { - $entity_types[$entity_type_id] = $entity_type->getLabel(); - } - } - } - - $form['entity_types'] = [ - '#type' => 'checkboxes', - '#title' => $this->t('Entity types using this graph'), - '#description' => $this->t('If none is selected, this graph is made available to all entity types that are using SPARQL storage.'), - '#options' => $entity_types, - '#disabled' => $graph->id() === SparqlGraphInterface::DEFAULT, - '#access' => (bool) $entity_types, - '#default_value' => (array) $graph->getEntityTypeIds(), - ]; - - return $form; - } - - /** - * {@inheritdoc} - */ - public function buildEntity(array $form, FormStateInterface $form_state): EntityInterface { - // Normalize the entity types array. - $entity_types = $form_state->getValue('entity_types'); - $form_state->setValue('entity_types', array_values(array_filter($entity_types))); - return parent::buildEntity($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function save(array $form, FormStateInterface $form_state): int { - $form_state->setRedirect('entity.sparql_graph.collection'); - drupal_set_message($this->t("Graph %name (%id) has been saved.", [ - '%name' => $this->getEntity()->label(), - '%id' => $this->getEntity()->id(), - ])); - return parent::save($form, $form_state); - } - -} diff --git a/sparql_entity_storage/src/Normalizer/NormalizerBase.php b/sparql_entity_storage/src/Normalizer/NormalizerBase.php deleted file mode 100644 index d1a51db4..00000000 --- a/sparql_entity_storage/src/Normalizer/NormalizerBase.php +++ /dev/null @@ -1,22 +0,0 @@ -compile()->getVariables(), TRUE); - } - // This converter only applies SPARQL entities. - $entity_storage = $this->entityManager->getStorage($entity_type_id); - if ($entity_storage instanceof SparqlEntityStorage) { - return $this->entityManager->hasDefinition($entity_type_id); - } - } - return FALSE; - } - - /** - * {@inheritdoc} - */ - public function convert($value, $definition, $name, array $defaults) { - // Here the escaped URI is transformed into a valid URI. - if (!SparqlArg::isValidResource($value)) { - $value = UriEncoder::decodeUrl($value); - } - $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults); - /** @var \Drupal\sparql_entity_storage\SparqlEntityStorageInterface $storage */ - $storage = $this->entityManager->getStorage($entity_type_id); - /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher */ - $dispatcher = \Drupal::getContainer()->get('event_dispatcher'); - $event = new ActiveGraphEvent($name, $value, $entity_type_id, $definition, $defaults); - // Determine the graph by dispatching an event. - $event = $dispatcher->dispatch(SparqlEntityStorageEvents::GRAPH_ENTITY_CONVERT, $event); - $entity = $storage->load($value, $event->getGraphs()); - // If the entity type is translatable, ensure we return the proper - // translation object for the current context. - if ($entity instanceof EntityInterface && $entity instanceof TranslatableInterface) { - $entity = $this->entityManager->getTranslationFromContext($entity, NULL, ['operation' => 'entity_upcast']); - } - return $entity; - } - -} diff --git a/sparql_entity_storage/src/Plugin/sparql_entity_storage/Id/DefaultSparqlEntityStorageEntityIdGenerator.php b/sparql_entity_storage/src/Plugin/sparql_entity_storage/Id/DefaultSparqlEntityStorageEntityIdGenerator.php deleted file mode 100644 index 472924df..00000000 --- a/sparql_entity_storage/src/Plugin/sparql_entity_storage/Id/DefaultSparqlEntityStorageEntityIdGenerator.php +++ /dev/null @@ -1,72 +0,0 @@ -uuid = $uuid; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity_type.manager'), - $container->get('uuid') - ); - } - - /** - * {@inheritdoc} - */ - public function generate() { - global $base_url; - - $entity_type_id = $this->getEntity()->getEntityTypeId(); - $bundle = $this->getEntity()->bundle(); - $uuid = $this->uuid->generate(); - - return "$base_url/$entity_type_id/$bundle/$uuid"; - } - -} diff --git a/sparql_entity_storage/src/RouteProcessor/SparqlEntityStorageRouteProcessor.php b/sparql_entity_storage/src/RouteProcessor/SparqlEntityStorageRouteProcessor.php deleted file mode 100644 index df89f49e..00000000 --- a/sparql_entity_storage/src/RouteProcessor/SparqlEntityStorageRouteProcessor.php +++ /dev/null @@ -1,52 +0,0 @@ -routeMatch = $route_match; - } - - /** - * {@inheritdoc} - */ - public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) { - if ($route->hasOption('parameters')) { - foreach ($route->getOption('parameters') as $type => $parameter) { - // If the converter exists in the parameter, then the parameter needs to - // be normalized. - if (isset($parameter['converter']) && $parameter['converter'] === 'sparql.paramconverter' && SparqlArg::isValidResource($parameters[$type])) { - $parameters[$type] = UriEncoder::encodeUrl($parameters[$type]); - } - } - } - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorage.php b/sparql_entity_storage/src/SparqlEntityStorage.php deleted file mode 100644 index 4702437d..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorage.php +++ /dev/null @@ -1,1334 +0,0 @@ -sparql = $sparql; - $this->entityTypeManager = $entity_type_manager; - $this->languageManager = $language_manager; - $this->moduleHandler = $module_handler; - $this->graphHandler = $sparql_graph_handler; - $this->fieldHandler = $sparql_field_handler; - $this->entityIdPluginManager = $entity_id_plugin_manager; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity_field.manager'), - $container->get('cache.entity'), - $container->get('entity.memory_cache'), - $container->get('entity_type.bundle.info'), - $container->get('sparql.endpoint'), - $container->get('entity_type.manager'), - $container->get('language_manager'), - $container->get('module_handler'), - $container->get('sparql.graph_handler'), - $container->get('sparql.field_handler'), - $container->get('plugin.manager.sparql_entity_id') - ); - } - - /** - * Builds a new graph (list of triples). - * - * @param string $graph_uri - * The URI of the graph. - * - * @return \EasyRdf\Graph - * The EasyRdf graph object. - */ - protected static function getGraph($graph_uri) { - $graph = new Graph($graph_uri); - return $graph; - } - - /** - * {@inheritdoc} - */ - public function getBundlePredicates(): array { - return $this->bundlePredicate; - } - - /** - * {@inheritdoc} - */ - public function getGraphHandler(): SparqlEntityStorageGraphHandlerInterface { - return $this->graphHandler; - } - - /** - * {@inheritdoc} - */ - public function getGraphDefinitions(): array { - return $this->getGraphHandler()->getGraphDefinitions($this->entityTypeId); - } - - /** - * {@inheritdoc} - */ - protected function doLoadMultiple(array $ids = NULL, array $graph_ids = []) { - // Attempt to load entities from the persistent cache. This will remove IDs - // that were loaded from $ids. - $entities_from_cache = $this->getFromPersistentCache($ids, $graph_ids); - // Load any remaining entities from the database. - $entities_from_storage = $this->getFromStorage($ids, $graph_ids); - - return $entities_from_cache + $entities_from_storage; - } - - /** - * Gets entities from the storage. - * - * @param array|null $ids - * If not empty, return entities that match these IDs. Return all entities - * when NULL. - * @param array $graph_ids - * A list of graph IDs. - * - * @return \Drupal\Core\Entity\ContentEntityInterface[] - * Array of entities from the storage. - * - * @throws \Drupal\sparql_entity_storage\Exception\SparqlQueryException - * If the SPARQL query fails. - * @throws \Exception - * The query fails with no specific reason. - */ - protected function getFromStorage(array $ids = NULL, array $graph_ids = []): array { - if (empty($ids)) { - return []; - } - $remaining_ids = $ids; - $entities = []; - while (count($remaining_ids)) { - $operation_ids = array_slice($remaining_ids, 0, 50, TRUE); - foreach ($operation_ids as $k => $v) { - unset($remaining_ids[$k]); - } - $entities_values = $this->loadFromStorage($operation_ids, $graph_ids); - if ($entities_values) { - foreach ($entities_values as $id => $entity_values) { - $bundle = $this->bundleKey ? $entity_values[$this->bundleKey][LanguageInterface::LANGCODE_DEFAULT] : FALSE; - $langcode_key = $this->getEntityType()->getKey('langcode'); - $translations = []; - if (!empty($entities_values[$id][$langcode_key])) { - foreach ($entities_values[$id][$langcode_key] as $langcode => $data) { - if (!empty(reset($data)['value'])) { - $translations[] = reset($data)['value']; - } - } - } - $entity = new $this->entityClass($entity_values, $this->entityTypeId, $bundle, $translations); - $this->trackOriginalGraph($entity); - $entities[$id] = $entity; - } - $this->invokeStorageLoadHook($entities); - $this->setPersistentCache($entities); - } - } - return $entities; - } - - /** - * Retrieves the entity data from the SPARQL endpoint. - * - * @param string[] $ids - * A list of entity IDs. - * @param string[]|null $graph_ids - * An ordered list of candidate graph IDs. - * - * @return array|null - * The entity values indexed by the field mapping ID or NULL in there are no - * results. - * - * @throws \Drupal\sparql_entity_storage\Exception\SparqlQueryException - * If the SPARQL query fails. - * @throws \Exception - * The query fails with no specific reason. - */ - protected function loadFromStorage(array $ids, array $graph_ids): ?array { - if (empty($ids)) { - return []; - } - - // @todo: We should filter per entity per graph and not load the whole - // database only to filter later on. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/2 - $ids_string = SparqlArg::serializeUris($ids, ' '); - $graphs = $this->getGraphHandler()->getEntityTypeGraphUrisFlatList($this->getEntityTypeId()); - $named_graph = ''; - foreach ($graphs as $graph) { - $named_graph .= 'FROM NAMED ' . SparqlArg::uri($graph) . "\n"; - } - - // @todo Get rid of the language filter. It's here because of eurovoc: - // \Drupal\taxonomy\Form\OverviewTerms::buildForm loads full entities - // of the whole tree: 7000+ terms in 24 languages is just too much. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/2 - $query = <<sparql->query($query); - return $this->processGraphResults($entity_values, $graph_ids); - } - - /** - * Processes results from the load query and returns a list of values. - * - * When an entity is loaded, the values might derive from multiple graph. This - * function will process the results and attempt to load a published version - * of the entity. If there is no published version available, then it will - * fallback to the rest of the graphs. - * - * If the graph parameter can be used to restrict the available graphs to load - * from. - * - * @param \EasyRdf\Sparql\Result|\EasyRdf\Graph $results - * A set of query results indexed per graph and entity id. - * @param string[] $graph_ids - * Graph IDs. - * - * @return array|null - * The entity values indexed by the field mapping ID or NULL in there are no - * results. - * - * @throws \Exception - * Thrown when the entity graph is empty. - * - * @see https://github.com/ec-europa/sparql_entity_storage/issues/2 - * - * @todo Reduce the cyclomatic complexity of this function in #19. - */ - protected function processGraphResults($results, array $graph_ids): ?array { - $values_per_entity = $this->deserializeGraphResults($results); - if (empty($values_per_entity)) { - return NULL; - } - - $default_language = $this->languageManager->getDefaultLanguage()->getId(); - $inbound_map = $this->fieldHandler->getInboundMap($this->entityTypeId); - $return = []; - foreach ($values_per_entity as $entity_id => $values_per_graph) { - $graph_uris = $this->getGraphHandler()->getEntityTypeGraphUris($this->getEntityTypeId()); - foreach ($graph_ids as $priority_graph_id) { - foreach ($values_per_graph as $graph_uri => $entity_values) { - // If the entity has been processed or the backend didn't returned - // anything for this graph, jump to the next graph retrieved from the - // SPARQL backend. - if (isset($return[$entity_id]) || array_search($graph_uri, array_column($graph_uris, $priority_graph_id)) === FALSE) { - continue; - } - - $bundle = $this->getActiveBundle($entity_values); - if (!$bundle) { - continue; - } - - // Check if the graph checked is in the request graphs. If there are - // multiple graphs set, probably the default is requested with the - // rest as fallback or it is a neutral call. If the default is - // requested, it is going to be first in line so in any case, use the - // first one. - if (!$graph_id = $this->getGraphHandler()->getBundleGraphId($this->getEntityTypeId(), $bundle, $graph_uri)) { - continue; - } - - // Map bundle and entity id. - $return[$entity_id][$this->bundleKey][LanguageInterface::LANGCODE_DEFAULT] = $bundle; - $return[$entity_id][$this->idKey][LanguageInterface::LANGCODE_DEFAULT] = $entity_id; - $return[$entity_id]['graph'][LanguageInterface::LANGCODE_DEFAULT] = $graph_id; - - $rdf_type = NULL; - foreach ($entity_values as $predicate => $field) { - $field_name = isset($inbound_map['fields'][$predicate][$bundle]['field_name']) ? $inbound_map['fields'][$predicate][$bundle]['field_name'] : NULL; - if (empty($field_name)) { - continue; - } - - $column = $inbound_map['fields'][$predicate][$bundle]['column']; - foreach ($field as $lang => $items) { - $langcode_key = ($lang === $default_language) ? LanguageInterface::LANGCODE_DEFAULT : $lang; - foreach ($items as $delta => $item) { - $item = $this->fieldHandler->getInboundValue($this->getEntityTypeId(), $field_name, $item, $langcode_key, $column, $bundle); - - if (!isset($return[$entity_id][$field_name][$langcode_key]) || !is_string($return[$entity_id][$field_name][$langcode_key])) { - $return[$entity_id][$field_name][$langcode_key][$delta][$column] = $item; - } - } - if (is_array($return[$entity_id][$field_name][$langcode_key])) { - $this->applyFieldDefaults($inbound_map['fields'][$predicate][$bundle]['type'], $return[$entity_id][$field_name][$langcode_key]); - } - } - } - } - } - } - return $return; - } - - /** - * Deserializes a list of graph results to an array. - * - * The results array is an array of loaded entity values from different - * graphs. - * @code - * $results = [ - * 'http://entity_id.uri' => [ - * 'http://field.mapping.uri' => [ - * 'x-default' => [ - * 0 => 'actual value' - * ] - * ] - * ]; - * @code - * - * @param \EasyRdf\Sparql\Result|\EasyRdf\Result $results - * A set of query results indexed per graph and entity id. - * - * @return array - * The entity values indexed by the field mapping id. - */ - protected function deserializeGraphResults(Result $results): array { - $values_per_entity = []; - foreach ($results as $result) { - $entity_id = (string) $result->entity_id; - $entity_graphs[$entity_id] = (string) $result->graph; - - $lang = LanguageInterface::LANGCODE_DEFAULT; - if ($result->field_value instanceof Literal) { - $lang_temp = $result->field_value->getLang(); - if ($lang_temp) { - $lang = $lang_temp; - } - } - $values_per_entity[$entity_id][(string) $result->graph][(string) $result->predicate][$lang][] = (string) $result->field_value; - } - - return $values_per_entity; - } - - /** - * Derives the bundle from the rdf:type. - * - * @param array $entity_values - * Entity in a raw formatted array. - * - * @return string - * The bundle ID string. - * - * @throws \Exception - * Thrown when the bundle is not found. - */ - protected function getActiveBundle(array $entity_values): ?string { - $bundles = []; - foreach ($this->bundlePredicate as $bundle_predicate) { - if (isset($entity_values[$bundle_predicate])) { - $bundle_data = $entity_values[$bundle_predicate]; - $bundles += $this->fieldHandler->getInboundBundleValue($this->entityTypeId, $bundle_data[LanguageInterface::LANGCODE_DEFAULT][0]); - } - } - if (empty($bundles)) { - return NULL; - } - - // Since it is possible to map more than one bundles to the same uri, allow - // modules to handle this. - $this->moduleHandler->alter('sparql_bundle_load', $entity_values, $bundles); - if (count($bundles) > 1) { - throw new \Exception('More than one bundles are defined for this uri.'); - } - return reset($bundles); - } - - /** - * {@inheritdoc} - */ - public function load($id, array $graph_ids = NULL): ?ContentEntityInterface { - $entities = $this->loadMultiple([$id], $graph_ids); - return array_shift($entities); - } - - /** - * {@inheritdoc} - */ - public function loadMultiple(array $ids = NULL, array $graph_ids = NULL): array { - $this->checkGraphs($graph_ids); - - // We copy this part from parent::loadMultiple(), otherwise we cannot pass - // the $graph_ids to self::getFromStaticCache() and self::doLoadMultiple(). - // START parent::loadMultiple() fork. - $entities = []; - $passed_ids = !empty($ids) ? array_flip($ids) : FALSE; - if ($this->entityType->isStaticallyCacheable() && $ids) { - $entities += $this->getFromStaticCache($ids, $graph_ids); - if ($passed_ids) { - $ids = array_keys(array_diff_key($passed_ids, $entities)); - } - } - if ($ids === NULL || $ids) { - $queried_entities = $this->doLoadMultiple($ids, $graph_ids); - } - if (!empty($queried_entities)) { - $this->postLoad($queried_entities); - $entities += $queried_entities; - } - if ($this->entityType->isStaticallyCacheable()) { - if (!empty($queried_entities)) { - $this->setStaticCache($queried_entities); - } - } - if ($passed_ids) { - $passed_ids = array_intersect_key($passed_ids, $entities); - foreach ($entities as $entity) { - $passed_ids[$entity->id()] = $entity; - } - $entities = $passed_ids; - } - // END parent::loadMultiple() fork. - if (empty($entities)) { - return []; - } - - return $entities; - } - - /** - * {@inheritdoc} - */ - protected function doPreSave(EntityInterface $entity) { - // The code bellow is forked from EntityStorageBase::doPreSave() and - // ContentEntityStorageBase::doPreSave(). We are not using the original - // methods in order to be able to pass an additional list of graphs - // parameter to ::loadUnchanged() method. - // START forking from ContentEntityStorageBase::doPreSave(). - /** @var \Drupal\Core\Entity\ContentEntityBase $entity */ - $entity->updateOriginalValues(); - if ($entity->getEntityType()->isRevisionable() && !$entity->isNew() && empty($entity->getLoadedRevisionId())) { - $entity->updateLoadedRevisionId(); - } - - // START forking from EntityStorageBase::doPreSave(). - $id = $entity->id(); - if ($entity->getOriginalId() !== NULL) { - $id = $entity->getOriginalId(); - } - $id_exists = $this->has($id, $entity); - if ($id_exists && $entity->isNew()) { - throw new EntityStorageException("'{$this->entityTypeId}' entity with ID '$id' already exists."); - } - if ($id_exists && !isset($entity->original)) { - // In the case when the entity graph has been changed before saving, we - // need the original graph, so that we load the original/unchanged entity - // from the backend. This property was set in during entity load, in - // ::trackOriginalGraph(). We can rely on this property also when the - // entity us saved via UI, as this value persists in entity over an entity - // form submit, because the entity is stored in the form state. - // @see \Drupal\sparql_entity_storage\SparqlEntityStorage::trackOriginalGraph() - $entity->original = $this->loadUnchanged($id, [$entity->sparqlEntityOriginalGraph]); - } - $entity->preSave($this); - $this->invokeHook('presave', $entity); - // END forking from EntityStorageBase::doPreSave(). - if (!$entity->isNew()) { - if (empty($entity->original) || $entity->id() != $entity->original->id()) { - throw new EntityStorageException("Update existing '{$this->entityTypeId}' entity while changing the ID is not supported."); - } - if (!$entity->isNewRevision() && $entity->getRevisionId() != $entity->getLoadedRevisionId()) { - throw new EntityStorageException("Update existing '{$this->entityTypeId}' entity revision while changing the revision ID is not supported."); - } - } - // END forking from ContentEntityStorageBase::doPreSave(). - // Finally reset the entity original graph property so that that its updated - // value is available for the rest of this request. - $this->trackOriginalGraph($entity); - - return $id; - } - - /** - * {@inheritdoc} - */ - public function loadUnchanged($id, array $graph_ids = NULL): ?ContentEntityInterface { - $this->checkGraphs($graph_ids); - - // START: Code forked from parent::loadUnchanged() and adapted to accept - // graph andidates. - $ids = [$id]; - parent::resetCache($ids); - - // START: Code adapted from EntityStorageBase::resetCache(). - // This part is replacing the ContentEntityStorageBase::resetCache() line. - if ($this->entityType->isStaticallyCacheable()) { - foreach ($graph_ids as $graph_id) { - unset($this->entities[$id][$graph_id]); - } - } - // END: Code adapted from EntityStorageBase::resetCache(). - $entities = $this->getFromPersistentCache($ids, $graph_ids); - if (!$entities) { - $entities[$id] = $this->load($id, $graph_ids); - } - else { - $this->postLoad($entities); - if ($this->entityType->isStaticallyCacheable()) { - $this->setStaticCache($entities); - } - } - - return $entities[$id]; - // END: Code forked from parent::loadUnchanged(). - } - - /** - * {@inheritdoc} - */ - public function loadRevision($revision_id) { - list($entity_id, $graph) = explode('||', $revision_id); - - return NULL; - } - - /** - * {@inheritdoc} - */ - public function deleteRevision($revision_id) { - } - - /** - * {@inheritdoc} - */ - public function deleteFromGraph(array $entities, string $graph_id): void { - if (!empty($entities)) { - $ids = array_map(function (ContentEntityInterface $entity): string { - return $entity->id(); - }, $entities); - // Make sure that passed entities are keyed by entity ID and are loaded - // only from the requested graph. - $entities = $this->loadMultiple($ids, [$graph_id]); - $this->doDelete($entities); - $this->resetCache(array_keys($entities)); - } - } - - /** - * {@inheritdoc} - */ - public function hasGraph(EntityInterface $entity, string $graph_id): bool { - $graph_uri = $this->getGraphHandler()->getBundleGraphUri($entity->getEntityTypeId(), $entity->bundle(), $graph_id); - return $this->idExists($entity->id(), $graph_uri); - } - - /** - * {@inheritdoc} - */ - public function loadByProperties(array $values = [], array $graph_ids = NULL): array { - $this->checkGraphs($graph_ids); - - /** @var \Drupal\sparql_entity_storage\Entity\Query\Sparql\SparqlQueryInterface $query */ - $query = $this->getQuery() - ->graphs($graph_ids) - ->accessCheck(FALSE); - $this->buildPropertyQuery($query, $values); - $result = $query->execute(); - - return $result ? $this->loadMultiple($result, $graph_ids) : []; - } - - /** - * {@inheritdoc} - */ - public function delete(array $entities) { - if (!$entities) { - // If no entities were passed, do nothing. - return; - } - - // Ensure that the entities are keyed by ID. - $keyed_entities = []; - foreach ($entities as $entity) { - $keyed_entities[$entity->id()] = $entity; - } - - // Allow code to run before deleting. - $entity_class = $this->entityClass; - $entity_class::preDelete($this, $keyed_entities); - foreach ($keyed_entities as $entity) { - $this->invokeHook('predelete', $entity); - } - $entities_by_graph = []; - /** @var \Drupal\Core\Entity\EntityInterface $keyed_entity */ - foreach ($keyed_entities as $keyed_entity) { - // Determine all possible graphs for the entity. - $graphs_by_bundle = $this->getGraphHandler()->getEntityTypeGraphUris($this->getEntityTypeId()); - $graphs = $graphs_by_bundle[$keyed_entity->bundle()]; - foreach ($graphs as $graph_name => $graph_uri) { - $entities_by_graph[$graph_uri][$keyed_entity->id()] = $keyed_entity; - } - } - /** @var string $id */ - foreach ($entities_by_graph as $graph => $entities_to_delete) { - $this->doDeleteFromGraph($entities_to_delete, $graph); - } - $this->resetCache(array_keys($keyed_entities), array_keys($graphs)); - - // Allow code to run after deleting. - $entity_class::postDelete($this, $keyed_entities); - foreach ($keyed_entities as $entity) { - $this->invokeHook('delete', $entity); - } - } - - /** - * {@inheritdoc} - */ - protected function doDelete($entities) { - $entities_by_graph = []; - /** @var string $id */ - /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ - foreach ($entities as $id => $entity) { - $graph_uri = $this->getGraphHandler()->getBundleGraphUri($entity->getEntityTypeId(), $entity->bundle(), $entity->graph->target_id); - $entities_by_graph[$graph_uri][$id] = $entity; - } - foreach ($entities_by_graph as $graph_uri => $entities_to_delete) { - $this->doDeleteFromGraph($entities, $graph_uri); - } - } - - /** - * Constructs and execute the delete query. - * - * @param array $entities - * An array of entity objects to delete. - * @param string $graph_uri - * The graph URI to delete from. - * - * @throws \Drupal\sparql_entity_storage\Exception\SparqlQueryException - * If the SPARQL query fails. - * @throws \Exception - * The query fails with no specific reason. - */ - protected function doDeleteFromGraph(array $entities, string $graph_uri): void { - $entity_list = SparqlArg::serializeUris(array_keys($entities)); - - $query = << -{ - ?entity ?field ?value -} -WHERE -{ - ?entity ?field ?value - FILTER( - ?entity IN ($entity_list) - ) -} -QUERY; - $this->sparql->query($query); - } - - /** - * {@inheritdoc} - */ - protected function getQueryServiceName() { - return 'entity.query.sparql'; - } - - /** - * {@inheritdoc} - */ - protected function doLoadRevisionFieldItems($revision_id) { - } - - /** - * {@inheritdoc} - */ - protected function doSaveFieldItems(ContentEntityInterface $entity, array $names = []) { - } - - /** - * {@inheritdoc} - */ - protected function doDeleteFieldItems($entities) { - } - - /** - * {@inheritdoc} - */ - protected function doDeleteRevisionFieldItems(ContentEntityInterface $revision) { - } - - /** - * {@inheritdoc} - */ - protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definition, $batch_size) { - return []; - } - - /** - * {@inheritdoc} - */ - protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefinitionInterface $field_definition) { - } - - /** - * {@inheritdoc} - */ - protected function doSave($id, EntityInterface $entity) { - $bundle = $entity->bundle(); - // Generate an ID before saving, if none is available. If the ID generation - // occurs earlier in the process (like on EntityInterface::create()), the - // entity might be considered not new by modules that don't strictly use the - // EntityInterface::isNew() method. - if (empty($id)) { - $id = $this->entityIdPluginManager->getPlugin($entity)->generate(); - $entity->{$this->idKey} = $id; - } - elseif ($entity->isNew() && $this->idExists($id)) { - throw new DuplicatedIdException("Attempting to create a new entity with the ID '$id' already taken."); - } - - // If the graph is not specified, fallback to the default one for the entity - // type. - if ($entity->get('graph')->isEmpty()) { - $entity->set('graph', $this->getGraphHandler()->getDefaultGraphId($this->getEntityTypeId())); - } - - $graph_id = $entity->get('graph')->target_id; - $graph_uri = $this->getGraphHandler()->getBundleGraphUri($entity->getEntityTypeId(), $entity->bundle(), $graph_id); - $graph = self::getGraph($graph_uri); - $lang_array = $this->toLangArray($entity); - foreach ($lang_array as $field_name => $langcode_data) { - foreach ($langcode_data as $langcode => $field_item) { - foreach ($field_item as $delta => $column_data) { - foreach ($column_data as $column => $value) { - // Filter out empty values or non mapped fields. The id is also - // excluded as it is not mapped. - if ($value === NULL || $value === '' || !$this->fieldHandler->hasFieldPredicate($this->getEntityTypeId(), $bundle, $field_name, $column)) { - continue; - } - $predicate = $this->fieldHandler->getFieldPredicates($this->getEntityTypeId(), $field_name, $column, $bundle); - $predicate = reset($predicate); - $value = $this->fieldHandler->getOutboundValue($this->getEntityTypeId(), $field_name, $value, $langcode, $column, $bundle); - $graph->add((string) $id, $predicate, $value); - } - } - } - } - - // Give implementations a chance to alter the graph right before is saved. - $this->alterGraph($graph, $entity); - - if (!$entity->isNew()) { - $this->deleteBeforeInsert($id, $graph_uri); - } - try { - $this->insert($graph, $graph_uri); - return $entity->isNew() ? SAVED_NEW : SAVED_UPDATED; - } - catch (\Exception $e) { - return FALSE; - } - } - - /** - * {@inheritdoc} - */ - protected function doPostSave(EntityInterface $entity, $update) { - parent::doPostSave($entity, $update); - - // After saving, this is now the "original entity", but subsequent saves - // must be able to reference the original graph. - // @see \Drupal\Core\Entity\EntityStorageBase::doPostSave() - $this->trackOriginalGraph($entity); - } - - /** - * In this method the latest values have to be applied to the entity. - * - * The end array should have an index with the x-default language which should - * be the default language to save and one index for each other translation. - * - * Since the user can be presented with non translatable fields in the - * translation form, the process has to give priority to the values of the - * current language over the default language. - * - * So, the process is: - * - If the current language is the default one, add all fields to the - * x-default index. - * - If the current language is not the default language, then the default - * - language will only provide the translatable fields as default and the - * non-translatable will be filled by the current language. - * - All the other languages, will only provide the translatable fields. - * - * Only t_literal fields should be translatable. - * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity to convert to an array of values. - * - * @return array - * The array of values including the translations. - */ - protected function toLangArray(ContentEntityInterface $entity): array { - $values = []; - $languages = array_keys(array_filter($entity->getTranslationLanguages(), function (LanguageInterface $language) { - return !$language->isLocked(); - })); - $translatable_fields = array_keys($entity->getTranslatableFields()); - $fields = array_keys($entity->getFields()); - $non_translatable_fields = array_diff($fields, $translatable_fields); - - $current_langcode = $entity->language()->getId(); - if ($entity->isDefaultTranslation()) { - foreach ($entity->getFields(FALSE) as $name => $field_item_list) { - if (!$field_item_list->isEmpty()) { - $values[$name][$current_langcode] = $field_item_list->getValue(); - } - } - $processed = [$entity->language()->getId()]; - } - else { - // Fill in the translatable fields of the default language and then all - // the fields from the current language. - $default_translation = $entity->getUntranslated(); - $default_langcode = $default_translation->language()->getId(); - foreach ($translatable_fields as $name) { - $values[$name][$default_langcode] = $default_translation->get($name)->getValue(); - } - // For the current language, add the translatable fields as a translation - // and the non translatable fields as default. - foreach ($non_translatable_fields as $name) { - $values[$name][$default_langcode] = $entity->get($name)->getValue(); - } - // The current language is not included in the translations if it is a - // new translation and is outdated if it is not a new translation. - // Thus, the handling occurs here, instead of the generic handling below. - foreach ($translatable_fields as $name) { - $values[$name][$current_langcode] = $entity->get($name)->getValue(); - } - - $processed = [$current_langcode, $default_langcode]; - } - - // For the rest of the languages not computed above, simply add the - // the translatable fields. This will prevent data loss from the database. - foreach (array_diff($languages, $processed) as $langcode) { - if (!$entity->hasTranslation($langcode)) { - continue; - } - $translation = $entity->getTranslation($langcode); - foreach ($translatable_fields as $name) { - $item_list = $translation->get($name); - if (!$item_list->isEmpty()) { - $values[$name][$langcode] = $item_list->getValue(); - } - } - } - return $values; - } - - /** - * Resolves the language based on entity and current site language. - * - * @param string $entity_type_id - * The entity type id. - * @param string $field_name - * The field name for which to resolve the language. - * @param string $langcode - * A default langcode or the fields detected langcode. - * - * @return string|null - * A language code or NULL, if the field has no language. - * - * @throws \Exception - * Thrown when a non existing field is requested. - */ - protected function resolveFieldLangcode($entity_type_id, $field_name, $langcode = NULL): ?string { - $format = $this->fieldHandler->getFieldFormat($entity_type_id, $field_name); - $non_languages = [ - LanguageInterface::LANGCODE_NOT_SPECIFIED, - LanguageInterface::LANGCODE_DEFAULT, - LanguageInterface::LANGCODE_NOT_APPLICABLE, - LanguageInterface::LANGCODE_SITE_DEFAULT, - LanguageInterface::LANGCODE_SYSTEM, - ]; - - if ($format == SparqlEntityStorageFieldHandlerInterface::TRANSLATABLE_LITERAL && !empty($langcode) && !in_array($langcode, $non_languages)) { - return $langcode; - } - - $langcode = $this->languageManager->getCurrentLanguage()->getId(); - if (in_array($langcode, $non_languages)) { - return NULL; - } - return $langcode; - } - - /** - * Alters the graph before saving the entity. - * - * Implementations are able to change, delete or add items to the graph before - * this is saved to SPARQL backend. - * - * @param \EasyRdf\Graph $graph - * The graph to be altered. - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity being saved. - */ - protected function alterGraph(Graph &$graph, EntityInterface $entity): void {} - - /** - * Insert a graph of triples. - * - * @param \EasyRdf\Graph $graph - * The graph to insert. - * @param string $graph_uri - * Graph to save to. - * - * @return \EasyRdf\Sparql\Result - * Response. - * - * @throws \Drupal\sparql_entity_storage\Exception\SparqlQueryException - * If the SPARQL query fails. - * @throws \Exception - * The query fails with no specific reason. - */ - protected function insert(Graph $graph, string $graph_uri): Result { - $graph_uri = SparqlArg::uri($graph_uri); - $query = "INSERT DATA INTO $graph_uri {\n"; - $query .= $graph->serialise('ntriples') . "\n"; - $query .= '}'; - return $this->sparql->update($query); - } - - /** - * {@inheritdoc} - */ - protected function has($id, EntityInterface $entity) { - return !$entity->isNew(); - } - - /** - * {@inheritdoc} - */ - public function countFieldData($storage_definition, $as_bool = FALSE) { - return $as_bool ? FALSE : 0; - } - - /** - * {@inheritdoc} - */ - public function hasData() { - return FALSE; - } - - /** - * Allow overrides for some field types. - * - * @param string $type - * The field type. - * @param array $values - * The field values. - * - * @todo: To be removed when columns will be supported. No need to manually - * set this. - */ - protected function applyFieldDefaults($type, array &$values): void { - if (empty($values)) { - return; - } - foreach ($values as &$value) { - // Textfield: provide default filter when filter not mapped. - switch ($type) { - case 'text_long': - if (!isset($value['format'])) { - $value['format'] = 'full_html'; - } - break; - - // Strip timezone part in dates. - // @todo Move in InboundOutboundValueSubscriber::massageInboundValue() - case 'datetime': - $time_stamp = (int) $value['value']; - // $time_stamp = strtotime($value['value']);. - $date = date('o-m-d', $time_stamp) . "T" . date('H:i:s', $time_stamp); - $value['value'] = $date; - break; - } - } - $this->moduleHandler->alter('sparql_apply_default_fields', $type, $values); - } - - /** - * {@inheritdoc} - */ - protected function getFromStaticCache(array $ids, array $graph_ids = []) { - $entities = []; - foreach ($ids as $id) { - // If there are more than one graphs in the request, return only the first - // one, if exists. If the first candidate doesn't exist in the static - // cache, we don't pickup the following because the first might be - // available later in the persistent cache or in the storage. - if (isset($this->entities[$id][$graph_ids[0]])) { - if (!isset($entities[$id])) { - $entities[$id] = $this->entities[$id][$graph_ids[0]]; - } - } - } - return $entities; - } - - /** - * {@inheritdoc} - */ - protected function setStaticCache(array $entities) { - if ($this->entityType->isStaticallyCacheable()) { - foreach ($entities as $id => $entity) { - $this->entities[$id][$entity->graph->target_id] = $entity; - } - } - } - - /** - * {@inheritdoc} - */ - protected function getFromPersistentCache(array &$ids = NULL, array $graph_ids = []) { - if (!$this->entityType->isPersistentlyCacheable() || empty($ids)) { - return []; - } - $entities = []; - // Build the list of cache entries to retrieve. - $cid_map = []; - foreach ($ids as $id) { - $graph_id = reset($graph_ids); - $cid_map[$id] = "{$this->buildCacheId($id)}:{$graph_id}"; - } - $cids = array_values($cid_map); - if ($cache = $this->cacheBackend->getMultiple($cids)) { - // Get the entities that were found in the cache. - foreach ($ids as $index => $id) { - $cid = $cid_map[$id]; - if (isset($cache[$cid]) && !isset($entities[$id])) { - $entities[$id] = $cache[$cid]->data; - unset($ids[$index]); - } - } - } - return $entities; - } - - /** - * {@inheritdoc} - */ - protected function setPersistentCache($entities) { - if (!$this->entityType->isPersistentlyCacheable()) { - return; - } - - $cache_tags = [ - $this->entityTypeId . '_values', - 'entity_field_info', - ]; - foreach ($entities as $id => $entity) { - $cid = "{$this->buildCacheId($id)}:{$entity->graph->target_id}"; - $this->cacheBackend->set($cid, $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags); - } - } - - /** - * {@inheritdoc} - */ - public function resetCache(array $ids = NULL, array $graph_ids = NULL): void { - if ($graph_ids && !$ids) { - throw new \InvalidArgumentException('Passing a value in $graphs_ids works only when used with non-null $ids.'); - } - - $this->checkGraphs($graph_ids, TRUE); - - if ($ids) { - $cids = []; - foreach ($ids as $id) { - foreach ($graph_ids as $graph) { - unset($this->entities[$id][$graph]); - $cids[] = "{$this->buildCacheId($id)}:{$graph}"; - } - } - if ($this->entityType->isPersistentlyCacheable()) { - $this->cacheBackend->deleteMultiple($cids); - } - } - else { - $this->entities = []; - if ($this->entityType->isPersistentlyCacheable()) { - Cache::invalidateTags([$this->entityTypeId . '_values']); - } - } - } - - /** - * {@inheritdoc} - */ - protected function buildCacheId($id) { - return "values:{$this->entityTypeId}:$id"; - } - - /** - * Delete an entity before it gets saved. - * - * The difference between deleteBeforeInsert and delete method is the - * properties_list variable. Filtering the fields to be deleted using this - * variable, ensures that additional data that might be imported through an - * external repository are not lost during an entity update. - * - * @param string $id - * The entity uri. - * @param string $graph_uri - * The graph uri. - * - * @throws \Drupal\sparql_entity_storage\Exception\SparqlQueryException - * If the SPARQL query fails. - * @throws \Exception - * The query fails with no specific reason. - */ - protected function deleteBeforeInsert(string $id, string $graph_uri): void { - $property_list = $this->fieldHandler->getPropertyListToArray($this->getEntityTypeId()); - $serialized = SparqlArg::serializeUris($property_list); - $id = SparqlArg::uri($id); - $graph_uri = SparqlArg::uri($graph_uri); - $query = <<sparql->query($query); - } - - /** - * {@inheritdoc} - */ - public function idExists(string $id, string $graph = NULL): bool { - $id = SparqlArg::uri($id); - $predicates = SparqlArg::serializeUris($this->bundlePredicate, ' '); - if ($graph) { - $graph = SparqlArg::uri($graph); - $query = "ASK WHERE { GRAPH $graph { $id ?type ?o . VALUES ?type { $predicates } } }"; - } - else { - $query = "ASK { $id ?type ?value . VALUES ?type { $predicates } }"; - } - - return $this->sparql->query($query)->isTrue(); - } - - /** - * Validates a list of graphs and provide defaults. - * - * @param string[]|null $graph_ids - * An ordered list of candidate graph IDs. - * @param bool $check_all_graphs - * (optional) If to check all graphs. By default, only the default graphs - * are checked. - * - * @throws \InvalidArgumentException - * If at least one of passed graphs doesn't exist for this entity type. - */ - protected function checkGraphs(array &$graph_ids = NULL, bool $check_all_graphs = FALSE): void { - if (!$graph_ids) { - if ($check_all_graphs) { - // No passed graph means "all graphs for this entity type". - $graph_ids = $this->getGraphHandler()->getEntityTypeGraphIds($this->getEntityTypeId()); - } - else { - // No passed graph means "all default graphs for this entity type". - $graph_ids = $this->getGraphHandler()->getEntityTypeDefaultGraphIds($this->getEntityTypeId()); - } - return; - } - - $entity_type_graph_ids = $this->getGraphHandler()->getEntityTypeGraphIds($this->getEntityTypeId()); - - // Validate each passed graph. - array_walk($graph_ids, function (string $graph_id) use ($entity_type_graph_ids): void { - if (!in_array($graph_id, $entity_type_graph_ids)) { - throw new \InvalidArgumentException("Graph '$graph_id' doesn't exist for entity type '{$this->getEntityTypeId()}'."); - } - }); - } - - /** - * Keep track of the originating graph of an entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - */ - protected function trackOriginalGraph(EntityInterface $entity): void { - // Store the graph ID of the loaded entity to be, eventually, used when this - // entity gets saved. During the saving process, this value is passed to - // SparqlEntityStorage::loadUnchanged() to correctly determine the - // original entity graph. This value persists in entity over an entity form - // submit, as the entity is stored in the form state, so that the entity - // save can rely on it. - // @see \Drupal\sparql_entity_storage\SparqlEntityStorage::doPreSave() - // @see \Drupal\Core\Entity\EntityForm - $entity->sparqlEntityOriginalGraph = $entity->get('graph')->target_id; - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginBase.php b/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginBase.php deleted file mode 100644 index 567b653f..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginBase.php +++ /dev/null @@ -1,79 +0,0 @@ -entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity_type.manager') - ); - } - - /** - * {@inheritdoc} - */ - public function setEntity(ContentEntityInterface $entity) { - $class = get_class($this->entityTypeManager->getStorage($entity->getEntityTypeId())); - if ($class != SparqlEntityStorage::class && !is_subclass_of($class, SparqlEntityStorage::class)) { - throw new \InvalidArgumentException("Passed entity must have a SPARQL storage."); - } - - $this->entity = $entity; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getEntity() { - return $this->entity; - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginInterface.php b/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginInterface.php deleted file mode 100644 index bcdf331b..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageEntityIdPluginInterface.php +++ /dev/null @@ -1,38 +0,0 @@ -alterInfo('sparql_entity_id_info'); - $this->setCacheBackend($cache_backend, 'sparql_entity_id_plugins'); - $this->entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public function getFallbackPluginId($plugin_id, array $configuration = []) { - return 'default'; - } - - /** - * Initializes the proper plugin given an entity. - * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity. - * - * @return \Drupal\sparql_entity_storage\SparqlEntityStorageEntityIdPluginInterface - * The plugin. - */ - public function getPlugin(ContentEntityInterface $entity) { - $entity_type_id = $entity->getEntityTypeId(); - $bundle_id = $entity->bundle(); - - if (!isset($this->instances[$entity_type_id][$bundle_id])) { - $options = ['plugin_id' => NULL]; - if ($mapping = SparqlMapping::loadByName($entity_type_id, $bundle_id)) { - if ($plugin_id = $mapping->getEntityIdPlugin()) { - $options['plugin_id'] = $plugin_id; - } - } - $this->instances[$entity_type_id][$bundle_id] = $this->getInstance($options); - } - - return $this->instances[$entity_type_id][$bundle_id]->setEntity($entity); - } - - /** - * {@inheritdoc} - */ - public function getInstance(array $options) { - $plugin_id = array_key_exists('plugin_id', $options) ? $options['plugin_id'] : NULL; - return $this->createInstance($plugin_id); - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageFieldHandler.php b/sparql_entity_storage/src/SparqlEntityStorageFieldHandler.php deleted file mode 100644 index d800e14d..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageFieldHandler.php +++ /dev/null @@ -1,543 +0,0 @@ -entityTypeManager = $entity_type_manager; - $this->entityFieldManager = $entity_field_manager; - $this->eventDispatcher = $event_dispatcher; - } - - /** - * Prepares the property mappings for the given entity type ID. - * - * This is the central point where the field maps SPARQL-to-Drupal (inbound) - * and Drupal-to-SPARQL (outbound) are build. The parsed results are - * statically cached. - * - * @param string $entity_type_id - * The entity type ID. - * - * @throws \Exception - * Thrown when a bundle does not have the mapped bundle. - */ - protected function buildEntityTypeProperties($entity_type_id) { - if (empty($this->outboundMap[$entity_type_id]) && empty($this->inboundMap[$entity_type_id])) { - $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); - - // @todo Support entity types without bundles or without bundle config - // entities, in #3. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/3 - $bundle_type = $entity_type->getBundleEntityType(); - - $bundle_storage = $this->entityTypeManager->getStorage($bundle_type); - $this->outboundMap[$entity_type_id] = $this->inboundMap[$entity_type_id] = []; - $this->outboundMap[$entity_type_id]['bundle_key'] = $this->inboundMap[$entity_type_id]['bundle_key'] = $entity_type->getKey('bundle'); - $bundle_entities = $this->entityTypeManager->getStorage($bundle_type)->loadMultiple(); - - foreach ($bundle_entities as $bundle_id => $bundle_entity) { - $field_definitions = $this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle_entity->id()); - $mapping = SparqlMapping::loadByName($entity_type_id, $bundle_entity->id()); - if (!$bundle_mapping = $mapping->getRdfType()) { - throw new \Exception("The {$bundle_entity->label()} SPARQL entity does not have an rdf_type set."); - } - $this->outboundMap[$entity_type_id]['bundles'][$bundle_id] = $bundle_mapping; - // More than one Drupal bundle can share the same mapped URI. - $this->inboundMap[$entity_type_id]['bundles'][$bundle_mapping][] = $bundle_id; - $base_fields_mapping = $mapping->getMappings(); - foreach ($field_definitions as $field_name => $field_definition) { - $field_storage_definition = $field_definition->getFieldStorageDefinition(); - - // @todo Unify field mappings in #3. - // @see https://github.com/ec-europa/sparql_entity_storage/issues/3 - if ($field_storage_definition instanceof BaseFieldDefinition) { - $field_mapping = $base_fields_mapping[$field_name] ?? NULL; - } - else { - $field_mapping = $field_storage_definition->getThirdPartySetting('sparql_entity_storage', 'mapping'); - } - - // This field is not mapped. - if (!$field_mapping) { - continue; - } - - $this->outboundMap[$entity_type_id]['fields'][$field_name]['main_property'] = $field_storage_definition->getMainPropertyName();; - foreach ($field_mapping as $column_name => $column_mapping) { - if (empty($column_mapping['predicate'])) { - continue; - } - - // Handle the serialized values. - $serialize = FALSE; - $field_storage_schema = $field_storage_definition->getSchema()['columns']; - // Inflate value back into a normal item. - if (!empty($field_storage_schema[$column_name]['serialize'])) { - $serialize = TRUE; - } - - // Retrieve the property definition primitive data type. - $property_definition = $field_storage_definition->getPropertyDefinition($column_name); - if (empty($property_definition)) { - throw new NonExistingFieldPropertyException("Field '$field_name' of type '{$field_storage_definition->getType()}' has no property '$column_name'."); - } - $data_type = $property_definition->getDataType(); - - $this->outboundMap[$entity_type_id]['fields'][$field_name]['columns'][$column_name][$bundle_id] = [ - 'predicate' => $column_mapping['predicate'], - 'format' => $column_mapping['format'], - 'serialize' => $serialize, - 'data_type' => $data_type, - ]; - - $this->inboundMap[$entity_type_id]['fields'][$column_mapping['predicate']][$bundle_id] = [ - 'field_name' => $field_name, - 'column' => $column_name, - 'serialize' => $serialize, - 'type' => $field_storage_definition->getType(), - 'data_type' => $data_type, - ]; - } - } - } - } - } - - /** - * {@inheritdoc} - */ - public function getInboundMap(string $entity_type_id): array { - if (!isset($this->inboundMap[$entity_type_id])) { - $this->buildEntityTypeProperties($entity_type_id); - } - return $this->inboundMap[$entity_type_id]; - } - - /** - * {@inheritdoc} - */ - public function getFieldPredicates(string $entity_type_id, string $field_name, ?string $column_name = NULL, ?string $bundle = NULL): array { - $drupal_to_sparql = $this->getOutboundMap($entity_type_id); - if (!isset($drupal_to_sparql['fields'][$field_name])) { - throw new UnmappedFieldException("You are requesting the mapping for a non mapped field: $field_name (entity type: $entity_type_id)."); - } - $field_mapping = $drupal_to_sparql['fields'][$field_name]; - $column_name = $column_name ?: $field_mapping['main_property']; - - $bundles = $bundle ? [$bundle] : array_keys($drupal_to_sparql['bundles']); - $return = []; - foreach ($bundles as $bundle) { - if (isset($field_mapping['columns'][$column_name][$bundle]['predicate'])) { - $return[$bundle] = $field_mapping['columns'][$column_name][$bundle]['predicate']; - } - } - return array_filter($return); - } - - /** - * {@inheritdoc} - */ - public function getFieldFormat(string $entity_type_id, string $field_name, ?string $column_name = NULL, ?string $bundle = NULL): array { - $drupal_to_sparql = $this->getOutboundMap($entity_type_id); - if (!isset($drupal_to_sparql['fields'][$field_name])) { - throw new \Exception("You are requesting the mapping for a non mapped field: $field_name."); - } - $field_mapping = $drupal_to_sparql['fields'][$field_name]; - $column_name = $column_name ?: $field_mapping['main_property']; - - if (!empty($bundle)) { - return [$field_mapping['columns'][$column_name][$bundle]['format']]; - } - - return array_values(array_column($field_mapping['columns'][$column_name], 'format')); - } - - /** - * {@inheritdoc} - */ - public function getFieldMainProperty(string $entity_type_id, string $field_name): string { - $outbound_data = $this->getOutboundMap($entity_type_id); - return $outbound_data['fields'][$field_name]['main_property']; - } - - /** - * {@inheritdoc} - */ - public function getPropertyListToArray(string $entity_type_id): array { - $inbound_map = $this->getInboundMap($entity_type_id); - return array_unique(array_keys($inbound_map['fields'])); - } - - /** - * {@inheritdoc} - */ - public function hasFieldPredicate(string $entity_type_id, string $bundle, string $field_name, string $column_name): bool { - $drupal_to_sparql = $this->getOutboundMap($entity_type_id); - return isset($drupal_to_sparql['fields'][$field_name]['columns'][$column_name][$bundle]); - } - - /** - * {@inheritdoc} - */ - public function bundlesToUris(string $entity_type_id, array $bundles, bool $to_resource_uris = FALSE): array { - if (SparqlArg::isValidResources($bundles)) { - return $bundles; - } - - foreach ($bundles as $index => $bundle) { - $value = $this->getOutboundBundleValue($entity_type_id, $bundle); - if (empty($value)) { - throw new \Exception("The $bundle bundle does not have a mapping."); - } - $bundles[$index] = $to_resource_uris ? SparqlArg::uri($value) : $value; - } - - return $bundles; - } - - /** - * {@inheritdoc} - */ - public function getOutboundValue(string $entity_type_id, string $field_name, $value, ?string $langcode = NULL, ?string $column_name = NULL, ?string $bundle = NULL) { - $outbound_map = $this->getOutboundMap($entity_type_id); - $format = $this->getFieldFormat($entity_type_id, $field_name, $column_name, $bundle); - $format = reset($format); - - $field_mapping_info = $this->getFieldInfoFromOutboundMap($entity_type_id, $field_name, $column_name, $bundle); - $field_mapping_info = reset($field_mapping_info); - - $event = new OutboundValueEvent($entity_type_id, $field_name, $value, $field_mapping_info, $langcode, $column_name, $bundle); - $this->eventDispatcher->dispatch(SparqlEntityStorageEvents::OUTBOUND_VALUE, $event); - $value = $event->getValue(); - - $serialize = $this->isFieldSerializable($entity_type_id, $field_name, $column_name); - if ($serialize) { - $value = serialize($value); - } - - if ($field_name == $outbound_map['bundle_key']) { - $value = $this->getOutboundBundleValue($entity_type_id, $value); - } - - switch ($format) { - case static::RESOURCE: - return [ - 'type' => substr($value, 0, 2) == '_:' ? 'bnode' : 'uri', - 'value' => $value, - ]; - - case static::NON_TYPE: - return new Literal($value); - - case static::TRANSLATABLE_LITERAL: - return Literal::create($value, $langcode); - - default: - return Literal::create($value, NULL, $format); - } - } - - /** - * {@inheritdoc} - */ - public function getInboundBundleValue(string $entity_type_id, string $bundle_uri): array { - $inbound_map = $this->getInboundMap($entity_type_id); - if (empty($inbound_map['bundles'][$bundle_uri])) { - throw new \Exception("A bundle mapped to <$bundle_uri> was not found."); - } - - return $inbound_map['bundles'][$bundle_uri]; - } - - /** - * {@inheritdoc} - */ - public function getInboundValue(string $entity_type_id, string $field_name, $value, ?string $langcode = NULL, ?string $column_name = NULL, ?string $bundle = NULL) { - // The outbound map contains the same information as the inbound map: the - // only difference is how the data is structured. It's safe to retrieve the - // field information from the outbound map. - // @see self::buildEntityTypeProperties() - $field_mapping_info = $this->getFieldInfoFromOutboundMap($entity_type_id, $field_name, $column_name, $bundle); - $field_mapping_info = reset($field_mapping_info); - - $event = new InboundValueEvent($entity_type_id, $field_name, $value, $field_mapping_info, $langcode, $column_name, $bundle); - $this->eventDispatcher->dispatch(SparqlEntityStorageEvents::INBOUND_VALUE, $event); - $value = $event->getValue(); - - if ($this->isFieldSerializable($entity_type_id, $field_name, $column_name)) { - $value = unserialize($value); - } - - return $value; - } - - /** - * {@inheritdoc} - */ - public static function getSupportedDataTypes(): array { - return [ - static::RESOURCE => t('Resource'), - static::TRANSLATABLE_LITERAL => t('Translatable literal'), - static::NON_TYPE => t('String (No type)'), - 'xsd:string' => t('Literal'), - 'xsd:boolean' => t('Boolean'), - 'xsd:date' => t('Date'), - 'xsd:dateTime' => t('Datetime'), - 'xsd:decimal' => t('Decimal'), - 'xsd:integer' => t('Integer'), - 'xsd:anyURI' => t('URI (xsd:anyURI)'), - ]; - } - - /** - * {@inheritdoc} - */ - public function fieldIsMapped(string $entity_type_id, string $field_name): bool { - $outbound_map = $this->getOutboundMap($entity_type_id); - return isset($outbound_map['fields'][$field_name]); - } - - /** - * {@inheritdoc} - */ - public function clearCache(): void { - unset($this->outboundMap); - unset($this->inboundMap); - } - - /** - * Returns the Drupal-to-SPARQL mapping array. - * - * @param string $entity_type_id - * The entity type id. - * - * @return array - * The drupal-to-sparql array. - */ - protected function getOutboundMap(string $entity_type_id): array { - if (!isset($this->outboundMap[$entity_type_id])) { - $this->buildEntityTypeProperties($entity_type_id); - } - return $this->outboundMap[$entity_type_id]; - } - - /** - * Returns whether the field is serializable. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $field_name - * The field name. - * @param string|null $column_name - * (optional) The column name. If omitted, the main property will be used. - * - * @return bool - * Whether the field is serializable. - * - * @throws \Exception - * Thrown when a non existing field is requested. - */ - protected function isFieldSerializable(string $entity_type_id, string $field_name, ?string $column_name = NULL): bool { - $drupal_to_sparql = $this->getOutboundMap($entity_type_id); - if (!isset($drupal_to_sparql['fields'][$field_name])) { - throw new \Exception("You are requesting the mapping for a non mapped field: $field_name."); - } - $field_mapping = $drupal_to_sparql['fields'][$field_name]; - $column_name = $column_name ?: $field_mapping['main_property']; - - $serialize_array = array_column($field_mapping['columns'][$column_name], 'serialize'); - if (empty($serialize_array)) { - return FALSE; - } - - $serialize = reset($serialize_array); - return $serialize; - } - - /** - * Returns the outbound bundle mapping. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle - * The bundle ID. - * - * @return string - * The bundle mapping. - * - * @throws \Exception - * Thrown when the bundle is not found. - */ - protected function getOutboundBundleValue(string $entity_type_id, string $bundle): string { - $outbound_map = $this->getOutboundMap($entity_type_id); - if (empty($outbound_map['bundles'][$bundle])) { - throw new \Exception("The $bundle bundle does not have a mapped id."); - } - - return $outbound_map['bundles'][$bundle]; - } - - /** - * Retrieves information about the mapping of a certain field. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $field_name - * The field name. - * @param string|null $column_name - * (optional) The column name. If omitted, the field main property is used. - * @param string|null $bundle - * (optional) If passed, filter the final array by bundle. - * - * @return array - * An associative array with the information about the field mappings. - * When no bundle is specified, an array of arrays is returned, where the - * first level keys are all the bundles with that field. - * - * @throws \Exception - * Thrown when the field is not found. - */ - protected function getFieldInfoFromOutboundMap(string $entity_type_id, string $field_name, ?string $column_name = NULL, ?string $bundle = NULL): array { - $mapping = $this->getOutboundMap($entity_type_id); - - if (!isset($mapping['fields'][$field_name])) { - throw new \Exception("You are requesting the mapping info for a non mapped field: $field_name."); - } - - $field_mapping = $mapping['fields'][$field_name]; - $column_name = $column_name ?: $field_mapping['main_property']; - - if (!empty($bundle)) { - return [$field_mapping['columns'][$column_name][$bundle]]; - } - - return array_values($field_mapping['columns'][$column_name]); - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageFieldHandlerInterface.php b/sparql_entity_storage/src/SparqlEntityStorageFieldHandlerInterface.php deleted file mode 100644 index 87c98f68..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageFieldHandlerInterface.php +++ /dev/null @@ -1,239 +0,0 @@ -'. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $field_name - * The field name. - * @param mixed $value - * The value to convert. - * @param string|null $langcode - * (optional) Pass the language code if one exists. This should be NULL if - * the format is not 't_literal'. - * @param string|null $column_name - * The column for which to calculate the value. If null, the field's main - * column will be used. - * @param string|null $bundle - * (optional) The same field of an entity type might use different value - * formats, depending on how is mapped on each bundle. Pass the bundle, when - * is available, for a better determination of the value format. - * - * @return mixed - * The calculated value. - */ - public function getOutboundValue(string $entity_type_id, string $field_name, $value, ?string $langcode = NULL, ?string $column_name = NULL, ?string $bundle = NULL); - - /** - * Returns the inbound bundle mapping. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle_uri - * The bundle URI. - * - * @return string[] - * An array of bundles that match the requested bundle. - * - * @throws \Exception - * Thrown when the bundle is not found. - */ - public function getInboundBundleValue(string $entity_type_id, string $bundle_uri): array; - - /** - * Returns the inbound value for the given field. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $field_name - * The field name. - * @param mixed $value - * The value to convert. - * @param string|null $langcode - * (optional) Pass the language code if one exists. This should be NULL if - * the format is not 't_literal'. - * @param string|null $column_name - * (optional) The column name for which to calculate the value. If omitted, - * the field main property will be used. - * @param string|null $bundle - * (optional) The same field of an entity type might use different value - * formats, depending on how is mapped on each bundle. Pass the bundle, when - * is available, for a better determination of the value format. - * - * @return mixed - * The calculated value. - */ - public function getInboundValue(string $entity_type_id, string $field_name, $value, ?string $langcode = NULL, ?string $column_name = NULL, ?string $bundle = NULL); - - /** - * Returns an array of available data types. - * - * @return \Drupal\Component\Render\MarkupInterface[] - * An array of data types. - */ - public static function getSupportedDataTypes(): array; - - /** - * Checks is a field is part of the map given an entity type. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $field_name - * The field name to be checked. - * - * @return bool - * If the field is mapped. - */ - public function fieldIsMapped(string $entity_type_id, string $field_name): bool; - - /** - * Clears the internal memory cache. - */ - public function clearCache(): void; - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageGraphHandler.php b/sparql_entity_storage/src/SparqlEntityStorageGraphHandler.php deleted file mode 100644 index 3efe4045..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageGraphHandler.php +++ /dev/null @@ -1,229 +0,0 @@ -entityTypeManager = $entity_type_manager; - $this->eventDispatcher = $event_dispatcher; - } - - /** - * {@inheritdoc} - */ - public function getGraphDefinitions(string $entity_type_id): array { - if (!isset($this->cache['definition'][$entity_type_id])) { - $query = $this->getSparqlGraphStorage()->getQuery(); - $ids = $query->condition($query->orConditionGroup() - ->condition('entity_types.*', [$entity_type_id], 'IN') - // A NULL value means "all entity types". - ->notExists('entity_types') - )->condition('status', TRUE) - // A determined order is a key feature. - ->sort('weight', 'ASC') - ->execute(); - - if (!$ids) { - // Do not cache an empty set, it may occur because this runs before any - // configuration has been imported, so the entities are not yet in. - return []; - } - - $graphs = $this->getSparqlGraphStorage()->loadMultiple($ids); - - $this->cache['definition'][$entity_type_id] = array_map(function (SparqlGraphInterface $graph): array { - return [ - 'title' => $graph->label(), - 'description' => $graph->getDescription(), - ]; - }, $graphs); - } - return $this->cache['definition'][$entity_type_id]; - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeGraphIds(string $entity_type_id, array $limit_to_graph_ids = NULL): array { - $graph_ids = array_keys($this->getGraphDefinitions($entity_type_id)); - if ($limit_to_graph_ids) { - $graph_ids = array_intersect($graph_ids, $limit_to_graph_ids); - } - return $graph_ids; - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeDefaultGraphIds(string $entity_type_id): array { - if (!isset($this->cache['default_graphs'][$entity_type_id])) { - $entity_graph_ids = $this->getEntityTypeGraphIds($entity_type_id); - /** @var \Drupal\sparql_entity_storage\Event\DefaultGraphsEvent $event */ - $event = $this->eventDispatcher->dispatch( - SparqlEntityStorageEvents::DEFAULT_GRAPHS, - new DefaultGraphsEvent($entity_type_id, $entity_graph_ids) - ); - // Do not allow 3rd party code to add invalid or disabled graphs. - $default_graph_ids = array_intersect($event->getDefaultGraphIds(), $entity_graph_ids); - - $this->cache['default_graphs'][$entity_type_id] = $default_graph_ids; - } - return $this->cache['default_graphs'][$entity_type_id]; - } - - /** - * {@inheritdoc} - */ - public function getDefaultGraphId(string $entity_type_id): string { - $graph_ids = $this->getEntityTypeGraphIds($entity_type_id); - return reset($graph_ids); - } - - /** - * {@inheritdoc} - */ - public function getBundleGraphUri(string $entity_type_id, string $bundle, string $graph_id): ?string { - $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); - $bundle_key = ($entity_type->hasKey('bundle') && $entity_type->getBundleEntityType()) ? $bundle : $entity_type_id; - return $this->getEntityTypeGraphUris($entity_type_id)[$bundle_key][$graph_id] ?? NULL; - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeGraphUris(string $entity_type_id, array $limit_to_graph_ids = NULL): array { - if (!isset($this->cache['structure'][$entity_type_id])) { - $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); - if ($entity_type->hasKey('bundle') && ($bundle_entity_id = $entity_type->getBundleEntityType())) { - $bundle_keys = array_values($this->entityTypeManager->getStorage($bundle_entity_id)->getQuery()->execute()); - } - else { - $bundle_keys = [$entity_type_id]; - } - - foreach ($bundle_keys as $bundle_key) { - $graphs = ($mapping = SparqlMapping::loadByName($entity_type_id, $bundle_key)) ? $mapping->getGraphs() : []; - $this->cache['structure'][$entity_type_id][$bundle_key] = $graphs; - } - } - - // Limit the results. - if ($limit_to_graph_ids) { - return array_map(function (array $graphs) use ($limit_to_graph_ids): array { - return array_intersect_key($graphs, array_flip($limit_to_graph_ids)); - }, $this->cache['structure'][$entity_type_id]); - } - - return $this->cache['structure'][$entity_type_id]; - } - - /** - * {@inheritdoc} - */ - public function bundleHasGraph(string $entity_type_id, string $bundle, string $graph_id): bool { - $entity_type_graphs = $this->getEntityTypeGraphUris($entity_type_id); - return !empty($entity_type_graphs[$bundle][$graph_id]); - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeGraphUrisFlatList(string $entity_type_id, array $limit_to_graph_ids = NULL): array { - $graphs = $this->getEntityTypeGraphUris($entity_type_id, $limit_to_graph_ids); - return array_reduce($graphs, function (array $uris, array $bundle_graphs): array { - return array_merge($uris, array_values($bundle_graphs)); - }, []); - } - - /** - * {@inheritdoc} - */ - public function getBundleGraphId(string $entity_type_id, string $bundle, string $graph_uri): ?string { - $graphs = $this->getEntityTypeGraphUris($entity_type_id); - $search = array_search($graph_uri, $graphs[$bundle]); - return $search !== FALSE ? $search : NULL; - } - - /** - * {@inheritdoc} - */ - public function clearCache(array $path = NULL): void { - if (empty($path)) { - $this->cache = static::EMPTY_CACHE; - return; - } - NestedArray::unsetValue($this->cache, $path); - - // If the path was a top-level cache category, restore its "empty version". - if (count($path) === 1 && array_key_exists($path[0], static::EMPTY_CACHE)) { - $this->cache[$path[0]] = static::EMPTY_CACHE[$path[0]]; - } - } - - /** - * Returns the SPARQL graph config entity storage service. - * - * @return \Drupal\Core\Config\Entity\ConfigEntityStorageInterface - * The SPARQL graph config entity storage service. - * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * If the entity type is not found. - */ - protected function getSparqlGraphStorage(): ConfigEntityStorageInterface { - if (!isset($this->sparqlGraphStorage)) { - $this->sparqlGraphStorage = $this->entityTypeManager->getStorage('sparql_graph'); - } - return $this->sparqlGraphStorage; - } - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageGraphHandlerInterface.php b/sparql_entity_storage/src/SparqlEntityStorageGraphHandlerInterface.php deleted file mode 100644 index 22ec23ad..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageGraphHandlerInterface.php +++ /dev/null @@ -1,203 +0,0 @@ - [], - 'default_graphs' => [], - 'structure' => [], - ]; - - /** - * Get the defined graph types for this entity type. - * - * A default graph is provided here already because there has to exist at - * least one available graph for the entities to be saved in. - * - * @param string $entity_type_id - * The entity type ID. - * - * @return array - * A structured array of graph definitions containing a title and a - * description. The array keys are the machine names of the graphs. - */ - public function getGraphDefinitions(string $entity_type_id): array; - - /** - * Returns a list of SPARQL graph IDs given a entity type ID. - * - * This is similar to ::getGraphDefinitions() but it returns only the SPARQL - * graph IDs as an indexed array. Additionally, the list can be limited - * to a given set of IDs by passing the second argument. - * - * @param string $entity_type_id - * The entity type ID. - * @param string[]|null $limit_to_graph_ids - * (optional) A list of SPARQL graph IDs to restrict the results. If omitted - * all the SPARQL graph IDs supported by the given entity type will be - * returned. - * - * @return array - * A list of SPARQL graph IDs. - */ - public function getEntityTypeGraphIds(string $entity_type_id, array $limit_to_graph_ids = NULL): array; - - /** - * Returns a list of default graph IDs. - * - * When requesting an entity, callers are passing a list of candidate graph - * IDs. If the list is missed, the value returned by this method is used. This - * is not necessary the list of all enabled graphs. Third party modules might - * restrict this list. For instance, if graphs 'default', 'foo', 'bar' are - * enabled, a call such as: - * @codingStandardsIgnoreStart - * SparqlEntityStorage::load('http://example.com', ['bar']); - * @codingStandardsIgnoreEnd - * will return the entity from the 'bar' graph (if exists). A module might - * decide to set the default graphs list to 'default', 'foo'. A call such as: - * @codingStandardsIgnoreStart - * SparqlEntityStorage::load('http://example.com'); - * @codingStandardsIgnoreEnd - * will search the entity first in 'default' and will fallback to 'foo'. If - * the entity doesn't exist in 'default' or 'foo', will return NULL because - * 'bar' graph is not in the list of default graph IDs. - * - * By default, all enabled graphs are returned. Third party code which intends - * to alter this list should subscribe to the - * SparqlEntityStorageEvents::DEFAULT_GRAPHS event and use the - * \Drupal\sparql_entity_storage\Event\DefaultGraphsEvent event setter to set - * its own preferences. - * - * @param string $entity_type_id - * The entity type ID. - * - * @return array - * A list of default graph IDs. - * - * @see \Drupal\sparql_entity_storage\SparqlEntityStorage::load() - * @see \Drupal\sparql_entity_storage\SparqlEntityStorage::loadMultiple() - * @see \Drupal\sparql_entity_storage\SparqlEntityStorage::loadUnchanged() - * @see \Drupal\sparql_entity_storage\SparqlEntityStorage::loadByProperties() - * @see \Drupal\sparql_entity_storage\Entity\Query\Sparql\SparqlQueryInterface::graphs() - * @see \Drupal\sparql_entity_storage\Event\SparqlEntityStorageEvents::DEFAULT_GRAPHS - * @see \Drupal\sparql_entity_storage\Event\DefaultGraphsEvent - */ - public function getEntityTypeDefaultGraphIds(string $entity_type_id): array; - - /** - * Gets the default graph ID for an entity type. - * - * The default graph is the topmost graph entity when sorting all enabled - * graphs by weight ascending for a given entity type. - * - * @param string $entity_type_id - * The entity type ID. - * - * @return string - * The default graph ID. - */ - public function getDefaultGraphId(string $entity_type_id): string; - - /** - * Returns the graph URI given an entity type ID, a bundle and the graph ID. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle - * The entity bundle. - * @param string $graph_id - * The graph ID. - * - * @return string|null - * The URI of the requested graph. - */ - public function getBundleGraphUri(string $entity_type_id, string $bundle, string $graph_id): ?string; - - /** - * Returns the graph URIs for a given entity type. - * - * The list could be restricted to match only the passed graph IDs. - * - * @param string $entity_type_id - * The entity type to be checked. - * @param string[]|null $limit_to_graph_ids - * (optional) A list of graph IDs to limit the results. NULL means that all - * graphs are allowed. Defaults to NULL. - * - * @return string[] - * A list of graph URIs. - */ - public function getEntityTypeGraphUris(string $entity_type_id, array $limit_to_graph_ids = NULL): array; - - /** - * Checks is a graph is available for a given bundle. - * - * @param string $entity_type_id - * The entity type of the bundle. - * @param string $bundle - * The bundle to be checked. - * @param string $graph_id - * The graph to be checked. - * - * @return bool - * If the graph is available for the specific bundle. - */ - public function bundleHasGraph(string $entity_type_id, string $bundle, string $graph_id): bool; - - /** - * Returns a plain, flat list of graph URIs related to the passed entity type. - * - * @param string $entity_type_id - * The ID of the entity type. - * @param array $limit_to_graph_ids - * Optionally filter the graphs to be returned. - * - * @return array - * A flat list of graph URIs. - */ - public function getEntityTypeGraphUrisFlatList(string $entity_type_id, array $limit_to_graph_ids = NULL): array; - - /** - * Returns the graph ID for a given graph URI. - * - * This is basically a reverse search to get the ID of the graph for a given - * entity type and bundle. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle - * The bundle. - * @param string $graph_uri - * The URI of the graph. - * - * @return string|null - * The ID of the graph or NULL. - */ - public function getBundleGraphId(string $entity_type_id, string $bundle, string $graph_uri): ?string; - - /** - * Clear the internal cache. - * - * @param string[]|null $path - * (optional) The path to a specific cache entry to be cleared. This - * parameter allows to clear only a specific cache entry. Defaults to NULL. - * - * @see \Drupal\Component\Utility\NestedArray::unsetValue() - */ - public function clearCache(array $path = NULL): void; - -} diff --git a/sparql_entity_storage/src/SparqlEntityStorageInterface.php b/sparql_entity_storage/src/SparqlEntityStorageInterface.php deleted file mode 100644 index 10774f1c..00000000 --- a/sparql_entity_storage/src/SparqlEntityStorageInterface.php +++ /dev/null @@ -1,165 +0,0 @@ -id() === SparqlGraphInterface::DEFAULT) { - return AccessResult::forbidden()->addCacheableDependency($sparql_graph); - } - return parent::checkAccess($sparql_graph, $operation, $account)->addCacheableDependency($sparql_graph); - - default: - return parent::checkAccess($sparql_graph, $operation, $account); - - } - } - -} diff --git a/sparql_entity_storage/src/SparqlGraphInterface.php b/sparql_entity_storage/src/SparqlGraphInterface.php deleted file mode 100644 index 11879507..00000000 --- a/sparql_entity_storage/src/SparqlGraphInterface.php +++ /dev/null @@ -1,99 +0,0 @@ - $this->t('Name'), - 'description' => [ - 'data' => $this->t('Description'), - 'class' => [RESPONSIVE_PRIORITY_MEDIUM], - ], - 'entity_types' => $this->t('Entity types'), - ] + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $sparql_graph) { - /** @var \Drupal\sparql_entity_storage\SparqlGraphInterface $sparql_graph */ - $row['label'] = $sparql_graph->label(); - $row['description'] = ['#markup' => $sparql_graph->getDescription()]; - - if ($entity_types = $sparql_graph->getEntityTypeIds()) { - $labels = implode(', ', array_intersect_key(\Drupal::service('entity_type.repository') - ->getEntityTypeLabels(), array_flip($entity_types))); - } - else { - $labels = $this->t('All SPARQL storage entity types'); - } - $row['entity_types'] = ['#markup' => $labels]; - - return $row + parent::buildRow($sparql_graph); - } - - /** - * {@inheritdoc} - */ - public function getDefaultOperations(EntityInterface $entity) { - $operations = parent::getDefaultOperations($entity); - - /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */ - $access_manager = \Drupal::service('access_manager'); - foreach (['enable', 'disable'] as $operation) { - if (isset($operations[$operation])) { - $route_name = "entity.{$this->entityTypeId}.$operation"; - $parameters = [$this->entityTypeId => $entity->id()]; - if (!$access_manager->checkNamedRoute($route_name, $parameters)) { - unset($operations[$operation]); - } - } - } - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - $form = parent::buildForm($form, $form_state); - $form[$this->entitiesKey]['#caption'] = $this->t('Reorder graphs to establish the graphs priority.'); - return $form; - } - -} diff --git a/sparql_entity_storage/src/SparqlGraphStoreTrait.php b/sparql_entity_storage/src/SparqlGraphStoreTrait.php deleted file mode 100644 index e15749df..00000000 --- a/sparql_entity_storage/src/SparqlGraphStoreTrait.php +++ /dev/null @@ -1,29 +0,0 @@ -getConnectionOptions(); - $connect_string = "http://{$connection_options['host']}:{$connection_options['port']}/sparql-graph-crud"; - // Use a local SPARQL 1.1 Graph Store. - return new GraphStore($connect_string); - } - -} diff --git a/sparql_entity_storage/src/SparqlMappingInterface.php b/sparql_entity_storage/src/SparqlMappingInterface.php deleted file mode 100644 index 0e27aa93..00000000 --- a/sparql_entity_storage/src/SparqlMappingInterface.php +++ /dev/null @@ -1,248 +0,0 @@ - [ - * 'column1' => [ - * 'predicate' => 'http://example.com', - * 'format' => 't_literal', - * ], - * 'column2' => [ - * 'predicate' => 'http://example.com/other', - * 'format' => 'xsd:dateTime', - * ], - * ], - * 'field2' => [ - * ... - * ], - * ] - * @endcode - * - The first level are field names, - * - The second level are field columns, such as 'value', 'target_id'. - * - The values are arrays with two keys: 'predicate', 'format'. - * - * @return $this - */ - public function addMappings(array $mappings): self; - - /** - * Sets the list of base fields mappings. - * - * Unlike ::addMappings(), this method replaces the whole list of existing - * mappings. - * - * @param array $mappings - * A structured associative array with the same structure as the parameter - * from ::addMappings(). - * - * @return $this - * - * @throws \InvalidArgumentException - * If the passed list of graphs doesn't contain the 'default' graph. - * - * @see self::addMappings() - */ - public function setMappings(array $mappings): self; - - /** - * Returns all base fields mappings. - * - * @return array - * All base fields mappings. - */ - public function getMappings(): array; - - /** - * Returns the mapping for a specific base field and column. - * - * @param string $field_name - * The field name. - * @param string $column_name - * (optional) The column name. Defaults to 'value'. - * - * @return array|null - * Associative array with two keys: 'predicate' and 'format'. - */ - public function getMapping(string $field_name, string $column_name = 'value'): ?array; - - /** - * Un-sets the mappings for a given list of fields. - * - * @param string[] $field_names - * A list of field names. - * - * @return $this - */ - public function unsetMappings(array $field_names): self; - - /** - * Loads a sparql_mapping entity given the entity type ID and the bundle. - * - * @param string $entity_type_id - * The entity type ID. - * @param string $bundle - * The bundle. - * - * @return static|null - * The sparql_mapping entity of NULL on failure. - */ - public static function loadByName(string $entity_type_id, string $bundle): ?self; - -} diff --git a/sparql_entity_storage/src/SparqlSerializer.php b/sparql_entity_storage/src/SparqlSerializer.php deleted file mode 100644 index ee79227d..00000000 --- a/sparql_entity_storage/src/SparqlSerializer.php +++ /dev/null @@ -1,77 +0,0 @@ -sparqlEndpoint = $sparqlEndpoint; - $this->graphHandler = $graph_handler; - } - - /** - * {@inheritdoc} - */ - public function serializeEntity(ContentEntityInterface $entity, string $format = 'turtle'): string { - $graph_uri = $this->graphHandler->getBundleGraphUri($entity->getEntityTypeId(), $entity->bundle(), $entity->graph->target_id); - $entity_id = $entity->id(); - - $query = << { - ?s ?p ?o . - VALUES ?s { <{$entity_id}> } . - } - } - UNION { - GRAPH <{$graph_uri}> { - ?s ?p ?o . - VALUES ?o { <{$entity_id}> } . - } - } -} -ORDER BY ?s, ?p, ?o -Query; - - $graph = new Graph($entity->id()); - $results = $this->sparqlEndpoint->query($query); - foreach ($results as $result) { - $graph->add($result->s, $result->p, $result->o); - } - return $graph->serialise($format); - } - -} diff --git a/sparql_entity_storage/src/SparqlSerializerInterface.php b/sparql_entity_storage/src/SparqlSerializerInterface.php deleted file mode 100644 index b99edfd0..00000000 --- a/sparql_entity_storage/src/SparqlSerializerInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - '_b', - '.' => '_c', - '~' => '_d', - ':' => '_e', - '/' => '_f', - '?' => '_g', - '#' => '_h', - '[' => '_i', - ']' => '_j', - '@' => '_k', - '!' => '_l', - '$' => '_m', - '&' => '_n', - '\'' => '_o', - '(' => '_p', - ')' => '_q', - '*' => '_r', - '+' => '_s', - ',' => '_t', - ';' => '_u', - '=' => '_v', - '`' => '_w', - '%' => '_x', - ]; - } - -} diff --git a/sparql_entity_storage/templates/Collector/sparql.html.twig b/sparql_entity_storage/templates/Collector/sparql.html.twig deleted file mode 100644 index eb19cb31..00000000 --- a/sparql_entity_storage/templates/Collector/sparql.html.twig +++ /dev/null @@ -1,158 +0,0 @@ -{% block toolbar %} - {% set icon %} - - {{ 'Sparql'|t }} - {{ collector.querycount }} - {% if collector.querycount > 0 %} - in {{ '%0.2f ms'|format(collector.time) }} - {% endif %} - - {% endset %} - {% set text %} -
- {{ 'Sparql Queries'|t }} - {{ collector.querycount }} -
-
- {{ 'Query time'|t }} - {{ '%0.2f ms'|format(collector.time) }} -
-
- {{ 'Connection'|t }} - {{ collector.database.driver }}://{{ collector.database.host }}:{{ collector.database.port }} - /{{ collector.database.database }} -
- {% endset %} - -
-
{{ icon|default('') }}
-
{{ text|default('') }}
-
-{% endblock %} - -{% block panel %} - - -{% endblock %} diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/jsonld b/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/jsonld deleted file mode 100644 index 3505f3d2..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/jsonld +++ /dev/null @@ -1 +0,0 @@ -[{"@id":"http://example.com/apple","http://example.com/fruit/label":[{"@value":"Apple","@language":"en"}],"http://example.com/fruit/uid":[{"@value":0}],"@type":["http://example.com/type/fruit"]},{"@id":"http://example.com/type/fruit"}] diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/n3 b/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/n3 deleted file mode 100644 index bb78740a..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/n3 +++ /dev/null @@ -1,6 +0,0 @@ -@prefix ns0: . - - - ns0:label "Apple"@en ; - ns0:uid 0 ; - a . diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/ntriples b/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/ntriples deleted file mode 100644 index 025ade57..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/ntriples +++ /dev/null @@ -1,3 +0,0 @@ - "Apple"@en . - "0"^^ . - . diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/rdfxml b/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/rdfxml deleted file mode 100644 index b119d44b..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/rdfxml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Apple - 0 - - - - diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/turtle b/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/turtle deleted file mode 100644 index bb78740a..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/rdf_entity/turtle +++ /dev/null @@ -1,6 +0,0 @@ -@prefix ns0: . - - - ns0:label "Apple"@en ; - ns0:uid 0 ; - a . diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/jsonld b/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/jsonld deleted file mode 100644 index 4b6dd5a6..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/jsonld +++ /dev/null @@ -1 +0,0 @@ -[{"@id":"http://example.com/citrus-fruits","@type":["http://www.w3.org/2004/02/skos/core#Concept"],"http://www.w3.org/2004/02/skos/core#inScheme":[{"@id":"http://example.com/fruit-type"}],"http://www.w3.org/2004/02/skos/core#prefLabel":[{"@value":"Citrus fruits","@language":"en"}]},{"@id":"http://example.com/fruit-type"},{"@id":"http://www.w3.org/2004/02/skos/core#Concept"}] diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/n3 b/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/n3 deleted file mode 100644 index ab081810..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/n3 +++ /dev/null @@ -1,6 +0,0 @@ -@prefix skos: . - - - a skos:Concept ; - skos:inScheme ; - skos:prefLabel "Citrus fruits"@en . diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/ntriples b/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/ntriples deleted file mode 100644 index 66df6e15..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/ntriples +++ /dev/null @@ -1,3 +0,0 @@ - . - . - "Citrus fruits"@en . diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/rdfxml b/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/rdfxml deleted file mode 100644 index 41f667fe..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/rdfxml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - Citrus fruits - - - diff --git a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/turtle b/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/turtle deleted file mode 100644 index ab081810..00000000 --- a/sparql_entity_storage/tests/fixtures/content-negotiation/taxonomy_term/turtle +++ /dev/null @@ -1,6 +0,0 @@ -@prefix skos: . - - - a skos:Concept ; - skos:inScheme ; - skos:prefLabel "Citrus fruits"@en . diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.fruit.reference.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.fruit.reference.yml deleted file mode 100644 index 3e8122db..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.fruit.reference.yml +++ /dev/null @@ -1,26 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.reference - - sparql_test.type.fruit -id: sparql_test.fruit.reference -field_name: reference -entity_type: sparql_test -bundle: fruit -label: Reference -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: - handler: 'default:sparql_test' - handler_settings: - target_bundles: - fruit: fruit - sort: - field: _none - auto_create: false - auto_create_bundle: null -field_type: entity_reference diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.date.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.date.yml deleted file mode 100644 index 88ac95a9..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.date.yml +++ /dev/null @@ -1,20 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.date - - sparql_test.type.vegetable - module: - - datetime -id: sparql_test.vegetable.date -field_name: date -entity_type: sparql_test -bundle: vegetable -label: Date -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: { } -field_type: datetime diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.reference.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.reference.yml deleted file mode 100644 index c6582347..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.reference.yml +++ /dev/null @@ -1,26 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.reference - - sparql_test.type.vegetable -id: sparql_test.vegetable.reference -field_name: reference -entity_type: sparql_test -bundle: vegetable -label: Reference -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: - handler: 'default:sparql_test' - handler_settings: - target_bundles: - fruit: fruit - sort: - field: _none - auto_create: false - auto_create_bundle: null -field_type: entity_reference diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text.yml deleted file mode 100644 index 61d062c0..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text.yml +++ /dev/null @@ -1,18 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.text - - sparql_test.type.vegetable -id: sparql_test.vegetable.text -field_name: text -entity_type: sparql_test -bundle: vegetable -label: Text -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: { } -field_type: string_long diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text_multi.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text_multi.yml deleted file mode 100644 index 2c2329f6..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.field.sparql_test.vegetable.text_multi.yml +++ /dev/null @@ -1,18 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.text_multi - - sparql_test.type.vegetable -id: sparql_test.vegetable.text_multi -field_name: text_multi -entity_type: sparql_test -bundle: vegetable -label: 'Text Multi' -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: { } -field_type: string_long diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.date.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.date.yml deleted file mode 100644 index e5fa4a76..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.date.yml +++ /dev/null @@ -1,25 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - datetime - - sparql_test -third_party_settings: - sparql_entity_storage: - mapping: - value: - predicate: 'http://example.com/date' - format: 'xsd:dateTime' -id: sparql_test.date -field_name: date -entity_type: sparql_test -type: datetime -settings: - datetime_type: datetime -module: datetime -locked: false -cardinality: 1 -translatable: false -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.reference.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.reference.yml deleted file mode 100644 index fb4357af..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.reference.yml +++ /dev/null @@ -1,24 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - sparql_test -third_party_settings: - sparql_entity_storage: - mapping: - target_id: - predicate: 'http://purl.org/dc/terms/relation' - format: resource -id: sparql_test.reference -field_name: reference -entity_type: sparql_test -type: entity_reference -settings: - target_type: sparql_test -module: core -locked: false -cardinality: -1 -translatable: false -indexes: { } -persist_with_no_fields: false -#custom_storage: false diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.text_multi.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.text_multi.yml deleted file mode 100644 index 04af67bf..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/field.storage.sparql_test.text_multi.yml +++ /dev/null @@ -1,24 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - sparql_test -third_party_settings: - sparql_entity_storage: - mapping: - value: - predicate: 'http://example.com/text_multi' - format: 'literal' -id: sparql_test.text_multi -field_name: text_multi -entity_type: sparql_test -type: string_long -settings: - case_sensitive: false -module: core -locked: false -cardinality: -1 -translatable: false -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_entity_storage.mapping.sparql_test.vegetable.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_entity_storage.mapping.sparql_test.vegetable.yml deleted file mode 100644 index 1595f8f4..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_entity_storage.mapping.sparql_test.vegetable.yml +++ /dev/null @@ -1,35 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - sparql_entity_storage.graph.default - - sparql_test.type.vegetable -third_party_settings: { } -id: sparql_test.vegetable -entity_type_id: sparql_test -bundle: vegetable -rdf_type: 'http://example.com/vegetable' -base_fields_mapping: - type: - target_id: - predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' - format: resource - title: - value: - predicate: 'http://example.com/vegetable/name' - format: t_literal - created: - value: - predicate: 'http://purl.org/dc/terms/issued' - format: 'xsd:dateTime' - changed: - value: - predicate: 'http://example.com/modified' - format: 'xsd:integer' - langcode: - value: - predicate: 'http://example.com/language' - format: t_literal -graph: - default: 'http://example.com/vegetable/graph/published' -entity_id_plugin: default \ No newline at end of file diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_test.type.vegetable.yml b/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_test.type.vegetable.yml deleted file mode 100644 index 12d2a85f..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/config/install/sparql_test.type.vegetable.yml +++ /dev/null @@ -1,6 +0,0 @@ -langcode: en -status: true -dependencies: { } -third_party_settings: { } -name: Vegetable -id: vegetable diff --git a/sparql_entity_storage/tests/modules/sparql_field_test/sparql_field_test.info.yml b/sparql_entity_storage/tests/modules/sparql_field_test/sparql_field_test.info.yml deleted file mode 100644 index 534093e3..00000000 --- a/sparql_entity_storage/tests/modules/sparql_field_test/sparql_field_test.info.yml +++ /dev/null @@ -1,8 +0,0 @@ -type: module -core: 8.x -name: 'SPARQL field test' -description: 'Testing module for SPARQL entity fields.' -package: Testing -dependencies: -- datetime -- sparql_test:sparql_test diff --git a/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.info.yml b/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.info.yml deleted file mode 100644 index c975161b..00000000 --- a/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.info.yml +++ /dev/null @@ -1,7 +0,0 @@ -type: module -core: 8.x -name: 'SPARQL graph test' -description: 'Testing module for SPARQL graphs.' -package: Testing -dependencies: - - 'sparql_entity_storage:sparql_entity_storage' diff --git a/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.services.yml b/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.services.yml deleted file mode 100644 index 27d645b5..00000000 --- a/sparql_entity_storage/tests/modules/sparql_graph_test/sparql_graph_test.services.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - sparql_graph_test.subscriber: - class: Drupal\sparql_graph_test\DefaultGraphsSubscriber - tags: - - name: event_subscriber diff --git a/sparql_entity_storage/tests/modules/sparql_graph_test/src/DefaultGraphsSubscriber.php b/sparql_entity_storage/tests/modules/sparql_graph_test/src/DefaultGraphsSubscriber.php deleted file mode 100644 index 562c8a8e..00000000 --- a/sparql_entity_storage/tests/modules/sparql_graph_test/src/DefaultGraphsSubscriber.php +++ /dev/null @@ -1,43 +0,0 @@ - 'limitGraphs', - ]; - } - - /** - * Reacts to default graph list building event. - * - * @param \Drupal\sparql_entity_storage\Event\DefaultGraphsEvent $event - * The event. - */ - public function limitGraphs(DefaultGraphsEvent $event) { - $graphs = $event->getDefaultGraphIds(); - if (($index = array_search('non_default_graph', $graphs)) !== FALSE) { - // Remove 'non_default_graph' graph. - unset($graphs[$index]); - } - // Add a disabled graph. - $graphs[] = 'disabled_graph'; - // Add an non-existing graph. - $graphs[] = 'non_existing_graph'; - - $event->setDefaultGraphIds($graphs); - } - -} diff --git a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.field.sparql_test.fruit.link.yml b/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.field.sparql_test.fruit.link.yml deleted file mode 100644 index 732d6a57..00000000 --- a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.field.sparql_test.fruit.link.yml +++ /dev/null @@ -1,22 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.link - - sparql_test.type.fruit - module: - - link -id: sparql_test.fruit.link -field_name: link -entity_type: sparql_test -bundle: fruit -label: Link -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: - link_type: 17 - title: 1 -field_type: link diff --git a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.storage.sparql_test.link.yml b/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.storage.sparql_test.link.yml deleted file mode 100644 index 82b94f96..00000000 --- a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/config/install/field.storage.sparql_test.link.yml +++ /dev/null @@ -1,30 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - link - - sparql_test -third_party_settings: - sparql_entity_storage: - mapping: - uri: - predicate: 'http://example.com/link/uri' - format: 'xsd:anyURI' - title: - predicate: 'http://example.com/link/title' - format: t_literal - options: - predicate: '' - format: no_format -id: sparql_test.link -field_name: link -entity_type: sparql_test -type: link -settings: { } -module: link -locked: false -cardinality: 1 -translatable: true -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/sparql_multi_column_field_test.info.yml b/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/sparql_multi_column_field_test.info.yml deleted file mode 100644 index 8f36938a..00000000 --- a/sparql_entity_storage/tests/modules/sparql_multi_column_field_test/sparql_multi_column_field_test.info.yml +++ /dev/null @@ -1,7 +0,0 @@ -type: module -core: 8.x -name: 'SPARQL multi-column field test' -description: 'Testing module for SPARQL multi-column field test.' -package: Testing -dependencies: -- 'sparql_test:sparql_test' diff --git a/sparql_entity_storage/tests/modules/sparql_test/config/install/field.field.sparql_test.fruit.text.yml b/sparql_entity_storage/tests/modules/sparql_test/config/install/field.field.sparql_test.fruit.text.yml deleted file mode 100644 index efa8da83..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/config/install/field.field.sparql_test.fruit.text.yml +++ /dev/null @@ -1,18 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.sparql_test.text - - sparql_test.type.fruit -id: sparql_test.fruit.text -field_name: text -entity_type: sparql_test -bundle: fruit -label: Text -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: { } -field_type: string_long diff --git a/sparql_entity_storage/tests/modules/sparql_test/config/install/field.storage.sparql_test.text.yml b/sparql_entity_storage/tests/modules/sparql_test/config/install/field.storage.sparql_test.text.yml deleted file mode 100644 index 3337138b..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/config/install/field.storage.sparql_test.text.yml +++ /dev/null @@ -1,28 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - sparql_test - - text -third_party_settings: - sparql_entity_storage: - mapping: - value: - predicate: 'http://purl.org/dc/terms/description' - format: t_literal - format: - predicate: 'http://purl.org/dc/terms/description/format' - format: t_literal -id: sparql_test.text -field_name: text -entity_type: sparql_test -type: text_long -settings: - case_sensitive: false -module: core -locked: false -cardinality: 1 -translatable: false -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_entity_storage.mapping.sparql_test.fruit.yml b/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_entity_storage.mapping.sparql_test.fruit.yml deleted file mode 100644 index c1a090d3..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_entity_storage.mapping.sparql_test.fruit.yml +++ /dev/null @@ -1,35 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - sparql_entity_storage.graph.default - - sparql_test.type.fruit -third_party_settings: { } -id: sparql_test.fruit -entity_type_id: sparql_test -bundle: fruit -rdf_type: 'http://example.com/fruit/type' -base_fields_mapping: - type: - target_id: - predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' - format: resource - title: - value: - predicate: 'http://example.com/fruit/name' - format: t_literal - created: - value: - predicate: 'http://purl.org/dc/terms/issued' - format: 'xsd:dateTime' - changed: - value: - predicate: 'http://example.com/modified' - format: 'xsd:integer' - langcode: - value: - predicate: 'http://example.com/language' - format: t_literal -graph: - default: 'http://example.com/fruit/graph/default' -entity_id_plugin: default diff --git a/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_test.type.fruit.yml b/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_test.type.fruit.yml deleted file mode 100644 index a190155e..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/config/install/sparql_test.type.fruit.yml +++ /dev/null @@ -1,6 +0,0 @@ -langcode: en -status: true -dependencies: { } -third_party_settings: { } -name: Fruit -id: fruit diff --git a/sparql_entity_storage/tests/modules/sparql_test/config/schema/sparql_test.schema.yml b/sparql_entity_storage/tests/modules/sparql_test/config/schema/sparql_test.schema.yml deleted file mode 100644 index 41f98858..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/config/schema/sparql_test.schema.yml +++ /dev/null @@ -1,7 +0,0 @@ -sparql_test.type.*: - type: config_entity - mapping: - id: - type: string - name: - type: label diff --git a/sparql_entity_storage/tests/modules/sparql_test/sparql_test.info.yml b/sparql_entity_storage/tests/modules/sparql_test/sparql_test.info.yml deleted file mode 100644 index aafdea33..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/sparql_test.info.yml +++ /dev/null @@ -1,7 +0,0 @@ -type: module -core: 8.x -name: 'SPARQL Test' -description: 'Support module for testing sparql_entity_storage_test module.' -package: Testing -dependencies: -- 'sparql_entity_storage:sparql_entity_storage' diff --git a/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTest.php b/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTest.php deleted file mode 100644 index d25d5c5b..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTest.php +++ /dev/null @@ -1,73 +0,0 @@ -setLabel(t('ID')); - - $fields['title'] = BaseFieldDefinition::create('string') - ->setLabel(t('Title')) - ->setTranslatable(TRUE) - ->setRequired(TRUE); - - $fields['created'] = BaseFieldDefinition::create('created') - ->setLabel(t('Authored on')); - - $fields['changed'] = BaseFieldDefinition::create('changed') - ->setLabel(t('Changed')); - - return $fields; - } - -} diff --git a/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTypeTest.php b/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTypeTest.php deleted file mode 100644 index 7a906658..00000000 --- a/sparql_entity_storage/tests/modules/sparql_test/src/Entity/SparqlTypeTest.php +++ /dev/null @@ -1,43 +0,0 @@ -expectException(get_class($expected_exception)); - $this->expectExceptionMessage($expected_exception->getMessage()); - } - - Database::startLog('log_test', 'sparql_default'); - $this->sparql->{$method}($query, $args); - $log = $this->sparql->getLogger()->get('log_test'); - - $this->assertCount(1, $log); - - $log_entry = reset($log); - $this->assertEquals($query, $log_entry['query']); - $this->assertSame($args, $log_entry['args']); - $this->assertEquals('default', $log_entry['target']); - $this->assertEquals('double', gettype($log_entry['time'])); - $this->assertGreaterThan(0, $log_entry['time']); - // @todo Inspect also $log_entry['caller'] when - // https://www.drupal.org/project/drupal/issues/2867788 lands. - // @see https://www.drupal.org/project/drupal/issues/2867788 - } - - /** - * Data provider for ::testLog(). - * - * @return array - * Test cases. - * - * @see DatabaseLogTest::testLog() - */ - public function provider(): array { - return [ - 'query' => [ - 'query', - 'SELECT DISTINCT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 100', - [], - NULL, - ], - 'update' => [ - 'update', - 'CLEAR GRAPH ;', - [], - NULL, - ], - 'query with arguments' => [ - 'query', - 'SELECT DISTINCT ?s ?p ?o WHERE { <:subject> ?p ?o } LIMIT 100', - [':subject' => 'http://example.com'], - new \InvalidArgumentException('Replacement arguments are not yet supported.'), - ], - ]; - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/DateTimeFieldsTest.php b/sparql_entity_storage/tests/src/Kernel/DateTimeFieldsTest.php deleted file mode 100644 index 23d8d9aa..00000000 --- a/sparql_entity_storage/tests/src/Kernel/DateTimeFieldsTest.php +++ /dev/null @@ -1,103 +0,0 @@ - 'fruit', - 'id' => 'http://example.com', - 'label' => $this->randomMachineName(), - 'created' => $created_unix, - 'changed' => $changed_unix, - ]); - $entity->save(); - - $loaded = $this->container->get('entity_type.manager')->getStorage('sparql_test')->loadUnchanged($entity->id()); - - $this->assertTripleDataType($loaded->id(), 'http://purl.org/dc/terms/issued', 'http://www.w3.org/2001/XMLSchema#dateTime'); - $this->assertTripleDataType($loaded->id(), 'http://example.com/modified', 'http://www.w3.org/2001/XMLSchema#integer'); - - // Verify that the retrieved values are presented as timestamp. - $this->assertEquals($created_unix, $loaded->get('created')->value); - $this->assertEquals($changed_unix, $loaded->get('changed')->value); - - // Assert that timestamp properties mapped as integer are stored as such. - $this->assertTripleValue($loaded->id(), 'http://example.com/modified', $changed_unix); - // Assert the stored value of timestamps mapped as xsd:dateTime. - $this->assertTripleValue($loaded->id(), 'http://purl.org/dc/terms/issued', $created_iso); - } - - /** - * Asserts the data type of a triple. - * - * @param string $subject - * The triple subject. - * @param string $predicate - * The triple predicate. - * @param string $object_data_type - * The expected triple object data type. - */ - protected function assertTripleDataType($subject, $predicate, $object_data_type) { - $subject = SparqlArg::uri($subject); - $predicate = SparqlArg::uri($predicate); - $object_data_type = SparqlArg::uri($object_data_type); - - $query = <<assertTrue($this->sparql->query($query)->getBoolean(), "Incorrect data type '$object_data_type' for predicate '$predicate'."); - } - - /** - * Asserts the stored value of a triple. - * - * @param string $subject - * The triple subject. - * @param string $predicate - * The triple predicate. - * @param string $expected_value - * The expected triple value. - */ - protected function assertTripleValue($subject, $predicate, $expected_value) { - $subject = SparqlArg::uri($subject); - $predicate = SparqlArg::uri($predicate); - - $query = <<sparql->query($query); - $this->assertCount(1, $result, 'Expected a single result, but got ' . $result->count()); - $this->assertEquals($expected_value, (string) $result[0]->object); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/EncodingTest.php b/sparql_entity_storage/tests/src/Kernel/EncodingTest.php deleted file mode 100644 index b859c7a4..00000000 --- a/sparql_entity_storage/tests/src/Kernel/EncodingTest.php +++ /dev/null @@ -1,85 +0,0 @@ -markTestSkipped('Library minimaxir/big-list-of-naughty-strings is required.'); - return; - } - } - $json = file_get_contents($path); - $naughty_strings = json_decode($json); - foreach ($naughty_strings as $naughty_string) { - // Ignore the empty string test, as the field won't be set. - if ($naughty_string === "") { - continue; - } - $rdf = SparqlTest::create([ - 'type' => 'fruit', - 'title' => 'Berry', - 'text' => $naughty_string, - ]); - try { - $rdf->save(); - } - catch (\Exception $e) { - fwrite(STDOUT, $e->getMessage() . "\n"); - fwrite(STDOUT, $e->getTraceAsString() . "\n"); - $msg = sprintf("Entity saved for naughty string '%s'.", $naughty_string); - $this->assertTrue(FALSE, $msg); - } - - $query = \Drupal::entityQuery('sparql_test') - ->condition('title', 'Berry') - ->condition('type', 'fruit') - ->range(0, 1); - - $result = $query->execute(); - $msg = sprintf("Loaded naughty object '%s'.", $naughty_string); - $this->assertFalse(empty($result), $msg); - - $loaded_rdf = NULL; - try { - $loaded_rdf = SparqlTest::load(reset($result)); - } - catch (\Exception $e) { - fwrite(STDOUT, $e->getMessage() . "\n"); - fwrite(STDOUT, $e->getTraceAsString() . "\n"); - $msg = sprintf("Entity loaded for naughty string '%s'.", $naughty_string); - $this->assertTrue(FALSE, $msg); - } - - $field = $loaded_rdf->get('text'); - $msg = sprintf("Field was empty for naughty string '%s'.", $naughty_string); - $this->assertTrue($field, $msg); - $first = $field->first(); - $msg = sprintf("First value set for naughty string '%s'.", $naughty_string); - $this->assertTrue($first, $msg); - $text = $first->getValue(); - - $msg = sprintf("Naughty string '%s' was correctly read back.", $naughty_string); - $this->assertEquals($text['value'], $naughty_string, $msg); - $rdf->delete(); - } - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/EntityCreationTest.php b/sparql_entity_storage/tests/src/Kernel/EntityCreationTest.php deleted file mode 100644 index 61a64942..00000000 --- a/sparql_entity_storage/tests/src/Kernel/EntityCreationTest.php +++ /dev/null @@ -1,52 +0,0 @@ - 'fruit', - 'id' => 'http://example.com/apple', - 'title' => 'Apple', - ])->save(); - - // Check that on saving an existing entity no exception is thrown. - SparqlTest::load('http://example.com/apple')->save(); - - // Check that new rdf_entity, with its own ID, don't raise any exception. - SparqlTest::create([ - 'type' => 'fruit', - 'id' => 'http://example.com/berry', - 'title' => 'Fruit with a different ID', - ])->save(); - - // Check that the expected exception is throw when trying to create a new - // entity with the same ID. - $this->setExpectedException(DuplicatedIdException::class, "Attempting to create a new entity with the ID 'http://example.com/apple' already taken."); - SparqlTest::create([ - 'type' => 'fruit', - 'id' => 'http://example.com/apple', - 'title' => "This fruit tries to steal the Apple's ID", - ])->save(); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/EntityLanguageTest.php b/sparql_entity_storage/tests/src/Kernel/EntityLanguageTest.php deleted file mode 100644 index 51b7394b..00000000 --- a/sparql_entity_storage/tests/src/Kernel/EntityLanguageTest.php +++ /dev/null @@ -1,80 +0,0 @@ -save(); - } - - /** @var \Drupal\sparql_test\Entity\SparqlTest $entity */ - $entity = SparqlTest::create([ - 'id' => 'http://example.com/apple', - 'type' => 'fruit', - 'title' => 'Apple', - 'text' => 'some text', - ]); - - foreach ($langcodes as $langcode) { - $entity->addTranslation($langcode, [ - 'title' => "$langcode translation", - ] + $entity->toArray()); - } - $entity->save(); - - $entity = SparqlTest::load('http://example.com/apple'); - foreach ($langcodes as $langcode) { - $translation = $entity->getTranslation($langcode); - $this->assertEquals("$langcode translation", $translation->label()); - // The field_text field is non-translatable. - $this->assertEquals('some text', $translation->text->value); - } - - // For a single translation, update the text field. - $translation = $entity->getTranslation('el'); - $translation->set('text', 'Τυχαιο κειμενο'); - $translation->save(); - - $entity = SparqlTest::load('http://example.com/apple'); - - // Make sure we are using the default language. - $untranslated = $entity->getUntranslated(); - $this->assertNotEquals('el', $untranslated->language()->getId()); - - // Test that the untranslatable field affected all translations. - $this->assertEquals('Τυχαιο κειμενο', $untranslated->text->value); - - $entity->removeTranslation('el'); - $entity->save(); - - $entity = SparqlTest::load('http://example.com/apple'); - - // The value for the non-translatable field should persist. - $this->assertEquals('Τυχαιο κειμενο', $entity->text->value); - - // Verify that the translation is deleted. - $this->setExpectedException('\InvalidArgumentException', "Invalid translation language (el) specified."); - $entity->getTranslation('el'); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/MultiColumnFieldTest.php b/sparql_entity_storage/tests/src/Kernel/MultiColumnFieldTest.php deleted file mode 100644 index c39a615c..00000000 --- a/sparql_entity_storage/tests/src/Kernel/MultiColumnFieldTest.php +++ /dev/null @@ -1,54 +0,0 @@ -installConfig(['sparql_multi_column_field_test']); - } - - /** - * Tests the link field. - */ - public function testLinkField(): void { - SparqlTest::create([ - 'type' => 'fruit', - 'id' => 'http://example.com/apple', - 'label' => $this->randomString(), - 'link' => [ - 'uri' => 'http://example.com', - 'title' => 'My link title', - ], - ])->save(); - - // Ensures that saving a link field with 2 columns mapped will save and load - // both columns in the same delta as expected. - $entity = SparqlTest::load('http://example.com/apple'); - $this->assertEquals('http://example.com', $entity->get('link')->uri); - $this->assertEquals('My link title', $entity->get('link')->title); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/SparqlEntityInsertTest.php b/sparql_entity_storage/tests/src/Kernel/SparqlEntityInsertTest.php deleted file mode 100644 index ae51410a..00000000 --- a/sparql_entity_storage/tests/src/Kernel/SparqlEntityInsertTest.php +++ /dev/null @@ -1,155 +0,0 @@ -installConfig(['sparql_field_test']); - } - - /** - * Test entity create. - * - * @dataProvider providerTestEntityInsertCallback - */ - public function testEntityInsert($values): void { - // Create 10 referable entities. - for ($i = 0; $i < 10; $i++) { - $entity = SparqlTest::create([ - 'title' => $this->randomString(), - 'type' => 'vegetable', - 'text' => $this->randomString(), - ]); - $entity->save(); - $entities[$i] = $entity; - } - - $referable_entities = array_rand($entities, 4); - $reference_array = []; - foreach ($referable_entities as $index) { - $reference_array[] = $entities[$index]->id(); - } - - $values += [ - 'title' => $this->randomMachineName(), - 'type' => 'vegetable', - 'reference' => $reference_array, - 'date' => \Drupal::time()->getRequestTime(), - ]; - - $entity = SparqlTest::create($values); - $entity->save(); - - // Reload the entity. - $loaded_entity = SparqlTest::load($entity->id()); - foreach (static::FIELDS as $field_name) { - $this->assertEquals($this->getEntityValue($entity, $field_name), $this->getEntityValue($loaded_entity, $field_name)); - } - } - - /** - * Data provider for testEntityInsert(). - * - * @return array[] - * Test cases. - */ - public static function providerTestEntityInsertCallback(): array { - $random = new Random(); - return [ - [ - [ - 'text' => $random->string(), - 'text_multi' => [ - $random->string(3000), - $random->string(3000), - ], - ], - ], - [ - [ - 'text' => $random->string(3000), - 'text_multi' => [ - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - $random->string(3000), - ], - ], - ], - // Empty values to test that values are not saved. - [[]], - ]; - } - - /** - * Returns the value of a field name of an array. - * - * Since SPARQL does not support deltas yet, this method will sort the values - * so that they can be comparable. - * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity object. - * @param string $field_name - * The field name. - * - * @return mixed - * The retrieved value or NULL if no value exists. - * - * @todo: Remove this when the deltas are supported. - * @todo: Discuss whether we need this in the storage level. - */ - protected function getEntityValue(ContentEntityInterface $entity, string $field_name) { - $value = $entity->get($field_name)->getValue(); - if (empty($value)) { - return $value; - } - return asort($value); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/SparqlEntityQueryTest.php b/sparql_entity_storage/tests/src/Kernel/SparqlEntityQueryTest.php deleted file mode 100644 index 3b805747..00000000 --- a/sparql_entity_storage/tests/src/Kernel/SparqlEntityQueryTest.php +++ /dev/null @@ -1,544 +0,0 @@ -installConfig(['sparql_field_test']); - - // Create 10 referable entities. - $prefix = "http://fruit.example.com/"; - for ($i = 0; $i < 10; $i++) { - $id = sprintf("%s%03d", $prefix, $i + 1); - $entity = SparqlTest::create([ - 'id' => $id, - 'title' => 'fruit title ' . ($i + 1), - 'type' => 'fruit', - 'text' => 'text field ' . ($i % 2), - ]); - $entity->save(); - $this->entities[$i] = $entity; - } - - $prefix = "http://vegetable.example.com/"; - foreach ($this->getTestEntityValues() as $i => $values) { - $id = sprintf("%s%03d", $prefix, $i + 1); - $values += [ - 'id' => $id, - 'type' => 'vegetable', - ]; - SparqlTest::create($values)->save(); - } - } - - /** - * Tests basic functionality related to Id and bundle filtering. - */ - public function testIdBundleFilters() { - // Checks the '=' operator for IDs for a valid ID and a valid bundle. - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/001') - ->condition('type', 'vegetable') - ->execute(); - $this->assertResult('http://vegetable.example.com/001'); - - // Checks the '=' operator for IDs for a valid ID and a different bundle. - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/001') - ->condition('type', 'fruit') - ->execute(); - $this->assertResult(); - - // Checks the '!=' operator for the bundle. - $this->results = $this->getQuery() - ->condition('id', [ - 'http://vegetable.example.com/001', - 'http://fruit.example.com/002', - ], 'IN') - ->condition('type', 'vegetable', '!=') - ->execute(); - $this->assertResult('http://fruit.example.com/002'); - - // Checks the IN operator for the bundle. - $this->results = $this->getQuery() - ->condition('id', [ - 'http://fruit.example.com/002', - 'http://vegetable.example.com/001', - ], 'IN') - ->condition('type', ['fruit', 'vegetable'], 'IN') - ->sort('id') - ->execute(); - $this->assertResult('http://fruit.example.com/002', 'http://vegetable.example.com/001'); - - // Checks the NOT IN operator for the bundle. - $this->results = $this->getQuery() - ->condition('id', [ - 'http://vegetable.example.com/001', - 'http://fruit.example.com/002', - ], 'IN') - ->condition('type', ['vegetable'], 'NOT IN') - ->execute(); - $this->assertResult('http://fruit.example.com/002'); - - // Checks the 'IN' operator for IDs. - $this->results = $this->getQuery() - ->condition('id', [ - 'http://vegetable.example.com/000', - 'http://vegetable.example.com/001', - 'http://vegetable.example.com/002', - ], 'IN') - ->condition('type', 'vegetable') - ->execute(); - $this->assertResult('http://vegetable.example.com/001', 'http://vegetable.example.com/002'); - - // Checks the '=' operator for IDs for an invalid ID. - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/000') - ->condition('type', 'vegetable') - ->execute(); - $this->assertResult(); - - // Checks the '!=' operator for IDs for a valid ID. - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/001', '!=') - ->condition('type', 'vegetable') - ->execute(); - $this->assertResult('http://vegetable.example.com/002', 'http://vegetable.example.com/003', 'http://vegetable.example.com/004', 'http://vegetable.example.com/005', 'http://vegetable.example.com/006', 'http://vegetable.example.com/007', 'http://vegetable.example.com/008', 'http://vegetable.example.com/009', 'http://vegetable.example.com/010'); - - // Checks the 'NOT IN' operator for IDs for a valid ID. - $this->results = $this->getQuery() - ->condition('id', [ - 'http://vegetable.example.com/002', - 'http://vegetable.example.com/003', - 'http://vegetable.example.com/004', - 'http://vegetable.example.com/005', - 'http://vegetable.example.com/006', - 'http://vegetable.example.com/007', - 'http://vegetable.example.com/008', - 'http://vegetable.example.com/009', - 'http://vegetable.example.com/010', - ], 'NOT IN') - ->condition('type', 'vegetable') - ->execute(); - $this->assertResult('http://vegetable.example.com/001'); - - // Try to fetch a NULL ID. - $this->setExpectedException('Exception', 'The value cannot be NULL for conditions related to the Id and bundle keys.'); - $this->results = $this->getQuery() - ->condition('id', NULL) - ->condition('type', 'vegetable') - ->execute(); - - // Try to filter ID with an invalid operator. - $this->setExpectedException('Exception', "Only '=', '!=', '<>', 'IN', 'NOT IN' operators are allowed for the Id and bundle keys."); - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/003', 'LIKE') - ->condition('type', 'vegetable') - ->execute(); - - // Try to fetch a NULL bundle. - $this->setExpectedException('Exception', 'The value cannot be NULL for conditions related to the Id and bundle keys.'); - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/002') - ->condition('type', NULL) - ->execute(); - - // Try to filter bundle with an invalid operator. - $this->setExpectedException('Exception', "Only '=', '!=', '<>', 'IN', 'NOT IN' operators are allowed for the Id and bundle keys."); - $this->results = $this->getQuery() - ->condition('id', 'http://vegetable.example.com/003') - ->condition('type', 'multi', 'STARTS WITH') - ->execute(); - } - - /** - * Tests basic functionality. - * - * The queries here are very simple only to ensure proper functionality of the - * basic conditions. - */ - public function testBaseEntityQueryFilters() { - // Submit an empty query. - $this->results = $this->getQuery() - ->sort('id') - ->execute(); - $this->assertCount(20, $this->results); - - // Submit an empty 'OR' query. - $this->results = $this->getQuery('OR') - ->sort('id') - ->execute(); - $this->assertCount(20, $this->results); - - $this->results = $this->getQuery() - ->exists('field_text') - ->condition("text.format", 'plain_text') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/001'); - - $this->results = $this->getQuery() - ->exists("text.format") - ->condition('text', '', 'LIKE') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - $this->results = $this->getQuery() - ->condition('text', '

', 'CONTAINS') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - $this->results = $this->getQuery() - ->condition('text', '', 'STARTS WITH') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - $this->results = $this->getQuery() - ->condition('text', '', 'ENDS WITH') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - $this->results = $this->getQuery() - ->condition('text', '', 'ENDS WITH') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - $this->results = $this->getQuery() - ->condition('reference', $this->entities[6]->id()) - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/004', 'http://vegetable.example.com/010'); - - $this->results = $this->getQuery() - ->exists('text.format') - ->notExists('date') - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/002'); - - // OR conjunctions. - $this->results = $this->getQuery('OR') - ->exists('text.format') - ->condition('reference', $this->entities[6]->id()) - ->sort('id') - ->execute(); - $this->assertResult('http://vegetable.example.com/001', 'http://vegetable.example.com/002', 'http://vegetable.example.com/004', 'http://vegetable.example.com/010'); - } - - /** - * Tests more complex functionality. - */ - public function testNestedConditionGroups() { - $query = $this->getQuery('OR'); - - // Entity 001 should match. - $condition = $query->andConditionGroup(); - $condition->exists('text.format'); - $condition->condition('text.value', 'test', 'CONTAINS'); - $condition->condition('text.format', ['plain_text', 'filtered_html'], 'IN'); - $query->condition($condition); - - // Entity 002 should match. - $condition = $query->orConditionGroup(); - $condition->condition('text', 'condition('text.value', '/html>', 'ENDS WITH'); - - // Entity 006 should match. - $subcondition = $query->andConditionGroup(); - $subcondition->condition('text_multi', 'test text multi 1'); - $subcondition->condition('text_multi', 'sample string 2', 'CONTAINS'); - $condition->condition($subcondition); - - // Entity 004 should match. - $subcondition = $query->andConditionGroup(); - $subcondition->condition('reference', $this->entities[4]->id()); - $subcondition->notExists('date'); - $condition->condition($subcondition); - $query->condition($condition); - - $this->results = $query->sort('id')->execute(); - $this->assertResult('http://vegetable.example.com/001', 'http://vegetable.example.com/002', 'http://vegetable.example.com/004', 'http://vegetable.example.com/006'); - } - - /** - * Tests operators '<', '>', '<=', '>=' for Ids. - * - * @dataProvider idStringComparisonDataProvider - */ - public function testIdStringComparison($value, $operator, $expected_results) { - $query = $this->getQuery(); - $query->condition('id', $value, $operator); - $this->results = $query->sort('id')->execute(); - $this->assertResult($expected_results); - } - - /** - * Data provider for testIdStringComparison test. - */ - public function idStringComparisonDataProvider() { - return [ - [ - 'http://fruit.example.com/002', - '<', - ['http://fruit.example.com/001'], - ], - [ - 'http://fruit.example.com/002', - '<=', - ['http://fruit.example.com/001', 'http://fruit.example.com/002'], - ], - [ - 'http://fruit.example.com/009', - '>', - // The vegetable bundle entities have an id starting with 'http://m' - // which is sorted after the 'http://d' so all entities of the - // vegetable bundled are also returned for the '>' and '>=' operators. - [ - 'http://fruit.example.com/010', - 'http://vegetable.example.com/001', - 'http://vegetable.example.com/002', - 'http://vegetable.example.com/003', - 'http://vegetable.example.com/004', - 'http://vegetable.example.com/005', - 'http://vegetable.example.com/006', - 'http://vegetable.example.com/007', - 'http://vegetable.example.com/008', - 'http://vegetable.example.com/009', - 'http://vegetable.example.com/010', - ], - ], - [ - 'http://fruit.example.com/009', - '>=', - [ - 'http://fruit.example.com/009', - 'http://fruit.example.com/010', - 'http://vegetable.example.com/001', - 'http://vegetable.example.com/002', - 'http://vegetable.example.com/003', - 'http://vegetable.example.com/004', - 'http://vegetable.example.com/005', - 'http://vegetable.example.com/006', - 'http://vegetable.example.com/007', - 'http://vegetable.example.com/008', - 'http://vegetable.example.com/009', - 'http://vegetable.example.com/010', - ], - ], - ]; - } - - /** - * Asserts that arrays are identical. - */ - protected function assertResult() { - $assert = []; - $expected = func_get_args(); - if ($expected && is_array($expected[0])) { - $expected = $expected[0]; - } - foreach ($expected as $binary) { - $assert[$binary] = strval($binary); - } - $this->assertSame($assert, $this->results); - } - - /** - * Provides entity values for the test's setup. - * - * @return array - * An array of entity values. - */ - protected function getTestEntityValues() { - $time = \Drupal::time()->getRequestTime(); - $return = []; - // Entity 001. - $return[] = [ - 'text' => [ - 'value' => 'test text 1', - 'format' => 'plain_text', - ], - 'text_multi' => [ - 'test text multi 1', - ], - 'date' => $time, - 'reference' => [ - $this->entities[4]->id(), - ], - ]; - - // Entity 002. - $return[] = [ - 'text' => [ - 'value' => '

Hello world!

', - 'format' => 'full_html', - ], - 'text_multi' => [ - 'test text multi 1', - ], - ]; - - // Entity 003. - $return[] = [ - 'text' => 'test text 1', - 'text_multi' => [ - 'test text multi 2', - ], - 'date' => $time, - 'reference' => [ - $this->entities[2]->id(), - $this->entities[3]->id(), - $this->entities[4]->id(), - ], - ]; - - // Entity 004. - $return[] = [ - 'reference' => [ - $this->entities[0]->id(), - $this->entities[1]->id(), - $this->entities[2]->id(), - $this->entities[3]->id(), - $this->entities[4]->id(), - $this->entities[5]->id(), - $this->entities[6]->id(), - $this->entities[7]->id(), - $this->entities[8]->id(), - $this->entities[9]->id(), - ], - ]; - - // Entity 005. - $return[] = [ - 'text' => 'sample string 2', - 'text_multi' => [ - 'test text multi 1', - 'test text multi 3', - 'test text multi 2', - ], - ]; - - // Entity 006. - $return[] = [ - 'text' => 'sample string 1', - 'text_multi' => [ - 'test text multi 1', - 'sample string 2', - ], - 'reference' => [ - $this->entities[8]->id(), - $this->entities[9]->id(), - ], - ]; - - // Entity 007. - $return[] = [ - 'text' => 'test text 1', - 'text_multi' => [ - 'test text multi 1', - ], - 'date' => $time, - 'reference' => [ - $this->entities[5]->id(), - ], - ]; - - // Entity 008. - $return[] = [ - 'text' => 'test text 1', - 'text_multi' => [ - 'test text multi 1', - ], - 'date' => $time, - 'reference' => [ - $this->entities[8]->id(), - ], - ]; - - // Entity 009. - $return[] = [ - 'text' => 'test text 1', - 'text_multi' => [ - 'test text multi 1', - ], - 'date' => $time, - 'reference' => [ - $this->entities[1]->id(), - ], - ]; - - // Entity 010. - $return[] = [ - 'text' => 'test text 1', - 'text_multi' => [ - 'test text multi 1', - ], - 'date' => $time, - 'reference' => [ - $this->entities[6]->id(), - ], - ]; - - return $return; - } - - /** - * Returns the SPARQL entity query. - * - * @param string $operator - * (optional) The logic operator ('AND' or 'OR'). Defaults to 'AND'. - * - * @return \Drupal\sparql_entity_storage\Entity\Query\Sparql\SparqlQueryInterface - * The SPARQL entity query. - */ - protected function getQuery(string $operator = 'AND'): SparqlQueryInterface { - return $this->container->get('entity_type.manager') - ->getStorage('sparql_test') - ->getQuery($operator); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/SparqlGraphTest.php b/sparql_entity_storage/tests/src/Kernel/SparqlGraphTest.php deleted file mode 100644 index b0fd26e0..00000000 --- a/sparql_entity_storage/tests/src/Kernel/SparqlGraphTest.php +++ /dev/null @@ -1,168 +0,0 @@ -container->get('entity_type.manager'); - /** @var \Drupal\sparql_entity_storage\SparqlEntityStorage $storage */ - $storage = $manager->getStorage('sparql_test'); - - // Create a 2nd graph. - $this->createGraph('foo', 10); - - $id = 'http://example.com/apple'; - /** @var \Drupal\sparql_test\Entity\SparqlTest $apple */ - $apple = $storage->create([ - 'id' => $id, - 'type' => 'fruit', - 'title' => 'Apple in foo graph', - 'graph' => 'foo', - ]); - $apple->save(); - - // Check that, by default, the entity exists only in the foo graph. - $apple = $storage->load($id); - $this->assertEquals('foo', $apple->graph->target_id); - $this->assertFalse($storage->hasGraph($apple, 'default')); - - // Check cascading over the graph candidate list. - $apple = $storage->load($id, ['default', 'foo']); - $this->assertEquals('foo', $apple->graph->target_id); - - // Set the 'default' graph. - $apple - ->set('graph', 'default') - ->set('title', 'Apple') - ->save(); - - // Check that, by default, the 'default' graph is loaded. - $apple = $storage->load($id); - $this->assertEquals('default', $apple->graph->target_id); - $this->assertTrue($storage->hasGraph($apple, 'default')); - $this->assertTrue($storage->hasGraph($apple, 'foo')); - - // Create a new 'arbitrary' graph and add it to the mapping. - $this->createGraph('arbitrary'); - - $apple - ->set('graph', 'arbitrary') - ->set('title', 'Apple in an arbitrary graph') - ->save(); - - $apple = $storage->load($id, ['arbitrary']); - $this->assertEquals('arbitrary', $apple->graph->target_id); - $this->assertEquals('Apple in an arbitrary graph', $apple->label()); - - // Delete the foo version. - $storage->deleteFromGraph([$apple], 'foo'); - $this->assertNull($storage->load($id, ['foo'])); - $this->assertNotNull($storage->load($id, ['default'])); - $this->assertNotNull($storage->load($id, ['arbitrary'])); - - // Create a graph that is excluded from the default graphs list. - // @see \Drupal\sparql_graph_test\DefaultGraphsSubscriber - $this->createGraph('non_default_graph'); - - $apple - ->set('graph', 'non_default_graph') - ->set('title', 'Apple in non_default_graph graph') - ->save(); - - // Delete the entity from 'default' and 'arbitrary'. - $storage->deleteFromGraph([$apple], 'default'); - $storage->deleteFromGraph([$apple], 'arbitrary'); - - // Check that the entity is loaded from an explicitly passed graph even it's - // a non-default graph. - $this->assertNotNull($storage->load($id, ['non_default_graph'])); - // Same for entity query. - $ids = $this->getQuery() - ->graphs(['non_default_graph']) - ->condition('id', $id) - ->execute(); - $this->assertCount(1, $ids); - $this->assertEquals($id, reset($ids)); - - // Even the entity exists in 'non_default_graph' is not returned because - // this graph is not a default graph. - $this->assertNull($storage->load($id)); - // Same for entity query. - $ids = $this->getQuery()->condition('id', $id)->execute(); - $this->assertEmpty($ids); - - // Delete the entity. - $apple->delete(); - // All versions are gone. - $this->assertNull($storage->load($id, ['default'])); - $this->assertNull($storage->load($id, ['foo'])); - $this->assertNull($storage->load($id, ['arbitrary'])); - $this->assertNull($storage->load($id, ['non_default_graph'])); - - // Check that the default graph method doesn't return a disabled or an - // invalid graph. - $this->createGraph('disabled_graph', 20, FALSE); - $default_graphs = $this->container->get('sparql.graph_handler') - ->getEntityTypeDefaultGraphIds('sparql_test'); - $this->assertNotContains('disabled_graph', $default_graphs); - $this->assertNotContains('non_existing_graph', $default_graphs); - - // Try to request the entity from a non-existing graph. - $this->setExpectedException(\InvalidArgumentException::class, "Graph 'invalid graph' doesn't exist for entity type 'sparql_test'."); - $storage->load($id, ['invalid graph', 'default', 'foo']); - } - - /** - * Creates a new graph entity and adds it to the 'fruit' mapping. - * - * @param string $id - * The graph ID. - * @param int $weight - * (optional) The graph weight. Defaults to 0. - * @param bool $status - * (optional) If the graph is enabled. Defaults to TRUE. - */ - protected function createGraph(string $id, int $weight = 0, bool $status = TRUE): void { - SparqlGraph::create(['id' => $id, 'label' => ucwords($id)]) - ->setStatus($status) - ->setWeight($weight) - ->save(); - SparqlMapping::loadByName('sparql_test', 'fruit') - ->addGraphs([$id => "http://example.com/fruit/graph/$id"]) - ->save(); - } - - /** - * Returns the entity query. - * - * @return \Drupal\sparql_entity_storage\Entity\Query\Sparql\SparqlQueryInterface - * The SPARQL entity query. - */ - protected function getQuery() { - return $this->container - ->get('entity_type.manager') - ->getStorage('sparql_test') - ->getQuery(); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/SparqlKernelTestBase.php b/sparql_entity_storage/tests/src/Kernel/SparqlKernelTestBase.php deleted file mode 100644 index a06159fa..00000000 --- a/sparql_entity_storage/tests/src/Kernel/SparqlKernelTestBase.php +++ /dev/null @@ -1,48 +0,0 @@ -setUpSparql(); - $this->installConfig(['sparql_entity_storage', 'sparql_test']); - } - - /** - * {@inheritdoc} - */ - public function tearDown(): void { - // Delete 'sparql_test' entities that might have been created during tests. - $storage = $this->container->get('entity_type.manager')->getStorage('sparql_test'); - $ids = $storage->getQuery()->execute(); - $storage->delete($storage->loadMultiple($ids)); - parent::tearDown(); - } - -} diff --git a/sparql_entity_storage/tests/src/Kernel/SparqlSerializerTest.php b/sparql_entity_storage/tests/src/Kernel/SparqlSerializerTest.php deleted file mode 100644 index bce5d8ab..00000000 --- a/sparql_entity_storage/tests/src/Kernel/SparqlSerializerTest.php +++ /dev/null @@ -1,69 +0,0 @@ -setUpSparql(); - $this->installConfig(['sparql_entity_storage', 'sparql_entity_serializer_test']); - } - - /** - * Tests content negotiation. - */ - public function testContentNegotiation() { - $entity = Rdf::create([ - 'rid' => 'fruit', - 'id' => 'http://example.com/apple', - 'label' => 'Apple', - ]); - $entity->save(); - - $encoders = $this->container->getParameter('sparql_entity.encoders'); - $serializer = $this->container->get('sparql_entity.serializer'); - foreach ($encoders as $format => $content_type) { - $serialized = trim($serializer->serializeEntity($entity, $format)); - $expected = trim(file_get_contents(__DIR__ . "/../../fixtures/content-negotiation/rdf_entity/$format")); - $this->assertEquals($expected, $serialized); - } - } - - /** - * {@inheritdoc} - */ - public function tearDown() { - Rdf::load('http://example.com/apple')->delete(); - parent::tearDown(); - } - -} diff --git a/sparql_entity_storage/tests/src/Traits/SparqlConnectionTrait.php b/sparql_entity_storage/tests/src/Traits/SparqlConnectionTrait.php deleted file mode 100644 index 1c3b9676..00000000 --- a/sparql_entity_storage/tests/src/Traits/SparqlConnectionTrait.php +++ /dev/null @@ -1,88 +0,0 @@ -resetParameters(TRUE); - $client->setUri("http://{$this->sparqlConnectionInfo['host']}:{$this->sparqlConnectionInfo['port']}/"); - $client->setMethod('GET'); - $response = $client->request(); - $server_header = $response->getHeader('Server'); - if (strpos($server_header, "Virtuoso/06") !== FALSE) { - throw new \Exception('Not running on Virtuoso 6.'); - } - } - - /** - * Setup the db connection to the triple store. - * - * @throws \LogicException - * When SIMPLETEST_SPARQL_DB is not set. - */ - protected function setUpSparql() { - // If the test is run with argument db url then use it. - // export SIMPLETEST_SPARQL_DB='sparql://127.0.0.1:8890/'. - $db_url = getenv('SIMPLETEST_SPARQL_DB'); - if (empty($db_url)) { - throw new \LogicException('No Sparql connection was defined. Set the SIMPLETEST_SPARQL_DB environment variable.'); - } - - $this->sparqlConnectionInfo = Database::convertDbUrlToConnectionInfo($db_url, dirname(dirname(__FILE__))); - $this->sparqlConnectionInfo['namespace'] = 'Drupal\\Driver\\Database\\sparql'; - - // Do not allow Virtuoso 6. - $this->detectVirtuoso6(); - - Database::addConnectionInfo('sparql_default', 'default', $this->sparqlConnectionInfo); - - $this->sparql = Database::getConnection('default', 'sparql_default'); - } - - /** - * {@inheritdoc} - */ - protected function writeSettings(array $settings) { - // The BrowserTestBase is creating a new copy of the settings.php file to - // the test directory so the SPARQL entry needs to be inserted into the new - // configuration. - $key = 'sparql_default'; - $target = 'default'; - - $settings['databases'][$key][$target] = (object) [ - 'value' => Database::getConnectionInfo($key)[$target], - 'required' => TRUE, - ]; - - parent::writeSettings($settings); - } - -}