Skip to content
This repository was archived by the owner on Aug 25, 2022. It is now read-only.

Commit

Permalink
Merge pull request #28 from ec-europa/sparql-entity-query
Browse files Browse the repository at this point in the history
Modernise the SPARQL entity query, fix some field handler issues and allow Rdf entity static loaders to pass graphs
  • Loading branch information
idimopoulos authored May 15, 2018
2 parents 0fad025 + 14e3270 commit c081b00
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 121 deletions.
2 changes: 1 addition & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ $storage = \Drupal::entityTypeManager()->getStorage('food');
$query = $storage->getQuery;
$ids = $query
->condition('type', 'fruit')
->setGraphType(['default', 'draft'])
->graphs(['default', 'draft'])
->execute();
```
8 changes: 4 additions & 4 deletions modules/rdf_draft/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ $query = \Drupal::service('entity_type.manager')
To further filter by graph, it is enough to call the

```
$query->setGraphType(['default', 'draft']);
$query->graphs(['default', 'draft']);
```
This is where the filter applies. You cannot currently filter by the
`condition()` method.

NOTICE: The results will have only one graph per entity and this will be the
first available graph. With the `setGraphType()` method, you set the priority,
first available graph. With the `graphs()` method, you set the priority,
not the list of graphs to retrieve from. Also, all loaded entities will be
affected by the priority provided in the setGraphType. If you want to set the
affected by the priority provided in the `graphs` method. If you want to set the
priority only for a specific entity, given that you have the id of this entity,
you can do it by setting the priority to the GraphHandler service itself through
the storage class.
Expand All @@ -108,7 +108,7 @@ This is because multiple entities can be loaded in a single request or the same
entity can be loaded more than once. This means that we cannot have a global
priority, nor reset the priority after the entity is loaded.

The difference with the `$query->setGraphType()` above, is that the query saves
The difference with the `$query->graphs()` above, is that the query saves
the graph locally for the query. That means that all loaded entities are
affected by it. For entities that do not have a specific set of graphs in the
query, the normal priority is being used (first from the 'default' graph and
Expand Down
5 changes: 1 addition & 4 deletions src/Entity/Controller/RdfListBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,9 @@ protected function getEntityIds() {
$definitions = $rdf_storage->getGraphDefinitions();
if (isset($definitions[$graph])) {
// Use the graph to build the list.
$query->setGraphType([$graph]);
$query->graphs([$graph]);
}
}
else {
$query->setGraphType($rdf_storage->getGraphHandler()->getEntityTypeGraphIds($rdf_storage->getEntityTypeId()));
}

if ($rid = $request->get('rid') ?: NULL) {
$rid = in_array($rid, array_keys($bundle_info->getBundleInfo('rdf_entity'))) ? [$rid] : NULL;
Expand Down
109 changes: 38 additions & 71 deletions src/Entity/Query/Sparql/Query.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
<?php

declare(strict_types = 1);

namespace Drupal\rdf_entity\Entity\Query\Sparql;

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\QueryBase;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Entity\Query\Sql\ConditionAggregate;
use Drupal\rdf_entity\Database\Driver\sparql\Connection;
use Drupal\rdf_entity\Entity\RdfEntitySparqlStorage;
use Drupal\rdf_entity\RdfEntitySparqlStorageInterface;
use Drupal\rdf_entity\RdfFieldHandler;
use Drupal\rdf_entity\RdfGraphHandlerInterface;

/**
* The base entity query class for Rdf entities.
* The base entity query class for RDF entities.
*/
class Query extends QueryBase implements QueryInterface {
class Query extends QueryBase implements SparqlQueryInterface {

/**
* The connection object.
Expand All @@ -39,15 +40,13 @@ class Query extends QueryBase implements QueryInterface {
protected $prepared = FALSE;

/**
* The graphs from where the query is going to try and load entities from.
*
* The variable holds a plain array of graph uris.
* The graph IDs from where the query is going load entities from.
*
* @var array
* If the value is NULL, the query will load entities from all graphs.
*
* @todo: Needs change to query graphs.
* @var string[]|null
*/
protected $graphs = NULL;
protected $graphIds;

/**
* An array that is meant to hold the results.
Expand Down Expand Up @@ -102,75 +101,35 @@ class Query extends QueryBase implements QueryInterface {
* The rdf graph handler service.
* @param \Drupal\rdf_entity\RdfFieldHandler $rdf_field_handler
* The rdf mapping handler service.
*
* @throws \Exception
* Thrown when the storage passed is not an RdfEntitySparqlStorage.
*
* @todo: Is this exception check needed?
*/
public function __construct(EntityTypeInterface $entity_type, $conjunction, Connection $connection, array $namespaces, EntityTypeManagerInterface $entity_type_manager, RdfGraphHandlerInterface $rdf_graph_handler, RdfFieldHandler $rdf_field_handler) {
// Assign the handlers before calling the parent so that they can be passed
// to the condition class properly.
$this->graphHandler = $rdf_graph_handler;
$this->fieldHandler = $rdf_field_handler;
$this->entityTypeManager = $entity_type_manager;
$this->entityStorage = $this->entityTypeManager->getStorage($entity_type->id());
$this->connection = $connection;
parent::__construct($entity_type, $conjunction, $namespaces);

if (!$this->entityStorage instanceof RdfEntitySparqlStorage) {
throw new \Exception('Sparql storage is required for this query.');
}

// Set a unique tag for the rdf_entity queries.
$this->addTag('rdf_entity');
$this->addMetaData('entity_type', $this->getEntityType());
}

/**
* Returns the graph handler service.
*
* @return \Drupal\rdf_entity\RdfGraphHandler
* The graph handler service.
*/
public function getGraphHandler() {
return $this->graphHandler;
}

/**
* Returns the mapping handler service.
*
* @return \Drupal\rdf_entity\RdfFieldHandler
* The mapping handler service.
*/
public function getfieldHandler() {
return $this->fieldHandler;
$this->addMetaData('entity_type', $this->entityType);
}

/**
* {@inheritdoc}
*/
public function getEntityTypeId() {
return $this->entityTypeId;
}

/**
* Returns the entity type.
*
* @return \Drupal\Core\Entity\EntityTypeInterface
* The entity type object.
*/
public function getEntityType() {
public function getEntityType(): EntityTypeInterface {
return $this->entityType;
}

/**
* Returns the entity type storage.
*
* @return \Drupal\rdf_entity\Entity\RdfEntitySparqlStorage
* The entity type storage.
* {@inheritdoc}
*/
public function getEntityStorage() {
public function getEntityStorage(): RdfEntitySparqlStorageInterface {
if (!isset($this->entityStorage)) {
$this->entityStorage = $this->entityTypeManager->getStorage($this->getEntityTypeId());
}
return $this->entityStorage;
}

Expand All @@ -195,24 +154,26 @@ public function execute() {
->result();
}

/**
* {@inheritdoc}
*/
public function graphs(array $graph_ids = NULL): SparqlQueryInterface {
$this->graphIds = $graph_ids;
return $this;
}

/**
* Sets the graph types for the query.
*
* This allows the filtering of graphs on the query level. Set the graph IDs
* to restrict the entities to the list of graphs. If the parameter is not
* passed, the default, topmost graph is used.
*
* @param string[]|null $graph_ids
* (optional) An array of graphs ids to be passed into the query.
*
* @todo: When a condition is set on the bundle, this graphs should be
* filtered accordingly.
*
* @see \Drupal\rdf_entity\Entity\RdfEntitySparqlStorage::processGraphResults()
* @deprecated Use the ::graphs() method instead.
*/
public function setGraphType(array $graph_ids = NULL) {
$graph_ids = $graph_ids ?: $this->getGraphHandler()->getDefaultGraphId($this->getEntityTypeId());
$this->graphs = $this->entityStorage->getGraphHandler()->getEntityTypeGraphUrisFlatList($this->getEntityTypeId(), $graph_ids);
@trigger_error('Drupal\rdf_entity\Entity\Query\Sparql\Query::setGraphType() is deprecated. Please use the ::graphs() method instead.', E_USER_DEPRECATED);
$graph_ids = $graph_ids ?: [$this->graphHandler->getDefaultGraphId($this->getEntityTypeId())];
$this->graphs($graph_ids);
}

/**
Expand All @@ -235,11 +196,17 @@ protected function prepare() {
}
$this->query .= "\n";

if ($this->graphs) {
foreach ($this->graphs as $graph) {
$this->query .= 'FROM <' . $graph . '>' . "\n";
}

if (!$this->graphIds) {
// If no graph IDs were requested, allow all graphs that Drupal is aware
// for this entity type.
$this->graphIds = $this->graphHandler->getEntityTypeGraphIds($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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Query/Sparql/SparqlCondition.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class SparqlCondition extends ConditionFundamentals implements ConditionInterfac
/**
* {@inheritdoc}
*/
public function __construct($conjunction, QueryInterface $query, array $namespaces, RdfGraphHandlerInterface $rdf_graph_handler, RdfFieldHandler $rdf_field_handler) {
public function __construct($conjunction, SparqlQueryInterface $query, array $namespaces, RdfGraphHandlerInterface $rdf_graph_handler, RdfFieldHandler $rdf_field_handler) {
$conjunction = strtoupper($conjunction);
parent::__construct($conjunction, $query, $namespaces);
$this->graphHandler = $rdf_graph_handler;
Expand Down
47 changes: 47 additions & 0 deletions src/Entity/Query/Sparql/SparqlQueryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Drupal\rdf_entity\Entity\Query\Sparql;

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\rdf_entity\RdfEntitySparqlStorageInterface;

/**
* Provides an interface for SPARQL entity queries.
*/
interface SparqlQueryInterface extends QueryInterface {

/**
* Sets the IDs of the graph to be queried.
*
* If this method is not called, the default graphs for this entity type are
* used. Calling the method with no argument will remove any filtering of RDF
* entities on graphs and the query will return all entities from all graphs
* that are known by Drupal for this entity type.
*
* @param string[]|null $graph_ids
* (optional) A list of graph IDs to filter on. If omitted, the query will
* return all entities from all graphs that are known by Drupal for this
* entity type.
*
* @return $this
*/
public function graphs(array $graph_ids = NULL): self;

/**
* Returns the entity type.
*
* @return \Drupal\Core\Entity\EntityTypeInterface
* The entity type object.
*/
public function getEntityType(): EntityTypeInterface;

/**
* Returns the entity type storage.
*
* @return \Drupal\rdf_entity\RdfEntitySparqlStorageInterface
* The entity type storage.
*/
public function getEntityStorage(): RdfEntitySparqlStorageInterface;

}
22 changes: 22 additions & 0 deletions src/Entity/Rdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,28 @@ public function hasGraph($graph) {
return $this->entityTypeManager()->getStorage($this->getEntityTypeId())->hasGraph($this, $graph);
}

/**
* {@inheritdoc}
*/
public static function load($id, array $graph_ids = NULL) {
$entity_type_repository = \Drupal::service('entity_type.repository');
$entity_type_manager = \Drupal::entityTypeManager();
/** @var \Drupal\rdf_entity\RdfEntitySparqlStorageInterface $storage */
$storage = $entity_type_manager->getStorage($entity_type_repository->getEntityTypeFromClass(get_called_class()));
return $storage->load($id, $graph_ids);
}

/**
* {@inheritdoc}
*/
public static function loadMultiple(array $ids = NULL, array $graph_ids = NULL) {
$entity_type_repository = \Drupal::service('entity_type.repository');
$entity_type_manager = \Drupal::entityTypeManager();
/** @var \Drupal\rdf_entity\RdfEntitySparqlStorageInterface $storage */
$storage = $entity_type_manager->getStorage($entity_type_repository->getEntityTypeFromClass(get_called_class()));
return $storage->loadMultiple($ids, $graph_ids);
}

/**
* Returns whether the entity bundle has mapping for a certain field column.
*
Expand Down
33 changes: 4 additions & 29 deletions src/Entity/RdfEntitySparqlStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -640,10 +640,10 @@ public function loadByProperties(array $values = [], array $graph_ids = NULL): a
unset($values[$uuid_key]);
}

/** @var \Drupal\rdf_entity\Entity\Query\Sparql\Query $query */
$query = $this->getQuery();
$query->setGraphType($graph_ids);
$query->accessCheck(FALSE);
/** @var \Drupal\rdf_entity\Entity\Query\Sparql\SparqlQueryInterface $query */
$query = $this->getQuery()
->graphs($graph_ids)
->accessCheck(FALSE);
$this->buildPropertyQuery($query, $values);
$result = $query->execute();

Expand Down Expand Up @@ -748,31 +748,6 @@ protected function getQueryServiceName() {
return 'entity.query.sparql';
}

/**
* {@inheritdoc}
*/
public function getQuery($conjunction = 'AND') {
// Access the service directly rather than entity.query factory so the
// storage's current entity type is used.
/** @var \Drupal\rdf_entity\Entity\Query\Sparql\Query $query */
$query = \Drupal::service($this->getQueryServiceName())->get($this->entityType, $conjunction, $this->graphHandler, $this->fieldHandler);

/*
* When the storage class supports the notion of a 'published state' by
* implementing the published interface, we then have to determine if
* drafting has been enabled for this entity type (rdf_draft module). If so,
* the 'draft' graph will hold the unpublished versions, 'default' graph
* contains the published entities.
*/
if (in_array(EntityPublishedInterface::class, class_implements($this->entityClass))) {
if ($this->moduleHandler->moduleExists('rdf_draft')) {
$query->setGraphType($this->getGraphHandler()->getEntityTypeGraphIds($this->getEntityTypeId()));
}
}

return $query;
}

/**
* {@inheritdoc}
*/
Expand Down
8 changes: 8 additions & 0 deletions src/Exception/UnmappedFieldException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Drupal\rdf_entity\Exception;

/**
* Thrown when an unmapped field is requested.
*/
class UnmappedFieldException extends \Exception {}
Loading

0 comments on commit c081b00

Please sign in to comment.