summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorDries2013-06-20 19:09:30 (GMT)
committerDries2013-06-20 19:09:30 (GMT)
commit5f67fd1d0858c6f52b4f2685a45b673d6b33e449 (patch)
tree6c21e54c968af830c2509d9e5849c2a3df79fe8a /core
parent98b6331e1e61608cf00c760d0fa10c90a93ecc71 (diff)
Issue #1893820 by fago, das-peter, Berdir: Manage entity field definitions in the entity manager.
Diffstat (limited to 'core')
-rw-r--r--core/core.services.yml2
-rw-r--r--core/includes/entity.api.php36
-rw-r--r--core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php5
-rw-r--r--core/lib/Drupal/Core/Entity/DatabaseStorageController.php74
-rw-r--r--core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php2
-rw-r--r--core/lib/Drupal/Core/Entity/EntityManager.php169
-rw-r--r--core/lib/Drupal/Core/Entity/EntityNG.php6
-rw-r--r--core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php44
-rw-r--r--core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php2
9 files changed, 202 insertions, 138 deletions
diff --git a/core/core.services.yml b/core/core.services.yml
index 50775db..5a60f4f 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -150,7 +150,7 @@ services:
- { name: persist }
plugin.manager.entity:
class: Drupal\Core\Entity\EntityManager
- arguments: ['@container.namespaces', '@service_container']
+ arguments: ['@container.namespaces', '@service_container', '@module_handler', '@cache.cache', '@language_manager']
plugin.manager.archiver:
class: Drupal\Core\Archiver\ArchiverManager
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index 986e344..726d1b1 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -473,26 +473,26 @@ function hook_entity_form_display_alter(\Drupal\entity\Plugin\Core\Entity\Entity
}
/**
- * Define custom entity properties.
+ * Define custom entity fields.
*
* @param string $entity_type
- * The entity type for which to define entity properties.
+ * The entity type for which to define entity fields.
*
* @return array
- * An array of property information having the following optional entries:
- * - definitions: An array of property definitions to add all entities of this
- * type, keyed by property name. See
- * Drupal\Core\TypedData\TypedDataManager::create() for a list of supported
- * keys in property definitions.
- * - optional: An array of property definitions for optional properties keyed
- * by property name. Optional properties are properties that only exist for
- * certain bundles of the entity type.
- * - bundle map: An array keyed by bundle name containing the names of
- * optional properties that entities of this bundle have.
- *
- * @see Drupal\Core\TypedData\TypedDataManager::create()
+ * An array of entity field information having the following optional entries:
+ * - definitions: An array of field definitions to add all entities of this
+ * type, keyed by field name. See
+ * \Drupal\Core\Entity\EntityManager::getFieldDefinitions() for a list of
+ * supported keys in field definitions.
+ * - optional: An array of field definitions for optional entity fields, keyed
+ * by field name. Optional fields are fields that only exist for certain
+ * bundles of the entity type.
+ * - bundle map: An array keyed by bundle name, containing the names of
+ * optional fields that entities of this bundle have.
+ *
* @see hook_entity_field_info_alter()
- * @see Drupal\Core\Entity\StorageControllerInterface::getPropertyDefinitions()
+ * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitions()
+ * @see \Drupal\Core\TypedData\TypedDataManager::create()
*/
function hook_entity_field_info($entity_type) {
if (mymodule_uses_entity_type($entity_type)) {
@@ -521,12 +521,12 @@ function hook_entity_field_info($entity_type) {
}
/**
- * Alter defined entity properties.
+ * Alter defined entity fields.
*
* @param array $info
- * The property info array as returned by hook_entity_field_info().
+ * The entity field info array as returned by hook_entity_field_info().
* @param string $entity_type
- * The entity type for which entity properties are defined.
+ * The entity type for which entity fields are defined.
*
* @see hook_entity_field_info()
*/
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
index e35a533..96a4dba 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
@@ -401,9 +401,10 @@ class ConfigStorageController extends EntityStorageControllerBase {
}
/**
- * Implements Drupal\Core\Entity\EntityStorageControllerInterface::getFieldDefinitions().
+ * {@inheritdoc}
*/
- public function getFieldDefinitions(array $constraints) {
+ public function baseFieldDefinitions() {
+ // @todo: Define abstract once all entity types have been converted.
return array();
}
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index a3cd9df..8fa28a6 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -27,22 +27,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
class DatabaseStorageController extends EntityStorageControllerBase {
/**
- * An array of field information, i.e. containing definitions.
- *
- * @var array
- *
- * @see hook_entity_field_info()
- */
- protected $entityFieldInfo;
-
- /**
- * Static cache of field definitions per bundle.
- *
- * @var array
- */
- protected $fieldDefinitions;
-
- /**
* Name of entity's revision database table field, if it supports revisions.
*
* Has the value FALSE if this entity does not use revisions.
@@ -555,64 +539,10 @@ class DatabaseStorageController extends EntityStorageControllerBase {
}
/**
- * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::getFieldDefinitions().
- */
- public function getFieldDefinitions(array $constraints) {
- if (!isset($this->entityFieldInfo)) {
- // First, try to load from cache.
- $cid = 'entity_field_definitions:' . $this->entityType . ':' . language(Language::TYPE_INTERFACE)->langcode;
- if ($cache = cache()->get($cid)) {
- $this->entityFieldInfo = $cache->data;
- }
- else {
- $this->entityFieldInfo = array(
- 'definitions' => $this->baseFieldDefinitions(),
- // Contains definitions of optional (per-bundle) fields.
- 'optional' => array(),
- // An array keyed by bundle name containing the optional fields added
- // by the bundle.
- 'bundle map' => array(),
- );
-
- // Invoke hooks.
- $result = module_invoke_all($this->entityType . '_property_info');
- $this->entityFieldInfo = NestedArray::mergeDeep($this->entityFieldInfo, $result);
- $result = module_invoke_all('entity_field_info', $this->entityType);
- $this->entityFieldInfo = NestedArray::mergeDeep($this->entityFieldInfo, $result);
-
- $hooks = array('entity_field_info', $this->entityType . '_property_info');
- drupal_alter($hooks, $this->entityFieldInfo, $this->entityType);
-
- // Enforce fields to be multiple by default.
- foreach ($this->entityFieldInfo['definitions'] as &$definition) {
- $definition['list'] = TRUE;
- }
- foreach ($this->entityFieldInfo['optional'] as &$definition) {
- $definition['list'] = TRUE;
- }
- cache()->set($cid, $this->entityFieldInfo, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
- }
- }
-
- $bundle = !empty($constraints['Bundle']) ? $constraints['Bundle'] : FALSE;
-
- // Add in per-bundle fields.
- if (!isset($this->fieldDefinitions[$bundle])) {
- $this->fieldDefinitions[$bundle] = $this->entityFieldInfo['definitions'];
-
- if ($bundle && isset($this->entityFieldInfo['bundle map'][$bundle])) {
- $this->fieldDefinitions[$bundle] += array_intersect_key($this->entityFieldInfo['optional'], array_flip($this->entityFieldInfo['bundle map'][$bundle]));
- }
- }
- return $this->fieldDefinitions[$bundle];
- }
-
- /**
- * Defines the base properties of the entity type.
- *
- * @todo: Define abstract once all entity types have been converted.
+ * {@inheritdoc}
*/
public function baseFieldDefinitions() {
+ // @todo: Define abstract once all entity types have been converted.
return array();
}
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 73c903d..e89cb02 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -309,7 +309,7 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
}
$data = $query->execute();
- $field_definition = $this->getFieldDefinitions(array());
+ $field_definition = \Drupal::entityManager()->getFieldDefinitions($this->entityType);
if ($this->revisionTable) {
$data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table'])));
}
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index ce19982..c6561b6 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -9,6 +9,9 @@ namespace Drupal\Core\Entity;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
@@ -48,6 +51,43 @@ class EntityManager extends PluginManagerBase {
protected $controllers = array();
/**
+ * The module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * The cache backend to use.
+ *
+ * @var \Drupal\Core\Cache\CacheBackendInterface
+ */
+ protected $cache;
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManager
+ */
+ protected $languageManager;
+
+ /**
+ * An array of field information per entity type, i.e. containing definitions.
+ *
+ * @var array
+ *
+ * @see hook_entity_field_info()
+ */
+ protected $entityFieldInfo;
+
+ /**
+ * Static cache of field definitions per bundle and entity type.
+ *
+ * @var array
+ */
+ protected $fieldDefinitions;
+
+ /**
* Constructs a new Entity plugin manager.
*
* @param \Traversable $namespaces
@@ -55,16 +95,27 @@ class EntityManager extends PluginManagerBase {
* keyed by the corresponding namespace to look for plugin implementations,
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The service container this object should use.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+ * The cache backend to use.
+ * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * The language manager.
*/
- public function __construct(\Traversable $namespaces, ContainerInterface $container) {
+ public function __construct(\Traversable $namespaces, ContainerInterface $container, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager) {
// Allow the plugin definition to be altered by hook_entity_info_alter().
$annotation_namespaces = array(
'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
);
+
+ $this->moduleHandler = $module_handler;
+ $this->cache = $cache;
+ $this->languageManager = $language_manager;
+
$this->discovery = new AnnotatedClassDiscovery('Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
$this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
$this->discovery = new AlterDecorator($this->discovery, 'entity_info');
- $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . language(Language::TYPE_INTERFACE)->langcode, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
+ $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->langcode, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
$this->factory = new DefaultFactory($this->discovery);
$this->container = $container;
@@ -289,4 +340,118 @@ class EntityManager extends PluginManagerBase {
return $admin_path;
}
+ /**
+ * Gets an array of entity field definitions.
+ *
+ * If a bundle is passed, fields specific to this bundle are included. Entity
+ * fields are always multi-valued, so 'list' is TRUE for each returned field
+ * definition.
+ *
+ * @param string $entity_type
+ * The entity type to get field definitions for.
+ * @param string $bundle
+ * (optional) The entity bundle for which to get field definitions. If NULL
+ * is passed, no bundle-specific fields are included. Defaults to NULL.
+ *
+ * @return array
+ * An array of field definitions of entity fields, keyed by field
+ * name. In addition to the typed data definition keys as described at
+ * \Drupal\Core\TypedData\TypedDataManager::create() the following keys are
+ * supported:
+ * - queryable: Whether the field is queryable via QueryInterface.
+ * Defaults to TRUE if 'computed' is FALSE or not set, to FALSE otherwise.
+ * - translatable: Whether the field is translatable. Defaults to FALSE.
+ * - configurable: A boolean indicating whether the field is configurable
+ * via field.module. Defaults to FALSE.
+ *
+ * @see \Drupal\Core\TypedData\TypedDataManager::create()
+ * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitionsByConstraints()
+ */
+ public function getFieldDefinitions($entity_type, $bundle = NULL) {
+ if (!isset($this->entityFieldInfo[$entity_type])) {
+ // First, try to load from cache.
+ $cid = 'entity_field_definitions:' . $entity_type . ':' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->langcode;
+ if ($cache = $this->cache->get($cid)) {
+ $this->entityFieldInfo[$entity_type] = $cache->data;
+ }
+ else {
+ $this->entityFieldInfo[$entity_type] = array(
+ 'definitions' => $this->getStorageController($entity_type)->baseFieldDefinitions(),
+ // Contains definitions of optional (per-bundle) fields.
+ 'optional' => array(),
+ // An array keyed by bundle name containing the optional fields added
+ // by the bundle.
+ 'bundle map' => array(),
+ );
+
+ // Invoke hooks.
+ $result = $this->moduleHandler->invokeAll($entity_type . '_field_info');
+ $this->entityFieldInfo[$entity_type] = NestedArray::mergeDeep($this->entityFieldInfo[$entity_type], $result);
+ $result = $this->moduleHandler->invokeAll('entity_field_info', array($entity_type));
+ $this->entityFieldInfo[$entity_type] = NestedArray::mergeDeep($this->entityFieldInfo[$entity_type], $result);
+
+ $hooks = array('entity_field_info', $entity_type . '_field_info');
+ $this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type], $entity_type);
+
+ // Enforce fields to be multiple by default.
+ foreach ($this->entityFieldInfo[$entity_type]['definitions'] as &$definition) {
+ $definition['list'] = TRUE;
+ }
+ foreach ($this->entityFieldInfo[$entity_type]['optional'] as &$definition) {
+ $definition['list'] = TRUE;
+ }
+ $this->cache->set($cid, $this->entityFieldInfo[$entity_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE, 'entity_field_info' => TRUE));
+ }
+ }
+
+ if (!$bundle) {
+ return $this->entityFieldInfo[$entity_type]['definitions'];
+ }
+ else {
+ // Add in per-bundle fields.
+ if (!isset($this->fieldDefinitions[$entity_type][$bundle])) {
+ $this->fieldDefinitions[$entity_type][$bundle] = $this->entityFieldInfo[$entity_type]['definitions'];
+ if (isset($this->entityFieldInfo[$entity_type]['bundle map'][$bundle])) {
+ $this->fieldDefinitions[$entity_type][$bundle] += array_intersect_key($this->entityFieldInfo[$entity_type]['optional'], array_flip($this->entityFieldInfo[$entity_type]['bundle map'][$bundle]));
+ }
+ }
+ return $this->fieldDefinitions[$entity_type][$bundle];
+ }
+ }
+
+ /**
+ * Gets an array of entity field definitions based on validation constraints.
+ *
+ * @param string $entity_type
+ * The entity type to get field definitions for.
+ * @param array $constraints
+ * An array of entity constraints as used for entities in typed data
+ * definitions, i.e. an array optionally including a 'Bundle' key.
+ * For example the constraints used by an entity reference could be:
+ * @code
+ * array(
+ * 'Bundle' => 'article',
+ * )
+ * @endcode
+ *
+ * @return array
+ * An array of field definitions of entity fields, keyed by field
+ * name.
+ *
+ * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitions()
+ */
+ public function getFieldDefinitionsByConstraints($entity_type, array $constraints) {
+ // @todo: Add support for specifying multiple bundles.
+ return $this->getFieldDefinitions($entity_type, isset($constraints['Bundle']) ? $constraints['Bundle'] : NULL);
+ }
+
+ /**
+ * Clears static and persistent field definition caches.
+ */
+ public function clearCachedFieldDefinitions() {
+ unset($this->entityFieldInfo);
+ unset($this->fieldDefinitions);
+ $this->cache->deleteTags(array('entity_field_info' => TRUE));
+ }
+
}
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 41f2f67..355114e 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -281,10 +281,8 @@ class EntityNG extends Entity {
*/
public function getPropertyDefinitions() {
if (!isset($this->fieldDefinitions)) {
- $this->fieldDefinitions = \Drupal::entityManager()->getStorageController($this->entityType)->getFieldDefinitions(array(
- 'EntityType' => $this->entityType,
- 'Bundle' => $this->bundle,
- ));
+ $bundle = $this->bundle != $this->entityType ? $this->bundle : NULL;
+ $this->fieldDefinitions = \Drupal::entityManager()->getFieldDefinitions($this->entityType, $bundle);
}
return $this->fieldDefinitions;
}
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
index e533dd7..0cf8b85 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
@@ -126,46 +126,16 @@ interface EntityStorageControllerInterface {
public function save(EntityInterface $entity);
/**
- * Gets an array of entity field definitions.
- *
- * If a 'bundle' key is present in the given entity definition, fields
- * specific to this bundle are included.
- * Entity fields are always multi-valued, so 'list' is TRUE for each
- * returned field definition.
- *
- * @param array $constraints
- * An array of entity constraints as used for entities in typed data
- * definitions, i.e. an array having an 'entity type' and optionally a
- * 'bundle' key. For example:
- * @code
- * array(
- * 'EntityType' => 'node',
- * 'Bundle' => 'article',
- * )
- * @endcode
+ * Defines the base fields of the entity type.
*
* @return array
- * An array of field definitions of entity fields, keyed by field
- * name. In addition to the typed data definition keys as described at
- * \Drupal::typedData()->create() the follow keys are supported:
- * - queryable: Whether the field is queryable via QueryInterface.
- * Defaults to TRUE if 'computed' is FALSE or not set, to FALSE otherwise.
- * - translatable: Whether the field is translatable. Defaults to FALSE.
- * - configurable: A boolean indicating whether the field is configurable
- * via field.module. Defaults to FALSE.
- * - property_constraints: An array of constraint arrays applying to the
- * field item properties, keyed by property name. E.g. the following
- * validates the value property to have a maximum length of 128:
- * @code
- * array(
- * 'value' => array('Length' => array('max' => 128)),
- * )
- * @endcode
- *
- * @see Drupal\Core\TypedData\TypedDataManager::create()
- * @see \Drupal::typedData()
+ * An array of entity field definitions as specified by
+ * \Drupal\Core\Entity\EntityManager::getFieldDefinitions(), keyed by field
+ * name.
+ *
+ * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitions()
*/
- public function getFieldDefinitions(array $constraints);
+ public function baseFieldDefinitions();
/**
* Gets the name of the service for the query for this entity storage.
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
index f6f224e..2b2b54a 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
@@ -178,7 +178,7 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
*/
public function getPropertyDefinitions() {
// @todo: Support getting definitions if multiple bundles are specified.
- return \Drupal::entityManager()->getStorageController($this->entityType)->getFieldDefinitions($this->definition['constraints']);
+ return \Drupal::entityManager()->getFieldDefinitionsByConstraints($this->entityType, $this->definition['constraints']);
}
/**