diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php index 9a4c413..09299be 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php @@ -207,20 +207,6 @@ class Field extends ConfigEntityBase implements \ArrayAccess { protected $storageDetails; /** - * The hook that is fired when saving or updating a field. - * - * @var string - */ - protected $hook; - - /** - * The arguments for firing a hook after saving or updating a field. - * - * @var array - */ - protected $hook_args; - - /** * {@inheritdoc} */ public function __construct(array $values, $entity_type = 'field_entity') { @@ -287,35 +273,31 @@ public function getExportProperties() { * {@inheritdoc} */ public function save() { - $this->module_handler = \Drupal::moduleHandler(); - $this->storage_controller = \Drupal::service('plugin.manager.entity')->getStorageController($this->entityType); - // Clear the derived data about the field. unset($this->schema, $this->storageDetails); if ($this->isNew()) { - $this->prepareNew(); + return $this->saveNew(); } else { - $this->prepareUpdate(); + return $this->saveUpdated(); } - - // Save the configuration. - $result = parent::save(); - field_cache_clear(); - - // Invoke external hooks after the cache is cleared for API consistency. - // This invokes either hook_field_create_field() or - // hook_field_update_field() depending on whether the field is new. - $this->module_handler->invokeAll($this->hook, $this->hook_args); - - return $result; } /** - * Prepares a new field definition for saving. + * Saves a new field definition. + * + * @return + * SAVED_NEW if the definition was saved. + * + * @throws \Drupal\Core\Entity\EntityStorageException + * In case of failures an exception is thrown. */ - protected function prepareNew() { + protected function saveNew() { + $module_handler = \Drupal::moduleHandler(); + $entity_manager = \Drupal::service('plugin.manager.entity'); + $storage_controller = $entity_manager->getStorageController($this->entityType); + // Field name cannot be longer than Field::ID_MAX_LENGTH characters. We // use drupal_strlen() because the DB layer assumes that column widths // are given in characters rather than bytes. @@ -329,7 +311,7 @@ protected function prepareNew() { } // Ensure the field name is unique (we do not care about deleted fields). - if ($prior_field = current($this->storage_controller->load(array($this->id)))) { + if ($prior_field = current($storage_controller->load(array($this->id)))) { $message = $prior_field->active ? 'Attempt to create field name %id which already exists and is active.' : 'Attempt to create field name %id which already exists, although it is inactive.'; @@ -339,7 +321,7 @@ protected function prepareNew() { // Disallow reserved field names. This can't prevent all field name // collisions with existing entity properties, but some is better than // none. - foreach (\Drupal::service('plugin.manager.entity')->getDefinitions() as $type => $info) { + foreach ($entity_manager->getDefinitions() as $type => $info) { if (in_array($this->id, $info['entity_keys'])) { throw new FieldException(format_string('Attempt to create field %id which is reserved by entity type %type.', array('%id' => $this->id, '%type' => $type))); } @@ -373,17 +355,34 @@ protected function prepareNew() { $this->storage['settings'] += $storage_type['settings']; // Invoke the storage backend's hook_field_storage_create_field(). - $this->module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this)); + $module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this)); - $this->hook = 'field_create_field'; - $this->hook_args = array($this); + // Save the configuration. + $result = parent::save(); + field_cache_clear(); + + // Invoke hook_field_create_field() after the cache is cleared for API + // consistency. + $module_handler->invokeAll('field_create_field', array($this)); + + return $result; } /** - * Prepares a field definition for updating. + * Saves an updated field definition. + * + * @return + * SAVED_UPDATED if the definition was saved. + * + * @throws \Drupal\Core\Entity\EntityStorageException + * In case of failures an exception is thrown. */ - protected function prepareUpdate() { - $original = $this->storage_controller->loadUnchanged($this->id()); + protected function saveUpdated() { + $module_handler = \Drupal::moduleHandler(); + $entity_manager = \Drupal::service('plugin.manager.entity'); + $storage_controller = $entity_manager->getStorageController($this->entityType); + + $original = $storage_controller->loadUnchanged($this->id()); // Some updates are always disallowed. if ($this->type != $original->type) { @@ -405,16 +404,23 @@ protected function prepareUpdate() { // See if any module forbids the update by throwing an exception. This // invokes hook_field_update_forbid(). - $this->module_handler->invokeAll('field_update_forbid', array($this, $original, $has_data)); + $module_handler->invokeAll('field_update_forbid', array($this, $original, $has_data)); // Tell the storage engine to update the field by invoking the // hook_field_storage_update_field(). The storage engine can reject the // definition update as invalid by raising an exception, which stops // execution before the definition is written to config. - $this->module_handler->invoke($this->storage['module'], 'field_storage_update_field', array($this, $original, $has_data)); + $module_handler->invoke($this->storage['module'], 'field_storage_update_field', array($this, $original, $has_data)); - $this->hook = 'field_update_field'; - $this->hook_args = array($this, $original, $has_data); + // Save the configuration. + $result = parent::save(); + field_cache_clear(); + + // Invoke hook_field_update_field() after the cache is cleared for API + // consistency. + $module_handler->invokeAll('field_update_field', array($this, $original, $has_data)); + + return $result; } /** diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php index 9727857..d065cbc 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php @@ -225,20 +225,6 @@ class FieldInstance extends ConfigEntityBase implements \ArrayAccess { protected $bundle_rename_allowed = FALSE; /** - * The hook that is fired when saving or updating a field instance. - * - * @var string - */ - protected $hook; - - /** - * The arguments for firing a hook after saving or updating a field instance. - * - * @var array - */ - protected $hook_args; - - /** * {@inheritdoc} */ public function __construct(array $values, $entity_type = 'field_instance') { @@ -330,62 +316,36 @@ public function getExportProperties() { * {@inheritdoc} */ public function save() { - $module_handler = \Drupal::moduleHandler(); - $entity_manager = \Drupal::service('plugin.manager.entity'); - $field_controller = $entity_manager->getStorageController('field_entity'); - $this->instance_controller = $entity_manager->getStorageController($this->entityType); - - $this->field = current($field_controller->load(array($this->field_name))); - if ($this->isNew()) { - $this->prepareNew(); + return $this->saveNew(); } else { - $this->prepareUpdate(); + return $this->saveUpdated(); } - - $field_type_info = field_info_field_types($this->field->type); - - // Set the default instance settings. - $this->settings += $field_type_info['instance_settings']; - - // Set the default widget and settings. - $this->widget += array( - 'type' => $field_type_info['default_widget'], - 'settings' => array(), - ); - // Get the widget module and settings from the widget type. - if ($widget_type_info = \Drupal::service('plugin.manager.field.widget')->getDefinition($this->widget['type'])) { - $this->widget['module'] = $widget_type_info['module']; - $this->widget['settings'] += $widget_type_info['settings']; - } - // If no weight is specified, make sure the field sinks to the bottom. - if (!isset($this->widget['weight'])) { - $max_weight = field_info_max_weight($this->entity_type, $this->bundle, 'form'); - $this->widget['weight'] = isset($max_weight) ? $max_weight + 1 : 0; - } - - // Save the configuration. - $result = parent::save(); - field_cache_clear(); - - // Invoke external hooks after the cache is cleared for API consistency. - // This invokes hook_field_create_instance() or hook_field_update_instance() - // depending on whether the field is new. - $module_handler->invokeAll($this->hook, $this->hook_args); - - return $result; } /** - * Prepares a field instance definition for saving. + * Saves a new field instance definition. + * + * @return + * SAVED_NEW if the definition was saved. + * + * @throws \Drupal\Core\Entity\EntityStorageException + * In case of failures an exception is thrown. */ - protected function prepareNew() { - if (empty($this->field)) { + protected function saveNew() { + $module_handler = \Drupal::moduleHandler(); + $entity_manager = \Drupal::service('plugin.manager.entity'); + $field_controller = $entity_manager->getStorageController('field_entity'); + $instance_controller = $entity_manager->getStorageController($this->entityType); + + $field = current($field_controller->load(array($this->field_name))); + + if (empty($field)) { throw new FieldException(format_string("Attempt to save an instance of a field @field_id that doesn't exist or is currently inactive.", array('@field_name' => $this->field_name))); } // Check that the field can be attached to this entity type. - if (!empty($field->entity_types) && !in_array($this->entity_type, $this->field->entity_types)) { + if (!empty($field->entity_types) && !in_array($this->entity_type, $field->entity_types)) { throw new FieldException(format_string('Attempt to create an instance of field @field_name on forbidden entity type @entity_type.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type))); } @@ -393,24 +353,45 @@ protected function prepareNew() { $this->id = $this->id(); // Ensure the field instance is unique within the bundle. - if ($prior_instance = current($this->instance_controller->load(array($this->id)))) { + if ($prior_instance = current($instance_controller->load(array($this->id)))) { throw new FieldException(format_string('Attempt to create an instance of field @field_name on bundle @bundle that already has an instance of that field.', array('@field_name' => $this->field_name, '@bundle' => $this->bundle))); } // Set the field UUID. - $this->field_uuid = $this->field->uuid; + $this->field_uuid = $field->uuid; + + // Ensure default values are present. + $this->prepareSave($field->type); + + // Save the configuration. + $result = parent::save(); + field_cache_clear(); - $this->hook = 'field_create_instance'; - $this->hook_args = array($this); + // Invoke hook_field_create_instance() after the cache is cleared for API + // consistency. + $module_handler->invokeAll('field_create_instance', array($this)); + + return $result; } /** - * Prepares for a field instance definition for updating. + * Saves an updated field instance definition. + * + * @return + * SAVED_UPDATED if the definition was saved. + * + * @throws \Drupal\Core\Entity\EntityStorageException + * In case of failures an exception is thrown. */ - protected function prepareUpdate() { - $original = \Drupal::service('plugin.manager.entity') - ->getStorageController($this->entityType) - ->loadUnchanged($this->getOriginalID()); + protected function saveUpdated() { + $module_handler = \Drupal::moduleHandler(); + $entity_manager = \Drupal::service('plugin.manager.entity'); + $field_controller = $entity_manager->getStorageController('field_entity'); + $instance_controller = $entity_manager->getStorageController($this->entityType); + + $field = current($field_controller->load(array($this->field_name))); + + $original = $instance_controller->loadUnchanged($this->getOriginalID()); // Some updates are always disallowed. if ($this->entity_type != $original->entity_type) { @@ -423,8 +404,50 @@ protected function prepareUpdate() { throw new FieldException("Cannot change an existing instance's field."); } - $this->hook = 'field_update_instance'; - $this->hook_args = array($this, $original); + // Ensure default values are present. + $this->prepareSave($field->type); + + // Save the configuration. + $result = parent::save(); + field_cache_clear(); + + // Invoke hook_field_update_instance() after the cache is cleared for API + // consistency. + $module_handler->invokeAll('field_update_instance', array($this, $original)); + + return $result; + } + + /** + * Prepares the instance definition for saving. + * + * @param string $field_type + * The field type. + * @todo Remove the parameter when http://drupal.org/node/1967106 is fixed. + */ + protected function prepareSave($field_type) { + $widget_manager = \Drupal::service('plugin.manager.field.widget'); + + $field_type_info = field_info_field_types($field_type); + + // Set the default instance settings. + $this->settings += $field_type_info['instance_settings']; + + // Set the default widget and settings. + $this->widget += array( + 'type' => $field_type_info['default_widget'], + 'settings' => array(), + ); + // Get the widget module and settings from the widget type. + if ($widget_type_info = $widget_manager->getDefinition($this->widget['type'])) { + $this->widget['module'] = $widget_type_info['module']; + $this->widget['settings'] += $widget_type_info['settings']; + } + // If no weight is specified, make sure the field sinks to the bottom. + if (!isset($this->widget['weight'])) { + $max_weight = field_info_max_weight($this->entity_type, $this->bundle, 'form'); + $this->widget['weight'] = isset($max_weight) ? $max_weight + 1 : 0; + } } /**