reverted: --- b/core/lib/Drupal/Core/Field/FormatterPluginManager.php +++ a/core/lib/Drupal/Core/Field/FormatterPluginManager.php @@ -9,7 +9,6 @@ use Drupal\Component\Plugin\Factory\DefaultFactory; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Entity\Field\FieldItemListInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageManager; use Drupal\Core\Plugin\DefaultPluginManager; @@ -201,26 +200,4 @@ return isset($info['settings']) ? $info['settings'] : array(); } - /** - * @todo Document. - */ - public function viewBaseField(FieldItemListInterface $items) { - $options = array( - 'field_definition' => $items->getFieldDefinition(), - 'view_mode' => 'default', - 'configuration' => array( - 'label' => 'hidden', - ), - ); - $formatter = $this->getInstance($options); - - $entity = $items->getEntity(); - - $items_multi = array($entity->id() => $items); - $formatter->prepareView($items_multi); - $result = $formatter->view($items); - $field_name = $items->getFieldDefinition()->getFieldName(); - return isset($result[$field_name]) ? $result[$field_name] : array(); - } - } reverted: --- b/core/lib/Drupal/Core/Field/WidgetPluginManager.php +++ a/core/lib/Drupal/Core/Field/WidgetPluginManager.php @@ -9,7 +9,6 @@ use Drupal\Component\Plugin\Factory\DefaultFactory; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Entity\Field\FieldItemListInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageManager; use Drupal\Core\Plugin\DefaultPluginManager; @@ -205,41 +204,4 @@ return isset($info['settings']) ? $info['settings'] : array(); } - /** - * @todo Document. - */ - public function baseFieldForm(FieldItemListInterface $field, array &$form, array &$form_state) { - $options = array( - 'field_definition' => $field->getFieldDefinition(), - 'form_mode' => 'default', - 'configuration' => array(), - ); - if (($field_data_definition = $field->getDefinition()) && isset($field_data_definition['default_widget'])) { - $options['configuration']['type'] = $field_data_definition['default_widget']; - } - $widget = $this->getInstance($options); - - $form += array('#parents' => array()); - $result = $widget->form($field, $form, $form_state); - $field_name = $field->getFieldDefinition()->getFieldName(); - return isset($result[$field_name]) ? $result[$field_name] : array(); - } - - /** - * @todo Document. - */ - public function baseFieldExtractFormValues(FieldItemListInterface $field, array &$form, array &$form_state) { - $options = array( - 'field_definition' => $field->getFieldDefinition(), - 'form_mode' => 'default', - 'configuration' => array(), - ); - if (($field_data_definition = $field->getDefinition()) && isset($field_data_definition['default_widget'])) { - $options['configuration']['type'] = $field_data_definition['default_widget']; - } - $widget = $this->getInstance($options); - - $widget->extractFormValues($field, $form, $form_state); - } - } diff -u b/core/modules/edit/lib/Drupal/edit/EditController.php b/core/modules/edit/lib/Drupal/edit/EditController.php --- b/core/modules/edit/lib/Drupal/edit/EditController.php +++ b/core/modules/edit/lib/Drupal/edit/EditController.php @@ -26,7 +26,6 @@ use Drupal\edit\Ajax\MetadataCommand; use Drupal\edit\Form\EditFieldForm; use Drupal\user\TempStoreFactory; -use Drupal\field\FieldInstanceInterface; /** * Returns responses for Edit module routes. @@ -218,14 +217,7 @@ // The form submission saved the entity in tempstore. Return the // updated view of the field from the tempstore copy. $entity = $this->tempStoreFactory->get('edit')->get($entity->uuid()); - - $field = $entity->get($field_name); - if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { - $output = field_view_field($entity, $field_name, $view_mode_id, $langcode); - } - else { - $output = \Drupal::service('plugin.manager.field.formatter')->viewBaseField($field); - } + $output = field_view_field($entity, $field_name, $view_mode_id, $langcode); $response->addCommand(new FieldFormSavedCommand(drupal_render($output))); } diff -u b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php --- b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php +++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php @@ -15,7 +15,6 @@ use Drupal\Core\Form\FormInterface; use Drupal\user\TempStoreFactory; use Drupal\Core\Entity\EntityChangedInterface; -use Drupal\field\FieldInstanceInterface; /** * Builds and process a form for editing a single entity field. @@ -88,13 +87,7 @@ } // Add the field form. - $field = $entity->get($field_name); - if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { - field_attach_form($form_state['entity'], $form, $form_state, $form_state['langcode'], array('field_name' => $form_state['field_name'])); - } - else { - $form[$field_name] = \Drupal::service('plugin.manager.field.widget')->baseFieldForm($field, $form, $form_state, $form_state['langcode']); - } + field_attach_form($form_state['entity'], $form, $form_state, $form_state['langcode'], array('field_name' => $form_state['field_name'])); // Add a dummy changed timestamp field to attach form errors to. if ($entity instanceof EntityChangedInterface) { @@ -135,18 +128,8 @@ $form_state['field_name'] = $field_name; // @todo Allow the usage of different form modes by exposing a hook and the - // UI for them. - $form_display = entity_get_render_form_display($entity, 'default'); - - // Let modules alter the form display. - $form_display_context = array( - 'entity_type' => $entity->entityType(), - 'bundle' => $entity->bundle(), - 'form_mode' => 'default', - ); - $this->moduleHandler->alter('entity_form_display', $form_display, $form_display_context); - - $form_state['form_display'] = $form_display; + // UI for them. + $form_state['form_display'] = entity_get_render_form_display($entity, 'default'); } /** @@ -154,14 +137,7 @@ */ public function validateForm(array &$form, array &$form_state) { $entity = $this->buildEntity($form, $form_state); - $field_name = $form_state['field_name']; - $field = $entity->get($field_name); - if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { - field_attach_form_validate($entity, $form, $form_state, array('field_name' => $field_name)); - } - else { - // @todo - } + field_attach_form_validate($entity, $form, $form_state, array('field_name' => $form_state['field_name'])); // Do validation on the changed field as well and assign the error to the // dummy form element we added for this. We don't know the name of this @@ -194,20 +170,14 @@ */ protected function buildEntity(array $form, array &$form_state) { $entity = clone $form_state['entity']; - $field_name = $form_state['field_name']; - $items = $entity->get($field_name); - if ($items->getFieldDefinition() instanceof FieldInstanceInterface) { - field_attach_extract_form_values($entity, $form, $form_state, array('field_name' => $field_name)); - } - else { - \Drupal::service('plugin.manager.field.widget')->baseFieldExtractFormValues($items, $form, $form_state); - } + + field_attach_extract_form_values($entity, $form, $form_state, array('field_name' => $field_name)); // @todo Refine automated log messages and abstract them to all entity // types: http://drupal.org/node/1678002. if ($entity->entityType() == 'node' && $entity->isNewRevision() && !isset($entity->log)) { - $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $items->getFieldDefinition()->getFieldLabel())); + $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $entity->get($field_name)->getFieldDefinition()->getFieldLabel())); } return $entity; reverted: --- b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php +++ a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php @@ -77,13 +77,7 @@ } // Early-return if no editor is available. + $formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($field_name)->getPluginId(); - if ($field_definition instanceof FieldInstanceInterface) { - $formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($field_name)->getPluginId(); - } - else { - $field_type_info = field_info_field_types($field_definition->getFieldType()); - $formatter_id = $field_type_info['default_formatter']; - } $items = $entity->getTranslation($langcode)->get($field_name)->getValue(); $editor_id = $this->editorSelector->getEditor($formatter_id, $field_definition, $items); if (!isset($editor_id)) { diff -u b/core/modules/field/field.module b/core/modules/field/field.module --- b/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -4,6 +4,7 @@ * Attach custom data fields to Drupal entities. */ +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Template\Attribute; use Drupal\field\FieldInterface; @@ -478,7 +479,7 @@ * The function takes care of invoking the prepare_view steps. It also respects * field access permissions. * - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity containing the field to display. * @param $field_name * The name of the field to display. @@ -511,16 +512,16 @@ * * @see field_view_value() */ -function field_view_field(EntityInterface $entity, $field_name, $display_options = array(), $langcode = NULL) { +function field_view_field(ContentEntityInterface $entity, $field_name, $display_options = array(), $langcode = NULL) { $output = array(); $bundle = $entity->bundle(); $entity_type = $entity->entityType(); // Return nothing if the field doesn't exist. - $instance = field_info_instance($entity_type, $field_name, $bundle); - if (!$instance) { + if (!$entity->hasField($field_name)) { return $output; } + $field_definition = $entity->get($field_name)->getFieldDefinition(); // Get the formatter object. if (is_string($display_options)) { @@ -531,11 +532,10 @@ $view_mode = '_custom'; // hook_field_attach_display_alter() needs to receive the 'prepared' // $display_options, so we cannot let preparation happen internally. - $field = field_info_field($entity_type, $field_name); $formatter_manager = drupal_container()->get('plugin.manager.field.formatter'); - $display_options = $formatter_manager->prepareConfiguration($field->getFieldType(), $display_options); + $display_options = $formatter_manager->prepareConfiguration($field_definition->getFieldType(), $display_options); $formatter = $formatter_manager->getInstance(array( - 'field_definition' => $instance, + 'field_definition' => $field_definition, 'view_mode' => $view_mode, 'prepare' => FALSE, 'configuration' => $display_options, @@ -543,7 +543,14 @@ } if ($formatter) { - $display_langcode = field_language($entity, $field_name, $langcode); + // @todo Unify language fallback handling between configurable and base + // fields. + if ($field_definition instanceof FieldInstanceInterface) { + $display_langcode = field_language($entity, $field_name, $langcode); + } + else { + $display_langcode = $entity->language()->id; + } // Invoke the formatter's prepareView() and view() methods. $items = $entity->getTranslation($display_langcode)->get($field_name); diff -u b/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php --- b/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -99,12 +99,6 @@ '#default_value' => $node->getChangedTime(), ); - $node_type = node_type_load($node->getType()); - if ($node_type->has_title) { - $form['title'] = \Drupal::service('plugin.manager.field.widget')->baseFieldForm($node->title, $form, $form_state, $this->getFormLangcode($form_state)); - $form['title']['#weight'] = -5; - } - $language_configuration = module_invoke('language', 'get_default_configuration', 'node', $node->getType()); $form['langcode'] = array( '#title' => t('Language'), @@ -431,26 +425,26 @@ * {@inheritdoc} */ public function buildEntity(array $form, array &$form_state) { - $node = parent::buildEntity($form, $form_state); + $entity = parent::buildEntity($form, $form_state); // A user might assign the node author by entering a user name in the node // form, which we then need to translate to a user ID. if (!empty($form_state['values']['name']) && $account = user_load_by_name($form_state['values']['name'])) { - $node->setAuthorId($account->id()); + $entity->setAuthorId($account->id()); } else { - $node->setAuthorId(0); + $entity->setAuthorId(0); } if (!empty($form_state['values']['date']) && $form_state['values']['date'] instanceOf DrupalDateTime) { - $node->setCreatedTime($form_state['values']['date']->getTimestamp()); + $entity->setCreatedTime($form_state['values']['date']->getTimestamp()); } else { - $node->setCreatedTime(REQUEST_TIME); + $entity->setCreatedTime(REQUEST_TIME); } - \Drupal::service('plugin.manager.field.widget')->baseFieldExtractFormValues($node->title, $form, $form_state); - return $node; + return $entity; } + /** * Overrides Drupal\Core\Entity\EntityFormController::save(). */ diff -u b/core/modules/node/node.module b/core/modules/node/node.module --- b/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -19,6 +19,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Template\Attribute; use Drupal\entity\Entity\EntityDisplay; +use Drupal\entity\Entity\EntityFormDisplay; use Drupal\file\Entity\File; use Drupal\user\UserInterface; @@ -191,14 +192,40 @@ * Implements hook_entity_display_alter(). */ function node_entity_display_alter(EntityDisplay $display, $context) { - // Hide field labels in search index. - if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') { - foreach ($display->getComponents() as $name => $options) { - if (isset($options['label'])) { - $options['label'] = 'hidden'; - $display->setComponent($name, $options); + if ($context['entity_type'] == 'node') { + // Hide field labels in search index. + if ($context['view_mode'] == 'search_index') { + foreach ($display->getComponents() as $name => $options) { + if (isset($options['label'])) { + $options['label'] = 'hidden'; + $display->setComponent($name, $options); + } } } + // @todo Manage base field displays in the YAML. + $display->setComponent('title', array( + 'label' => 'hidden', + 'type' => 'text_default', + )); + } +} + +/** + * Implements hook_entity_form_display_alter(). + */ +function node_entity_form_display_alter(EntityFormDisplay $form_display, $context) { + if ($context['entity_type'] == 'node') { + // @todo Manage base field displays in the YAML. + $node_type = node_type_load($context['bundle']); + if ($node_type->has_title) { + // Title is also registered in node_field_extra_fields(). + $options = $form_display->getComponent('title') ?: array('weight' => -5); + $options['type'] = 'text_textfield'; + $form_display->setComponent('title', $options); + } + else { + $form_display->removeComponent('title'); + } } } @@ -640,7 +667,8 @@ $uri = $node->uri(); $variables['node_url'] = url($uri['path'], $uri['options']); - $variables['label'] = Drupal::service('plugin.manager.field.formatter')->viewBaseField($node->get('title')); + $variables['label'] = $variables['elements']['title']; + unset($variables['elements']['title']); $variables['page'] = $variables['view_mode'] == 'full' && node_is_page($node); // Helpful $content variable for templates. only in patch2: unchanged: --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -723,6 +723,14 @@ function entity_get_render_display(EntityInterface $entity, $view_mode) { $display = entity_get_display($entity_type, $bundle, $render_view_mode); $display->originalMode = $view_mode; + // Let modules alter the display. + $display_context = array( + 'entity_type' => $entity_type, + 'bundle' => $bundle, + 'view_mode' => $view_mode, + ); + drupal_alter('entity_display', $display, $display_context); + return $display; } @@ -823,6 +831,14 @@ function entity_get_render_form_display(EntityInterface $entity, $form_mode) { $form_display = entity_get_form_display($entity_type, $bundle, $render_form_mode); $form_display->originalMode = $form_mode; + // Let modules alter the form display. + $form_display_context = array( + 'entity_type' => $entity_type, + 'bundle' => $bundle, + 'form_mode' => $form_mode, + ); + drupal_alter('entity_form_display', $form_display, $form_display_context); + return $form_display; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/EntityFormController.php +++ b/core/lib/Drupal/Core/Entity/EntityFormController.php @@ -125,15 +125,6 @@ protected function init(array &$form_state) { $this->prepareEntity(); $form_display = entity_get_render_form_display($this->entity, $this->getOperation()); - - // Let modules alter the form display. - $form_display_context = array( - 'entity_type' => $this->entity->entityType(), - 'bundle' => $this->entity->bundle(), - 'form_mode' => $this->getOperation(), - ); - $this->moduleHandler->alter('entity_form_display', $form_display, $form_display_context); - $this->setFormDisplay($form_display, $form_state); // Invoke the prepare form hooks. only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/EntityRenderController.php +++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php @@ -176,20 +176,9 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la // Store entities for rendering by view_mode. $view_modes[$entity_view_mode][$entity->id()] = $entity; - // Load the corresponding display settings if not stored yet. + // Get the corresponding display settings. if (!isset($displays[$entity_view_mode][$bundle])) { - // Get the display object for this bundle and view mode. - $display = entity_get_render_display($entity, $entity_view_mode); - - // Let modules alter the display. - $display_context = array( - 'entity_type' => $this->entityType, - 'bundle' => $bundle, - 'view_mode' => $entity_view_mode, - ); - drupal_alter('entity_display', $display, $display_context); - - $displays[$entity_view_mode][$bundle] = $display; + $displays[$entity_view_mode][$bundle] = entity_get_render_display($entity, $entity_view_mode); } } only in patch2: unchanged: --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php @@ -53,9 +53,8 @@ public function getRenderer($field_name) { // Instantiate the formatter object from the stored display properties. if ($configuration = $this->getComponent($field_name)) { - $instance = field_info_instance($this->targetEntityType, $field_name, $this->bundle); $formatter = $this->pluginManager->getInstance(array( - 'field_definition' => $instance, + 'field_definition' => $this->getFieldDefinition($field_name), 'view_mode' => $this->originalMode, // No need to prepare, defaults have been merged in setComponent(). 'prepare' => FALSE, only in patch2: unchanged: --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php @@ -53,9 +53,8 @@ public function getRenderer($field_name) { // Instantiate the widget object from the stored display properties. if ($configuration = $this->getComponent($field_name)) { - $instance = field_info_instance($this->targetEntityType, $field_name, $this->bundle); $widget = $this->pluginManager->getInstance(array( - 'field_definition' => $instance, + 'field_definition' => $this->getFieldDefinition($field_name), 'form_mode' => $this->originalMode, // No need to prepare, defaults have been merged in setComponent(). 'prepare' => FALSE, only in patch2: unchanged: --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php @@ -8,6 +8,7 @@ namespace Drupal\entity; use Drupal\Core\Config\Entity\ConfigEntityBase; +use Drupal\Core\Entity\ContentEntityInterface; /** * Base class for config entity types that store configuration for entity forms @@ -44,6 +45,16 @@ public $bundle; /** + * A partial entity, created via _field_create_entity_from_ids() from + * $targetEntityType and $bundle. + * + * @var \Drupal\Core\Entity\EntityInterface + * + * @todo Remove when getFieldDefinition() is fixed to not need it. + */ + private $targetEntity; + + /** * View or form mode to be displayed. * * @var string @@ -194,9 +205,7 @@ public function getComponent($name) { // visibility. if (isset($this->content[$name])) { if ($this->content[$name]['visible']) { - return array( - 'weight' => $this->content[$name]['weight'], - ); + return $this->content[$name]; } else { return NULL; @@ -231,8 +240,8 @@ public function setComponent($name, array $options = array()) { $options['weight'] = isset($max) ? $max + 1 : 0; } - if ($instance = field_info_instance($this->targetEntityType, $name, $this->bundle)) { - $options = $this->pluginManager->prepareConfiguration($instance->getFieldType(), $options); + if ($field_definition = $this->getFieldDefinition($name)) { + $options = $this->pluginManager->prepareConfiguration($field_definition->getFieldType(), $options); // Clear the persisted plugin, if any. unset($this->plugins[$name]); @@ -290,4 +299,17 @@ public function getHighestWeight() { return $weights ? max($weights) : NULL; } + /** + * Returns the field definition of a field. + */ + protected function getFieldDefinition($field_name) { + // @todo Replace this entire implementation with + // \Drupal::entityManager()->getFieldDefinition() after [#2047229] lands. + if (!isset($this->targetEntity)) { + $this->targetEntity = _field_create_entity_from_ids((object) array('entity_type' => $this->targetEntityType, 'bundle' => $this->bundle, 'entity_id' => NULL)); + } + if (($this->targetEntity instanceof ContentEntityInterface) && $this->targetEntity->hasField($field_name)) { + return $this->targetEntity->get($field_name)->getFieldDefinition(); + } + } } only in patch2: unchanged: --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -6,7 +6,9 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; use Drupal\entity\Entity\EntityFormDisplay; +use Drupal\field\FieldInstanceInterface; /** * @defgroup field_attach Field Attach API @@ -63,7 +65,7 @@ * @param string $method * The name of the method to invoke. * @param callable $target_function - * A function that receives an $instance object and returns the object on + * A function that receives a field definition and returns the object on * which the method should be invoked. * @param \Drupal\Core\Entity\EntityInterface $entity * The fully formed $entity_type entity. @@ -100,27 +102,31 @@ function field_invoke_method($method, $target_function, EntityInterface $entity, $options += $default_options; $entity_type = $entity->entityType(); - // Determine the list of instances to iterate on. - $instances = _field_invoke_get_instances($entity_type, $entity->bundle(), $options); + // Determine the list of fields to iterate on. + $field_definitions = _field_invoke_get_field_definitions($entity_type, $entity->bundle(), $options); - // Iterate through the instances and collect results. + // Iterate through the fields and collect results. $return = array(); - foreach ($instances as $instance) { + foreach ($field_definitions as $field_definition) { // Let the function determine the target object on which the method should be // called. - $target = call_user_func($target_function, $instance); + $target = call_user_func($target_function, $field_definition); if (method_exists($target, $method)) { - $field = $instance->getField(); - $field_name = $field->getFieldName(); - // Determine the list of languages to iterate on. - $available_langcodes = field_available_languages($entity_type, $field); - $langcodes = _field_language_suggestion($available_langcodes, $options['langcode'], $field_name); + // @todo Unify language fallback handling between configurable and base + // fields. + if ($field_definition instanceof FieldInstanceInterface) { + $available_langcodes = field_available_languages($entity_type, $field_definition->getField()); + $langcodes = _field_language_suggestion($available_langcodes, $options['langcode'], $field_definition->getFieldName()); + } + else { + $langcodes = array($entity->language()->id); + } foreach ($langcodes as $langcode) { - $items = $entity->getTranslation($langcode)->get($field_name); + $items = $entity->getTranslation($langcode)->get($field_definition->getFieldName()); $items->filterEmptyValues(); $result = $target->$method($items, $a, $b); @@ -198,7 +204,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities $entity_type = $entity->entityType(); // Determine the list of instances to iterate on. - $entity_instances = _field_invoke_get_instances($entity_type, $entity->bundle(), $options); + $entity_instances = _field_invoke_get_field_definitions($entity_type, $entity->bundle(), $options); foreach ($entity_instances as $instance) { $instance_uuid = $instance->uuid(); @@ -260,7 +266,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities } /** - * Retrieves a list of instances to operate on. + * Retrieves a list of field definitions to operate on. * * Helper for field_invoke_method(). * @@ -277,9 +283,9 @@ function field_invoke_method_multiple($method, $target_function, array $entities * See field_invoke_method() for details. * * @return - * The array of selected instance definitions. + * The array of selected field definitions. */ -function _field_invoke_get_instances($entity_type, $bundle, $options) { +function _field_invoke_get_field_definitions($entity_type, $bundle, $options) { if ($options['deleted']) { // Deleted fields are not included in field_info_instances(), and need to // be fetched from the database with field_read_instances(). @@ -290,12 +296,24 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) { // option. $params['field_id'] = $options['field_id']; } - $instances = field_read_instances($params, array('include_deleted' => TRUE)); + $field_definitions = field_read_instances($params, array('include_deleted' => TRUE)); } elseif (isset($options['field_name'])) { - // Single-field mode by field name: field_info_instance() does the - // filtering. - $instances = array(field_info_instance($entity_type, $options['field_name'], $bundle)); + // @todo Replace with \Drupal::entityManager()->getFieldDefinition() after + // [#2047229] lands. + $entity = _field_create_entity_from_ids((object) array('entity_type' => $entity_type, 'bundle' => $bundle, 'entity_id' => NULL)); + $field_definitions = array($entity->get($options['field_name'])->getFieldDefinition()); + } + elseif (isset($options['display'])) { + // @todo Replace with \Drupal::entityManager()->getFieldDefinitions() after + // [#2047229] lands. + $entity = _field_create_entity_from_ids((object) array('entity_type' => $entity_type, 'bundle' => $bundle, 'entity_id' => NULL)); + $field_definitions = array(); + foreach ($options['display']->getComponents() as $name => $component_options) { + if ($entity->hasField($name)) { + $field_definitions[] = $entity->get($name)->getFieldDefinition(); + } + } } else { $instances = field_info_instances($entity_type, $bundle); @@ -309,15 +327,16 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) { } } } + $field_definitions = $instances; } - return $instances; + return $field_definitions; } /** * Defines a 'target function' for field_invoke_method(). * - * Used to invoke methods on an instance's widget. + * Used to invoke methods on a field's widget. * * @param \Drupal\entity\Entity\EntityFormDisplay $form_display * An EntityFormDisplay object. @@ -326,8 +345,8 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) { * A 'target function' for field_invoke_method(). */ function _field_invoke_widget_target($form_display) { - return function ($instance) use ($form_display) { - return $form_display->getRenderer($instance->getFieldName()); + return function (FieldDefinitionInterface $field_definition) use ($form_display) { + return $form_display->getRenderer($field_definition->getFieldName()); }; } only in patch2: unchanged: --- a/core/modules/field/field.deprecated.inc +++ b/core/modules/field/field.deprecated.inc @@ -7,10 +7,10 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; use Drupal\entity\Entity\EntityDisplay; use Drupal\field\Field; - /** * Returns information about field types. * @@ -561,6 +561,7 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc // Get the entity_form_display object for this form. $form_display = $form_state['form_display']; + $options['display'] = $form_display; // If no language is provided use the default site language. $options['langcode'] = field_valid_language($langcode); @@ -628,7 +629,9 @@ function field_attach_form_validate(ContentEntityInterface $entity, $form, &$for if ($has_violations) { // Map errors back to form elements. - field_invoke_method('flagErrors', _field_invoke_widget_target($form_state['form_display']), $entity, $form, $form_state, $options); + $form_display = $form_state['form_display']; + $options['display'] = $form_display; + field_invoke_method('flagErrors', _field_invoke_widget_target($form_display), $entity, $form, $form_state, $options); } } @@ -655,6 +658,7 @@ function field_attach_form_validate(ContentEntityInterface $entity, $form, &$for function field_attach_extract_form_values(EntityInterface $entity, $form, &$form_state, array $options = array()) { // Extract field values from submitted values. $form_display = $form_state['form_display']; + $options['display'] = $form_display; field_invoke_method('extractFormValues', _field_invoke_widget_target($form_display), $entity, $form, $form_state, $options); // Let other modules act on submitting the entity. @@ -754,14 +758,15 @@ function field_attach_prepare_view($entity_type, array $entities, array $display * @deprecated as of Drupal 8.0. Use the entity system instead. */ function field_attach_view(EntityInterface $entity, EntityDisplay $display, $langcode = NULL, array $options = array()) { + $options['display'] = $display; // Determine the actual language code to display for each field, given the // language codes available in the field data. $options['langcode'] = field_language($entity, NULL, $langcode); - // For each instance, call the view() method on the formatter object handed + // For each field, call the view() method on the formatter object handed // by the entity display. - $target_function = function ($instance) use ($display) { - return $display->getRenderer($instance->getFieldName()); + $target_function = function (FieldDefinitionInterface $field_definition) use ($display) { + return $display->getRenderer($field_definition->getFieldName()); }; $null = NULL; $output = field_invoke_method('view', $target_function, $entity, $null, $null, $options);