diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 681fc63..efca79d 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -365,8 +365,7 @@ function field_sync_field_status() { $field = \Drupal::config($name)->get(); $fields[$field['uuid']] = $field; } - $deleted_fields = $state->get('field.field.deleted') ?: array(); - $fields += $deleted_fields; + $fields += \Drupal::entityManager()->getStorageController('field_entity')->getDeletedFieldData(); if (empty($fields)) { return; diff --git a/core/modules/field/field.purge.inc b/core/modules/field/field.purge.inc index df30467..ce6369b 100644 --- a/core/modules/field/field.purge.inc +++ b/core/modules/field/field.purge.inc @@ -121,10 +121,8 @@ function field_purge_batch($batch_size) { } // Retrieve all deleted fields. Any that have no instances can be purged. - $deleted_fields = \Drupal::state()->get('field.field.deleted') ?: array(); + $deleted_fields = \Drupal::entityManager()->getStorageController('field_entity')->getDeletedFields(); foreach ($deleted_fields as $field) { - $field = new Field($field); - // We cannot purge anything if the entity type is unknown (e.g. the // providing module was uninstalled). // @todo Revisit after https://drupal.org/node/2080823. @@ -171,18 +169,19 @@ function field_purge_instance($instance) { * The field record to purge. */ function field_purge_field($field) { + $entity_manager = \Drupal::entityManager(); $instances = field_read_instances(array('field_id' => $field['uuid']), array('include_deleted' => 1)); if (count($instances) > 0) { throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field['field_name']))); } - $state = \Drupal::state(); - $deleted_fields = $state->get('field.field.deleted'); + $field_storage_controller = $entity_manager->getStorageController('field_entity'); + $deleted_fields = $field_storage_controller->getDeletedFieldData(); unset($deleted_fields[$field['uuid']]); - $state->set('field.field.deleted', $deleted_fields); + $field_storage_controller->setDeletedFieldData($deleted_fields); // Notify the storage layer. - \Drupal::entityManager()->getStorageController($field->entity_type)->onFieldPurge($field); + $entity_manager->getStorageController($field->entity_type)->onFieldPurge($field); // Clear the cache. field_info_cache_clear(); diff --git a/core/modules/field/field.services.yml b/core/modules/field/field.services.yml index c6ef5da..e160b77 100644 --- a/core/modules/field/field.services.yml +++ b/core/modules/field/field.services.yml @@ -7,7 +7,7 @@ services: arguments: ['@container.namespaces', '@cache.field', '@module_handler', '@language_manager', '@plugin.manager.entity.field.field_type'] field.info: class: Drupal\field\FieldInfo - arguments: ['@cache.field', '@config.factory', '@module_handler', '@plugin.manager.entity.field.field_type'] + arguments: ['@cache.field', '@config.factory', '@module_handler', '@entity.manager', '@plugin.manager.entity.field.field_type'] cache.field: class: Drupal\Core\Cache\CacheBackendInterface tags: diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php index 3421461..3d0d426 100644 --- a/core/modules/field/lib/Drupal/field/Entity/Field.php +++ b/core/modules/field/lib/Drupal/field/Entity/Field.php @@ -416,8 +416,8 @@ protected function saveUpdated() { */ public function delete() { if (!$this->deleted) { + $field_controller = \Drupal::entityManager()->getStorageController('field_entity'); $instance_controller = \Drupal::entityManager()->getStorageController('field_instance'); - $state = \Drupal::state(); // Delete all non-deleted instances. $instance_ids = array(); @@ -438,11 +438,11 @@ public function delete() { // in the key_value table so we can use it later during // field_purge_batch(). This makes sure a new field can be created // immediately with the same name. - $deleted_fields = $state->get('field.field.deleted') ?: array(); $config = $this->getExportProperties(); $config['deleted'] = TRUE; + $deleted_fields = $field_controller->getDeletedFieldData(); $deleted_fields[$this->uuid] = $config; - $state->set('field.field.deleted', $deleted_fields); + $field_controller->setDeletedFieldData($deleted_fields); parent::delete(); diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php index 8d6bc3a..59cd316 100644 --- a/core/modules/field/lib/Drupal/field/FieldInfo.php +++ b/core/modules/field/lib/Drupal/field/FieldInfo.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigFactory; +use Drupal\Core\Entity\EntityManager; use Drupal\Core\Entity\Field\FieldTypePluginManager; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -39,13 +40,20 @@ class FieldInfo { protected $cacheBackend; /** - * Stores a module manager to invoke hooks. + * The module handler. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** + * The entity manager. + * + * @var \Drupal\Core\Entity\EntityManager + */ + protected $entityManager; + + /** * The field type manager to define field. * * @var \Drupal\Core\Entity\Field\FieldTypePluginManager @@ -131,13 +139,16 @@ class FieldInfo { * The configuration factory object to use. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler class to use for invoking hooks. + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager. * @param \Drupal\Core\Entity\Field\FieldTypePluginManager $field_type_manager * The 'field type' plugin manager. */ - public function __construct(CacheBackendInterface $cache_backend, ConfigFactory $config, ModuleHandlerInterface $module_handler, FieldTypePluginManager $field_type_manager) { + public function __construct(CacheBackendInterface $cache_backend, ConfigFactory $config, ModuleHandlerInterface $module_handler, EntityManager $entity_manager, FieldTypePluginManager $field_type_manager) { $this->cacheBackend = $cache_backend; - $this->moduleHandler = $module_handler; $this->config = $config; + $this->moduleHandler = $module_handler; + $this->entityManager = $entity_manager; $this->fieldTypeManager = $field_type_manager; } @@ -227,18 +238,12 @@ public function getFields() { return $this->fieldsById; } - // Read from persistent cache. - if ($cached = $this->cacheBackend->get('field_info:fields')) { - $this->fieldsById = $cached->data; - } - else { - // Collect and prepare fields. - foreach (field_read_fields(array(), array('include_deleted' => TRUE)) as $field) { - $this->fieldsById[$field['uuid']] = $this->prepareField($field); - } - - // Store in persistent cache. - $this->cacheBackend->set('field_info:fields', $this->fieldsById, CacheBackendInterface::CACHE_PERMANENT, array('field_info' => TRUE)); + // Collect and prepare fields. + $storage_controller = $this->entityManager->getStorageController('field_entity'); + $fields = $storage_controller->loadMultiple(); + $fields += $storage_controller->getDeletedFields(); + foreach ($fields as $field) { + $this->fieldsById[$field->uuid()] = $this->prepareField($field); } // Fill the name/ID map. @@ -268,25 +273,16 @@ public function getInstances($entity_type = NULL) { // If the full list is not present in "static" cache yet. if (!$this->loadedAllInstances) { - // Read from persistent cache. - if ($cached = $this->cacheBackend->get('field_info:instances')) { - $this->bundleInstances = $cached->data; - } - else { - // Collect and prepare instances. + // Collect and prepare instances. - // We also need to populate the static field cache, since it will not - // be set by subsequent getBundleInstances() calls. - $this->getFields(); - - foreach (field_read_instances() as $instance) { - $field = $this->getField($instance['entity_type'], $instance['field_name']); - $instance = $this->prepareInstance($instance, $field['type']); - $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance; - } + // We also need to populate the static field cache, since it will not + // be set by subsequent getBundleInstances() calls. + $this->getFields(); - // Store in persistent cache. - $this->cacheBackend->set('field_info:instances', $this->bundleInstances, CacheBackendInterface::CACHE_PERMANENT, array('field_info' => TRUE)); + foreach ($this->entityManager->getStorageController('field_instance')->loadMultiple() as $instance) { + $field = $this->getField($instance['entity_type'], $instance['field_name']); + $instance = $this->prepareInstance($instance, $field['type']); + $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance; } $this->loadedAllInstances = TRUE; @@ -323,10 +319,8 @@ public function getField($entity_type, $field_name) { return; } - // Do not check the (large) persistent cache, but read the definition. - // Cache miss: read from definition. - if ($field = entity_load('field_entity', $entity_type . '.' . $field_name)) { + if ($field = $this->entityManager->getStorageController('field_entity')->load($entity_type . '.' . $field_name)) { $field = $this->prepareField($field); // Save in the "static" cache. @@ -360,14 +354,14 @@ public function getFieldById($field_id) { return; } - // No persistent cache, fields are only persistently cached as part of a - // bundle. - // Cache miss: read from definition. - if ($fields = field_read_fields(array('uuid' => $field_id), array('include_deleted' => TRUE))) { + $properties = array( + 'uuid' => $field_id, + 'include_deleted' => TRUE, + ); + if ($fields = $this->entityManager->getStorageController('field_entity')->loadByProperties($properties)) { $field = current($fields); $field = $this->prepareField($field); - // Store in the static cache. $this->fieldsById[$field['uuid']] = $field; if (!$field['deleted']) { @@ -404,46 +398,13 @@ public function getBundleInstances($entity_type, $bundle) { return array(); } - // Read from the persistent cache. We read fields first, since - // unserializing the cached instance objects tries to access the field - // definitions. - if ($cached_fields = $this->cacheBackend->get("field_info:bundle:fields:$entity_type:$bundle")) { - $fields = $cached_fields->data; - - // Extract the field definitions and save them in the "static" cache. - foreach ($fields as $field) { - if (!isset($this->fieldsById[$field['uuid']])) { - $this->fieldsById[$field['uuid']] = $field; - if (!$field['deleted']) { - $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid']; - } - } - } - - // We can now unserialize the instances. - $cached_instances = $this->cacheBackend->get("field_info:bundle:instances:$entity_type:$bundle"); - $instances = $cached_instances->data; - - // Store the instance definitions in the "static" cache'. Empty (or - // non-existent) bundles are stored separately, so that they do not - // pollute the global list returned by getInstances(). - if ($instances) { - $this->bundleInstances[$entity_type][$bundle] = $instances; - } - else { - $this->emptyBundles[$entity_type][$bundle] = TRUE; - } - return $instances; - } - // Cache miss: collect from the definitions. $field_map = $this->getFieldMap(); $instances = array(); $fields = array(); // Do not return anything for unknown entity types. - if (entity_get_info($entity_type) && !empty($field_map[$entity_type])) { - + if ($this->entityManager->getDefinition($entity_type) && !empty($field_map[$entity_type])) { // Collect names of fields and instances involved in the bundle, using the // field map. The field map is already filtered to active, non-deleted // fields and instances, so those are kept out of the persistent caches. @@ -457,7 +418,7 @@ public function getBundleInstances($entity_type, $bundle) { // Load and prepare the corresponding fields and instances entities. if ($config_ids) { // Place the fields in our global "static". - $loaded_fields = entity_load_multiple('field_entity', array_keys($config_ids)); + $loaded_fields = $this->entityManager->getStorageController('field_entity')->loadMultiple(array_keys($config_ids)); foreach ($loaded_fields as $field) { if (!isset($this->fieldsById[$field['uuid']])) { $field = $this->prepareField($field); @@ -470,7 +431,7 @@ public function getBundleInstances($entity_type, $bundle) { } // Then collect the instances. - $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids)); + $loaded_instances = $this->entityManager->getStorageController('field_instance')->loadMultiple(array_values($config_ids)); foreach ($loaded_instances as $instance) { $field = $instance->getField(); @@ -490,11 +451,6 @@ public function getBundleInstances($entity_type, $bundle) { $this->emptyBundles[$entity_type][$bundle] = TRUE; } - // Store in the persistent cache. Fields and instances are cached in - // separate entries because they need to be unserialized separately. - $this->cacheBackend->set("field_info:bundle:fields:$entity_type:$bundle", $fields, CacheBackendInterface::CACHE_PERMANENT, array('field_info' => TRUE)); - $this->cacheBackend->set("field_info:bundle:instances:$entity_type:$bundle", $instances, CacheBackendInterface::CACHE_PERMANENT, array('field_info' => TRUE)); - return $instances; } diff --git a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php index 2b4ef46..bac9f67 100644 --- a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php +++ b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php @@ -190,4 +190,16 @@ public function loadByProperties(array $conditions = array()) { return $matching_instances; } + public function getDeletedFieldInstances() { + $deleted = array(); + foreach ($this->getDeletedFieldInstanceData() as $uuid => $config) { + $deleted[$uuid] = $this->create($config); + } + return $deleted; + } + + public function getDeletedFieldInstanceData() { + return $this->state->get('field.instance.deleted') ?: array(); + } + } diff --git a/core/modules/field/lib/Drupal/field/FieldStorageController.php b/core/modules/field/lib/Drupal/field/FieldStorageController.php index fff0df7..8592524 100644 --- a/core/modules/field/lib/Drupal/field/FieldStorageController.php +++ b/core/modules/field/lib/Drupal/field/FieldStorageController.php @@ -96,10 +96,10 @@ public static function createInstance(ContainerInterface $container, $entity_typ public function loadByProperties(array $conditions = array()) { // Include instances of inactive fields if specified in the // $conditions parameters. - $include_inactive = $conditions['include_inactive']; + $include_inactive = isset($conditions['include_inactive']) ? $conditions['include_inactive'] : FALSE; unset($conditions['include_inactive']); // Include deleted instances if specified in the $conditions parameters. - $include_deleted = $conditions['include_deleted']; + $include_deleted = isset($conditions['include_deleted']) ? $conditions['include_deleted'] : FALSE; unset($conditions['include_deleted']); // Get fields stored in configuration. @@ -115,10 +115,7 @@ public function loadByProperties(array $conditions = array()) { // Merge deleted fields (stored in state) if needed. if ($include_deleted) { - $deleted_fields = $this->state->get('field.field.deleted') ?: array(); - foreach ($deleted_fields as $id => $config) { - $fields[$id] = $this->entityManager->getStorageController($this->entityType)->create($config); - } + $fields += $this->getDeletedFields(); } // Translate "do not include inactive instances" into actual conditions. @@ -156,6 +153,18 @@ public function loadByProperties(array $conditions = array()) { } return $matching_fields; + } + + public function getDeletedFields() { + $deleted = array(); + foreach ($this->getDeletedFieldData() as $uuid => $config) { + $deleted[$uuid] = $this->create($config); + } + return $deleted; + } + public function getDeletedFieldData() { + return $this->state->get('field.field.deleted') ?: array(); } + }