diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index c12e4db..fbf6271 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -279,6 +279,29 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter } /** + * Alters the settings used for displaying an entity. + * + * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display + * The entity_display object that will be used to display the entity + * components. + * @param array $context + * An associative array containing: + * - entity_type: The entity type, e.g., 'node' or 'user'. + * - bundle: The bundle, e.g., 'page' or 'article'. + * - view_mode: The view mode, e.g. 'full', 'teaser'... + */ +function hook_entity_display_alter(Drupal\field\Plugin\Core\Entity\EntityDisplay $display, array $context) { + // Leave field labels out of the search index. + if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') { + foreach ($display->content as $name => &$properties) { + if (isset($properties['label'])) { + $properties['label'] = 'hidden'; + } + } + } +} + +/** * Define custom entity properties. * * @param string $entity_type diff --git a/core/includes/entity.inc b/core/includes/entity.inc index a866864..d4ca7a5 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -564,6 +564,128 @@ function entity_view_multiple(array $entities, $view_mode, $langcode = NULL) { } /** + * Returns the entity_display object associated to a bundle and view mode. + * + * Use this function when assigning suggested display options for a component + * in a given view mode. Note that they will only be actually used at render + * time if the view mode itself is configured to use dedicated display settings + * for the bundle; if not, the 'default' display is used instead. + * + * The function reads the entity_display object from the current configuration, + * or returns a ready-to-use empty one if configuration entry exists yet for + * this bundle and view mode. This streamlines manipulation of display objects + * by always returning a consistent object that reflects the current state of + * the configuration. + * + * Example usage: + * - Set the 'body' field to be displayed and the 'field_image' field to be + * hidden on article nodes in the 'default' display. + * @code + * entity_get_display('article', 'node', 'default') + * ->setComponent('body', array( + * 'type' => 'text_summary_or_trimmed', + * 'settings' => array('trim_length' => '200') + * 'weight' => 1, + * )) + * ->removeComponent('field_image') + * ->save(); + * @endcode + * + * @param string $entity_type + * The entity type. + * @param string $bundle + * The bundle. + * @param string $view_mode + * The view mode, or 'default' to retrieve the 'default' display object for + * this bundle. + * + * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay + * The display object associated to the view mode. + */ +function entity_get_display($entity_type, $bundle, $view_mode) { + // Try loading the display from configuration. + $display = entity_load('entity_display', $entity_type . '.' . $bundle . '.' . $view_mode); + + // If not found, create a fresh display object. We do not preemptively create + // new entity_display configuration entries for each existing entity type and + // bundle whenever a new view mode becomes available. Instead, configuration + // entries are only created when a display object is explicitly configured + // and saved. + if (!$display) { + $display = entity_create('entity_display', array( + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'viewMode' => $view_mode, + )); + } + + return $display; +} + +/** + * Returns the entity_display object used to render an entity. + * + * Depending on the configuration of the view mode for the bundle, this can be + * either the display object associated to the view mode, or the 'default' + * display. + * + * This function should only be used internally when rendering an entity. When + * assigning suggested display options for a component in a given view mode, + * entity_get_display() should be used instead, in order to avoid inadvertently + * modifying the output of other view modes that might happen to use the + * 'default' display too. Those options will then be effectively applied only + * if the view mode is configured to use them. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity being rendered. + * @param string $view_mode + * The view mode being rendered. + * + * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay + * The display object that should be used to render the entity. + * + * @see entity_get_render_display(). + */ +function entity_get_render_display(EntityInterface $entity, $view_mode) { + $entity_type = $entity->entityType(); + $bundle = $entity->bundle(); + + // Determine the display to use for rendering this entity. Depending on the + // configuration of the view mode for this bundle, this will be either the + // display associated to the view mode, or the 'default' display. + $view_mode_settings = field_view_mode_settings($entity_type, $bundle); + $render_view_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default'; + + $display = entity_get_display($entity_type, $bundle, $render_view_mode); + $display->originalViewMode = $view_mode; + + return $display; +} + +/** + * Adjusts weights and visibility of components in displayed entities. + * + * This is used as a #pre_render callback. + */ +function _entity_view_pre_render($elements) { + $display = $elements['#entity_display']; + + $extra_fields = field_info_extra_fields($display->targetEntityType, $display->bundle, 'display'); + foreach (array_keys($extra_fields) as $name) { + if (isset($elements[$name]) && (!isset($elements[$name]['#access']) || $elements[$name]['#access'])) { + if ($options = $display->getComponent($name)) { + $elements[$name]['#weight'] = $options['weight']; + } + else { + $elements[$name]['#access'] = FALSE; + } + } + } + + return $elements; +} + +/** * Returns the entity query object for this entity type. * * @param $entity_type diff --git a/core/lib/Drupal/Core/Entity/EntityRenderController.php b/core/lib/Drupal/Core/Entity/EntityRenderController.php index 2cd0578..eb3147e 100644 --- a/core/lib/Drupal/Core/Entity/EntityRenderController.php +++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php @@ -30,37 +30,64 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la // Allow modules to change the view mode. $context = array('langcode' => $langcode); - $prepare = array(); - foreach ($entities as $key => $entity) { + $view_modes = array(); + $displays = array(); + + foreach ($entities as $entity) { // Remove previously built content, if exists. $entity->content = array(); drupal_alter('entity_view_mode', $view_mode, $entity, $context); $entity->content['#view_mode'] = $view_mode; - $prepare[$view_mode][$key] = $entity; + $view_modes[$view_mode][$entity->id()] = $entity; + + $bundle = $entity->bundle(); + + // Load the corresponding display settings if not stored yet. + if (!isset($displays[$view_mode][$bundle])) { + // Get the display object to use for rendering the entity.. + $display = entity_get_render_display($entity, $view_mode); + + // Let modules alter the display. + // Note: if config entities get a static cache at some point, the + // objects should be cloned before running drupal_alter(). + $display_context = array( + 'entity_type' => $this->entityType, + 'bundle' => $bundle, + 'view_mode' => $view_mode, + ); + drupal_alter('entity_display', $display, $display_context); + + $displays[$view_mode][$bundle] = $display; + } + + // Assigning weights to 'extra fields' is done in a pre_render callback. + $entity->content['#pre_render'] = array('_entity_view_pre_render'); + $entity->content['#entity_display'] = $displays[$view_mode][$bundle]; } // Prepare and build field content, grouped by view mode. - foreach ($prepare as $view_mode => $prepare_entities) { - $call = array(); + foreach ($view_modes as $view_mode => $view_mode_entities) { + $call_prepare = array(); // To ensure hooks are only run once per entity, check for an - // entity_view_prepared flag and only process items without it. - foreach ($prepare_entities as $entity) { - if (empty($entity->entity_view_prepared)) { + // entity_view_prepared flag and only process relevant entities. + foreach ($view_mode_entities as $entity) { + if (empty($entity->entity_view_prepared) || $entity->entity_view_prepared != $view_mode) { // Add this entity to the items to be prepared. - $call[$entity->id()] = $entity; + $call_prepare[$entity->id()] = $entity; - // Mark this item as prepared. - $entity->entity_view_prepared = TRUE; + // Mark this item as prepared for this view mode. + $entity->entity_view_prepared = $view_mode; } } - if (!empty($call)) { - field_attach_prepare_view($this->entityType, $call, $view_mode, $langcode); - module_invoke_all('entity_prepare_view', $call, $this->entityType); + if (!empty($call_prepare)) { + field_attach_prepare_view($this->entityType, $call_prepare, $displays[$view_mode], $langcode); + module_invoke_all('entity_prepare_view', $call_prepare, $this->entityType); } - foreach ($entities as $entity) { - $entity->content += field_attach_view($this->entityType, $entity, $view_mode, $langcode); + + foreach ($view_mode_entities as $entity) { + $entity->content += field_attach_view($this->entityType, $entity, $displays[$view_mode][$entity->bundle()], $langcode); } } } diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index f89d149..b73857c 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -376,15 +376,15 @@ function _comment_body_field_create($info) { 'bundle' => 'comment_node_' . $info->type, 'settings' => array('text_processing' => 1), 'required' => TRUE, - 'display' => array( - 'default' => array( - 'label' => 'hidden', - 'type' => 'text_default', - 'weight' => 0, - ), - ), ); field_create_instance($instance); + entity_get_display('comment', 'comment_node_' . $info->type, 'default') + ->setComponent('comment_body', array( + 'label' => 'hidden', + 'type' => 'text_default', + 'weight' => 0, + )) + ->save(); } } diff --git a/core/modules/contact/lib/Drupal/contact/MessageRenderController.php b/core/modules/contact/lib/Drupal/contact/MessageRenderController.php index 3044a85..7a1db0d 100644 --- a/core/modules/contact/lib/Drupal/contact/MessageRenderController.php +++ b/core/modules/contact/lib/Drupal/contact/MessageRenderController.php @@ -23,9 +23,8 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la foreach ($entities as $entity) { // Add the message extra field, if enabled. - $bundle = $entity->bundle(); $entity_view_mode = $entity->content['#view_mode']; - $fields = field_extra_fields_get_display($this->entityType, $bundle, $entity_view_mode); + $fields = field_extra_fields_get_display($entity, $entity_view_mode); if (!empty($entity->message) && !empty($fields['message']['visible'])) { $entity->content['message'] = array( '#type' => 'item', diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php index 1aca55d..db26798 100644 --- a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php +++ b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php @@ -29,7 +29,7 @@ class EditorSelectionTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'field_test', 'field', 'number', 'text', 'edit', 'edit_test'); + public static $modules = array('system', 'entity', 'field_test', 'field', 'number', 'text', 'edit', 'edit_test'); public static function getInfo() { return array( @@ -103,24 +103,26 @@ function createFieldWithInstance($field_name, $type, $cardinality, $label, $inst 'label' => $label, 'settings' => $widget_settings, ), - 'display' => array( - 'default' => array( - 'label' => 'above', - 'type' => $formatter_type, - 'settings' => $formatter_settings - ), - ), ); field_create_instance($this->$instance); + + entity_get_display('test_entity', 'test_bundle', 'default') + ->setComponent($field_name, array( + 'label' => 'above', + 'type' => $formatter_type, + 'settings' => $formatter_settings + )) + ->save(); } /** * Retrieves the FieldInstance object for the given field and returns the * editor that Edit selects. */ - function getSelectedEditor($items, $field_name, $display = 'default') { + function getSelectedEditor($items, $field_name, $view_mode = 'default') { + $options = entity_get_display('test_entity', 'test_bundle', $view_mode)->getComponent($field_name); $field_instance = field_info_instance('test_entity', $field_name, 'test_bundle'); - return $this->editorSelector->getEditor($field_instance['display'][$display]['type'], $field_instance, $items); + return $this->editorSelector->getEditor($options['type'], $field_instance, $items); } /** diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php index c88f563..37d4ee5 100644 --- a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php +++ b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php @@ -60,13 +60,14 @@ function testEmailField() { 'placeholder' => 'example@example.com', ), ), - 'display' => array( - 'full' => array( - 'type' => 'email_mailto', - ), - ), ); field_create_instance($this->instance); + // Create a display for the full view mode. + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], array( + 'type' => 'email_mailto', + )) + ->save(); // Display creation form. $this->drupalGet('test-entity/add/test_bundle'); @@ -87,7 +88,8 @@ function testEmailField() { // Verify that a mailto link is displayed. $entity = field_test_entity_test_load($id); - $entity->content = field_attach_view('test_entity', $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + $entity->content = field_attach_view('test_entity', $entity, $display); $this->drupalSetContent(drupal_render($entity->content)); $this->assertLinkByHref('mailto:test@example.com'); } diff --git a/core/modules/entity/entity.install b/core/modules/entity/entity.install new file mode 100644 index 0000000..2e1efd7 --- /dev/null +++ b/core/modules/entity/entity.install @@ -0,0 +1,47 @@ +get()) { + return $config; + } + + // Initialize a fresh structure. + $uuid = new Uuid(); + $properties = array( + 'id' => $id, + 'uuid' => $uuid->generate(), + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'viewMode' => $view_mode, + 'content' => array(), + ); + foreach ($properties as $key => $value) { + $config->set($key, $value); + } + return $config; +} diff --git a/core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php b/core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php new file mode 100644 index 0000000..9048788 --- /dev/null +++ b/core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php @@ -0,0 +1,345 @@ +originalViewMode = $this->viewMode; + } + + /** + * Overrides \Drupal\Core\Entity\Entity::id(). + */ + public function id() { + return $this->targetEntityType . '.' . $this->bundle . '.' . $this->viewMode; + } + + /** + * Overrides \Drupal\config\ConfigEntityBase::save(). + */ + public function save() { + // Build an ID if none is set. + if (empty($this->id)) { + $this->id = $this->id(); + } + return parent::save(); + } + + /** + * Overrides \Drupal\config\ConfigEntityBase::getExportProperties(); + */ + public function getExportProperties() { + $names = array( + 'id', + 'uuid', + 'targetEntityType', + 'bundle', + 'viewMode', + 'content', + ); + $properties = array(); + foreach ($names as $name) { + $properties[$name] = $this->get($name); + } + return $properties; + } + + /** + * Creates a duplicate of the EntityDisplay object on a different view mode. + * + * The new object necessarily has the same $targetEntityType and $bundle + * properties than the original one. + * + * @param $view_mode + * The view mode for the new object. + * + * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay + * The new object. + */ + public function createCopy($view_mode) { + $display = $this->createDuplicate(); + $display->viewMode = $display->originalViewMode = $view_mode; + return $display; + } + + /** + * Gets the display options for all components. + * + * @return array + * The array of display options, keyed by component name. + */ + public function getComponents() { + $result = array(); + foreach ($this->content as $name => $options) { + if (!isset($options['visible']) || $options['visible'] === TRUE) { + unset($options['visible']); + $result[$name] = $options; + } + } + return $result; + } + + /** + * Gets the display options set for a component. + * + * @param string $name + * The name of the component. + * + * @return array|null + * The display options for the component, or NULL if the component is not + * displayed. + */ + public function getComponent($name) { + // We always store 'extra fields', whether they are visible or hidden. + $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, 'display'); + if (isset($extra_fields[$name])) { + // If we have explicit settings, return an array or NULL depending on + // visibility. + if (isset($this->content[$name])) { + if ($this->content[$name]['visible']) { + return array( + 'weight' => $this->content[$name]['weight'], + ); + } + else { + return NULL; + } + } + + // If no explicit settings for the extra field, look at the default + // visibility in its definition. + $definition = $extra_fields[$name]; + if (!isset($definition['visible']) || $definition['visible'] == TRUE) { + return array( + 'weight' => $definition['weight'] + ); + } + else { + return NULL; + } + } + + if (isset($this->content[$name])) { + return $this->content[$name]; + } + } + + /** + * Sets the display options for a component. + * + * @param string $name + * The name of the component. + * @param array $options + * The display options. + * + * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay + * The EntityDisplay object. + */ + public function setComponent($name, array $options = array()) { + // If no weight specified, make sure the field sinks at the bottom. + if (!isset($options['weight'])) { + $max = $this->getHighestWeight(); + $options['weight'] = isset($max) ? $max + 1 : 0; + } + + if ($instance = field_info_instance($this->targetEntityType, $name, $this->bundle)) { + $field = field_info_field($instance['field_name']); + $options = drupal_container()->get('plugin.manager.field.formatter')->prepareConfiguration($field['type'], $options); + + // Clear the persisted formatter, if any. + unset($this->formatters[$name]); + } + + // We always store 'extra fields', whether they are visible or hidden. + $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, 'display'); + if (isset($extra_fields[$name])) { + $options['visible'] = TRUE; + } + + $this->content[$name] = $options; + + return $this; + } + + /** + * Sets a component to be hidden. + * + * @param string $name + * The name of the component. + * + * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay + * The EntityDisplay object. + */ + public function removeComponent($name) { + $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, 'display'); + if (isset($extra_fields[$name])) { + // 'Extra fields' are exposed in hooks and can appear at any given time. + // Therefore we store extra fields that are explicitly being hidden, so + // that we can differenciate with those that are simply not configured + // yet. + $this->content[$name] = array( + 'visible' => FALSE, + ); + } + else { + unset($this->content[$name]); + unset($this->formatters[$name]); + } + + return $this; + } + + /** + * Returns the highest weight of the components in the display. + * + * @return int|null + * The highest weight of the components in the display, or NULL if the + * display is empty. + */ + public function getHighestWeight() { + $weights = array(); + + // Collect weights for the components in the display. + foreach ($this->content as $options) { + if (isset($options['weight'])) { + $weights[] = $options['weight']; + } + } + + // Let other modules feedback about their own additions. + $weights = array_merge($weights, module_invoke_all('field_info_max_weight', $this->targetEntityType, $this->bundle, $this->viewMode)); + + return $weights ? max($weights) : NULL; + } + + /** + * Returns the Formatter plugin for a field. + * + * @param string $field_name + * The field name. + * + * @return \Drupal\field\Plugin\Type\Formatter\FormatterInterface + * If the field is not hidden, the Formatter plugin to use for rendering + * it. + */ + public function getFormatter($field_name) { + if (isset($this->formatters[$field_name])) { + return $this->formatters[$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 = drupal_container()->get('plugin.manager.field.formatter')->getInstance(array( + 'instance' => $instance, + 'view_mode' => $this->originalViewMode, + // No need to prepare, defaults have been merged in setComponent(). + 'prepare' => FALSE, + 'configuration' => $configuration + )); + } + else { + $formatter = NULL; + } + + // Persist the formatter object. + $this->formatters[$field_name] = $formatter; + return $formatter; + } + +} diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php new file mode 100644 index 0000000..8b0ce69 --- /dev/null +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php @@ -0,0 +1,201 @@ + 'Entity display configuration entities', + 'description' => 'Tests the entity display configuration entities.', + 'group' => 'Entity API', + ); + } + + protected function setUp() { + parent::setUp(); + + $this->enableModules(array('system', 'entity', 'field')); + } + + /** + * Tests basic CRUD operations on EntityDisplay objects. + */ + public function testEntityDisplayCRUD() { + $display = entity_create('entity_display', array( + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'viewMode' => 'default', + )); + + $expected = array(); + + // Check that providing no 'weight' results in the highest current weight + // being assigned. + $expected['component_1'] = array('weight' => 0); + $expected['component_2'] = array('weight' => 1); + $display->setComponent('component_1'); + $display->setComponent('component_2'); + $this->assertEqual($display->getComponent('component_1'), $expected['component_1']); + $this->assertEqual($display->getComponent('component_2'), $expected['component_2']); + + // Check that arbitrary options are correctly stored. + $expected['component_3'] = array('weight' => 10, 'foo' => 'bar'); + $display->setComponent('component_3', $expected['component_3']); + $this->assertEqual($display->getComponent('component_3'), $expected['component_3']); + + // Check that the display can be properly saved and read back. + $display->save(); + $display = entity_load('entity_display', $display->id()); + foreach (array('component_1', 'component_2', 'component_3') as $name) { + $this->assertEqual($display->getComponent($name), $expected[$name]); + } + + // Check that getComponents() returns options for all components. + $this->assertEqual($display->getComponents(), $expected); + + // Check that a component can be removed. + $display->removeComponent('component_3'); + $this->assertNULL($display->getComponent('component_3')); + + // Check that the removal is correctly persisted. + $display->save(); + $display = entity_load('entity_display', $display->id()); + $this->assertNULL($display->getComponent('component_3')); + + // Check that CreateCopy() creates a new component that can be correclty + // saved. + $new_display = $display->createCopy('other_view_mode'); + $new_display->save(); + $new_display = entity_load('entity_display', $new_display->id()); + $this->assertEqual($new_display->targetEntityType, $display->targetEntityType); + $this->assertEqual($new_display->bundle, $display->bundle); + $this->assertEqual($new_display->viewMode, 'other_view_mode'); + $this->assertEqual($new_display->getComponents(), $display->getComponents()); + } + + /** + * Tests entity_get_display(). + */ + public function testEntityGetDisplay() { + // Check that entity_get_display() returns a fresh object when no + // configuration entry exists. + $display = entity_get_display('entity_test', 'entity_test', 'default'); + $this->assertTrue($display->isNew()); + + // Add some components and save the display. + $display->setComponent('component_1', array('weight' => 10)) + ->save(); + + // Check that entity_get_display() returns the correct object. + $display = entity_get_display('entity_test', 'entity_test', 'default'); + $this->assertFalse($display->isNew()); + $this->assertEqual($display->id, 'entity_test.entity_test.default'); + $this->assertEqual($display->getComponent('component_1'), array('weight' => 10)); + } + + /** + * Tests the behavior of a field component within an EntityDisplay object. + */ + public function testExtraFieldComponent() { + $display = entity_create('entity_display', array( + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'viewMode' => 'default', + )); + + // Check that the default visibility taken into account for extra fields + // unknown in the display. + $this->assertEqual($display->getComponent('display_extra_field'), array('weight' => 5)); + $this->assertNull($display->getComponent('display_extra_field_hidden')); + + // Check that setting explicit options overrides the defaults. + $display->removeComponent('display_extra_field'); + $display->setComponent('display_extra_field_hidden', array('weight' => 10)); + $this->assertNull($display->getComponent('display_extra_field')); + $this->assertEqual($display->getComponent('display_extra_field_hidden'), array('weight' => 10)); + } + + /** + * Tests the behavior of a field component within an EntityDisplay object. + */ + public function testFieldComponent() { + $this->enableModules(array('field_sql_storage', 'field_test')); + + $display = entity_create('entity_display', array( + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'viewMode' => 'default', + )); + + // Create a field and an instance. + $field = array( + 'field_name' => 'test_field', + 'type' => 'test_field' + ); + field_create_field($field); + $instance = array( + 'field_name' => $field['field_name'], + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ); + field_create_instance($instance); + + // Check that providing no options results in default values being used. + $display->setComponent($field['field_name']); + $field_type_info = field_info_field_types($field['type']); + $default_formatter = $field_type_info['default_formatter']; + $default_settings = field_info_formatter_settings($default_formatter); + $expected = array( + 'weight' => 0, + 'label' => 'above', + 'type' => $default_formatter, + 'settings' => $default_settings, + ); + $this->assertEqual($display->getComponent($field['field_name']), $expected); + + // Check that the getFormatter() method returns the correct formatter plugin. + $formatter = $display->getFormatter($field['field_name']); + $this->assertEqual($formatter->getPluginId(), $default_formatter); + $this->assertEqual($formatter->getSettings(), $default_settings); + + // Check that the formatter is statically persisted, by assigning an + // arbitrary property and reading it back. + $random_value = $this->randomString(); + $formatter->randomValue = $random_value; + $formatter = $display->getFormatter($field['field_name']); + $this->assertEqual($formatter->randomValue, $random_value ); + + // Check that changing the definition creates a new formatter. + $display->setComponent($field['field_name'], array( + 'type' => 'field_test_multiple', + )); + $formatter = $display->getFormatter($field['field_name']); + $this->assertEqual($formatter->getPluginId(), 'field_test_multiple'); + $this->assertFalse(isset($formatter->randomValue)); + + // Check that specifying an unknown formatter (e.g. case of a disabled + // module) gets stored as is in the display, but results in the default + // formatter being used. + $display->setComponent($field['field_name'], array( + 'type' => 'unknown_formatter', + )); + $options = $display->getComponent($field['field_name']); + $this->assertEqual($options['type'], 'unknown_formatter'); + $formatter = $display->getFormatter($field['field_name']); + $this->assertEqual($formatter->getPluginId(), $default_formatter); + } + +} diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php index 2620844..c97c6ef 100644 --- a/core/modules/field/field.api.php +++ b/core/modules/field/field.api.php @@ -1105,12 +1105,13 @@ function hook_field_attach_purge($entity_type, $entity, $field, $instance) { * - entity_type: The type of $entity; for example, 'node' or 'user'. * - entity: The entity with fields to render. * - view_mode: View mode; for example, 'full' or 'teaser'. - * - display: Either a view mode string or an array of display settings. If - * this hook is being invoked from field_attach_view(), the 'display' - * element is set to the view mode string. If this hook is being invoked - * from field_view_field(), this element is set to the $display argument and - * the view_mode element is set to '_custom'. See field_view_field() for - * more information on what its $display argument contains. + * - display_options: Either a view mode string or an array of display + * options. If this hook is being invoked from field_attach_view(), the + * 'display_options' element is set to the view mode string. If this hook + * is being invoked from field_view_field(), this element is set to the + * $display_options argument and the view_mode element is set to '_custom'. + * See field_view_field() for more information on what its $display_options + * argument contains. * - language: The language code used for rendering. */ function hook_field_attach_view_alter(&$output, $context) { @@ -1943,94 +1944,6 @@ function hook_field_info_max_weight($entity_type, $bundle, $context) { } /** - * Alters the display settings of a field before it is displayed. - * - * Note that instead of hook_field_display_alter(), which is called for all - * fields on all entity types, hook_field_display_ENTITY_TYPE_alter() may be - * used to alter display settings for fields on a specific entity type only. - * - * This hook is called once per field per displayed entity. If the result of the - * hook involves reading from the database, it is highly recommended to - * statically cache the information. - * - * @param array $display_properties - * The display settings that will be used to display the field values, as - * found in the 'display' key of $instance definitions. - * @param array $context - * An associative array containing: - * - entity_type: The entity type, e.g., 'node' or 'user'. - * - bundle: The bundle, e.g., 'page' or 'article'. - * - field: The field being rendered. - * - instance: The instance being rendered. - * - view_mode: The view mode, e.g. 'full', 'teaser'... - * - * @see hook_field_display_ENTITY_TYPE_alter() - */ -function hook_field_display_alter(array &$display_properties, array $context) { - // Leave field labels out of the search index. - // Note: The check against $context['entity_type'] == 'node' could be avoided - // by using hook_field_display_node_alter() instead of - // hook_field_display_alter(), resulting in less function calls when - // rendering non-node entities. - if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') { - $display_properties['label'] = 'hidden'; - } -} - -/** - * Alters the display settings of a field before it is displayed. - * - * Modules can implement hook_field_display_ENTITY_TYPE_alter() to alter display - * settings for fields on a specific entity type, rather than implementing - * hook_field_display_alter(). - * - * This hook is called once per field per displayed entity. If the result of the - * hook involves reading from the database, it is highly recommended to - * statically cache the information. - * - * @param array $display_properties - * The display settings that will be used to display the field values, as - * found in the 'display' key of $instance definitions. - * @param array $context - * An associative array containing: - * - entity_type: The entity type, e.g., 'node' or 'user'. - * - bundle: The bundle, e.g., 'page' or 'article'. - * - field: The field being rendered. - * - instance: The instance being rendered. - * - view_mode: The view mode, e.g. 'full', 'teaser'... - * - * @see hook_field_display_alter() - */ -function hook_field_display_ENTITY_TYPE_alter(array &$display_properties, array $context) { - // Leave field labels out of the search index. - if ($context['view_mode'] == 'search_index') { - $display_properties['label'] = 'hidden'; - } -} - -/** - * Alters the display settings of pseudo-fields before an entity is displayed. - * - * This hook is called once per displayed entity. If the result of the hook - * involves reading from the database, it is highly recommended to statically - * cache the information. - * - * @param $displays - * An array of display settings for the pseudo-fields in the entity, keyed by - * pseudo-field names. - * @param $context - * An associative array containing: - * - entity_type: The entity type; e.g., 'node' or 'user'. - * - bundle: The bundle name. - * - view_mode: The view mode, e.g. 'full', 'teaser'... - */ -function hook_field_extra_fields_display_alter(&$displays, $context) { - if ($context['entity_type'] == 'taxonomy_term' && $context['view_mode'] == 'full') { - $displays['description']['visible'] = FALSE; - } -} - -/** * Alters the widget properties of a field instance on a given entity type * before it gets displayed. * diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index 29ebd3b..1a006ec 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -7,6 +7,7 @@ use Drupal\field\FieldValidationException; use Drupal\Core\Entity\EntityInterface; +use Drupal\entity\Plugin\Core\Entity\EntityDisplay; /** * @defgroup field_storage Field Storage API @@ -715,26 +716,6 @@ function _field_invoke_widget_target() { } /** - * Defines a 'target function' for field_invoke_method(). - * - * Used to invoke methods on an instance's formatter. - * - * @param mixed $display - * Can be either: - * - The name of a view mode. - * - An array of display properties, as found in - * $instance['display'][$view_mode]. - * - * @return callable $target_function - * A 'target function' for field_invoke_method(). - */ -function _field_invoke_formatter_target($display) { - return function ($instance) use ($display) { - return $instance->getFormatter($display); - }; -} - -/** * Adds form elements for all fields for an entity to a form structure. * * The form elements for the entity's fields are added by reference as direct @@ -1361,10 +1342,10 @@ function field_attach_delete_revision($entity_type, $entity) { * * @param $entity_type * The type of entities in $entities; e.g. 'node' or 'user'. - * @param $entities + * @param array $entities * An array of entities, keyed by entity ID. - * @param $view_mode - * View mode, e.g. 'full', 'teaser'... + * @param array $displays + * An array of entity display objects, keyed by bundle name. * @param $langcode * (Optional) The language the field values are to be shown in. If no language * is provided the current language is used. @@ -1372,7 +1353,7 @@ function field_attach_delete_revision($entity_type, $entity) { * An associative array of additional options. See field_invoke_method() for * details. */ -function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcode = NULL, array $options = array()) { +function field_attach_prepare_view($entity_type, array $entities, array $displays, $langcode = NULL, array $options = array()) { $options['langcode'] = array(); // To ensure hooks are only run once per entity, only process items without @@ -1396,8 +1377,15 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcod $null = NULL; // First let the field types do their preparation. _field_invoke_multiple('prepare_view', $entity_type, $prepare, $null, $null, $options); - // Then let the formatters do their own specific massaging. - field_invoke_method_multiple('prepareView', _field_invoke_formatter_target($view_mode), $prepare, $view_mode, $null, $options); + // Then let the formatters do their own specific massaging. For each + // instance, call the prepareView() method on the formatter object handed by + // the entity display. + $target_function = function ($instance) use ($displays) { + if (isset($displays[$instance['bundle']])) { + return $displays[$instance['bundle']]->getFormatter($instance['field_name']); + } + }; + field_invoke_method_multiple('prepareView', $target_function, $prepare, $null, $null, $options); } /** @@ -1437,37 +1425,38 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcod * The type of $entity; e.g. 'node' or 'user'. * @param Drupal\Core\Entity\EntityInterface $entity * The entity with fields to render. - * @param $view_mode - * View mode, e.g. 'full', 'teaser'... + * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display + * The entity display object. * @param $langcode * The language the field values are to be shown in. If no language is * provided the current language is used. * @param array $options * An associative array of additional options. See field_invoke_method() for * details. - * @return + + * @return array * A renderable array for the field values. */ -function field_attach_view($entity_type, EntityInterface $entity, $view_mode, $langcode = NULL, array $options = array()) { +function field_attach_view($entity_type, EntityInterface $entity, EntityDisplay $display, $langcode = NULL, array $options = array()) { // Determine the actual language code to display for each field, given the // language codes available in the field data. $options['langcode'] = field_language($entity_type, $entity, NULL, $langcode); - // Invoke field_default_view(). + // For each instance, call the view() method on the formatter object handed + // by the entity display. + $target_function = function ($instance) use ($display) { + return $display->getFormatter($instance['field_name']); + }; $null = NULL; - $output = field_invoke_method('view', _field_invoke_formatter_target($view_mode), $entity, $view_mode, $null, $options); - - // Add custom weight handling. - $output['#pre_render'][] = '_field_extra_fields_pre_render'; - $output['#entity_type'] = $entity_type; - $output['#bundle'] = $entity->bundle(); + $output = field_invoke_method('view', $target_function, $entity, $null, $null, $options); // Let other modules alter the renderable array. + $view_mode = $display->originalViewMode; $context = array( 'entity_type' => $entity_type, 'entity' => $entity, 'view_mode' => $view_mode, - 'display' => $view_mode, + 'display_options' => $view_mode, 'langcode' => $langcode, ); drupal_alter('field_attach_view', $output, $context); diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc index ac66c77..a62ad2e 100644 --- a/core/modules/field/field.crud.inc +++ b/core/modules/field/field.crud.inc @@ -588,7 +588,6 @@ function _field_write_instance(&$instance, $update = FALSE) { // Set defaults. $instance += array( 'settings' => array(), - 'display' => array(), 'widget' => array(), 'required' => FALSE, 'label' => $instance['field_name'], @@ -615,30 +614,6 @@ function _field_write_instance(&$instance, $update = FALSE) { $instance['widget']['module'] = $widget_type['module']; $instance['widget']['settings'] += field_info_widget_settings($instance['widget']['type']); - // Make sure there are at least display settings for the 'default' view mode, - // and fill in defaults for each view mode specified in the definition. - $instance['display'] += array( - 'default' => array(), - ); - foreach ($instance['display'] as $view_mode => $display) { - $display += array( - 'label' => 'above', - 'type' => isset($field_type['default_formatter']) ? $field_type['default_formatter'] : 'hidden', - 'settings' => array(), - ); - if ($display['type'] != 'hidden') { - $formatter_type = field_info_formatter_types($display['type']); - $display['module'] = $formatter_type['module']; - $display['settings'] += field_info_formatter_settings($display['type']); - } - // If no weight specified, make sure the field sinks at the bottom. - if (!isset($display['weight'])) { - $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], $view_mode); - $display['weight'] = isset($max_weight) ? $max_weight + 1 : 0; - } - $instance['display'][$view_mode] = $display; - } - // The serialized 'data' column contains everything from $instance that does // not have its own column and is not automatically populated when the // instance is read. diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc index 5fab889..688d611 100644 --- a/core/modules/field/field.info.inc +++ b/core/modules/field/field.info.inc @@ -522,7 +522,7 @@ function field_info_extra_fields($entity_type, $bundle, $context) { } /** - * Returns the maximum weight of all the components in an entity. + * Returns the maximum weight of all the components in a form entity. * * This includes fields, 'extra_fields', and other components added by * third-party modules (e.g. field_group). @@ -531,33 +531,25 @@ function field_info_extra_fields($entity_type, $bundle, $context) { * The type of entity; e.g. 'node' or 'user'. * @param $bundle * The bundle name. - * @param $context - * The context for which the maximum weight is requested. Either 'form', or - * the name of a view mode. * * @return * The maximum weight of the entity's components, or NULL if no components * were found. */ -function field_info_max_weight($entity_type, $bundle, $context) { +function field_info_max_weight($entity_type, $bundle) { $weights = array(); // Collect weights for fields. foreach (field_info_instances($entity_type, $bundle) as $instance) { - if ($context == 'form') { - $weights[] = $instance['widget']['weight']; - } - elseif (isset($instance['display'][$context]['weight'])) { - $weights[] = $instance['display'][$context]['weight']; - } + $weights[] = $instance['widget']['weight']; } // Collect weights for extra fields. - foreach (field_info_extra_fields($entity_type, $bundle, $context) as $extra) { + foreach (field_info_extra_fields($entity_type, $bundle, 'form') as $extra) { $weights[] = $extra['weight']; } // Let other modules feedback about their own additions. - $weights = array_merge($weights, module_invoke_all('field_info_max_weight', $entity_type, $bundle, $context)); + $weights = array_merge($weights, module_invoke_all('field_info_max_weight', $entity_type, $bundle, 'form')); $max_weight = $weights ? max($weights) : NULL; return $max_weight; diff --git a/core/modules/field/field.install b/core/modules/field/field.install index b88faa8..695fd89 100644 --- a/core/modules/field/field.install +++ b/core/modules/field/field.install @@ -357,15 +357,6 @@ function _update_7000_field_create_instance($field, &$instance) { 'deleted' => 0, ); - // Merge in display defaults. - if (isset($instance['display'])) { - foreach ($instance['display'] as &$display) { - $display += array( - 'weight' => 0, - ); - } - } - // The serialized 'data' column contains everything from $instance that does // not have its own column and is not automatically populated when the // instance is read. @@ -403,6 +394,97 @@ function field_update_8001() { } /** + * Migrate all instance display settings to configuration. + * + * @ingroup config_upgrade + */ +function field_update_8002() { + $displays = array(); + module_load_install('entity'); + + $query = db_select('field_config_instance', 'fc')->fields('fc'); + foreach ($query->execute() as $record) { + // Unserialize the data array and start investigating the display key + // which holds the configuration of this instance for all view modes. + $data = unserialize($record->data); + + // Skip field instances that were created directly with the new API earlier + // in the upgrade path. + if (!isset($data['display'])) { + continue; + } + + foreach ($data['display'] as $view_mode => $display_options) { + // Determine name and create initial entry in the $displays array if it + // does not exist yet. + $display_id = $record->entity_type . '.' . $record->bundle . '.' . $view_mode; + if (!isset($displays[$display_id])) { + $displays[$display_id] = _update_8000_entity_get_display($record->entity_type, $record->bundle, $view_mode); + } + + // The display object does not store hidden fields. + if ($display_options['type'] != 'hidden') { + // We do not need the 'module' key anymore. + unset($display_options['module']); + $displays[$display_id]->set("content.$record->field_name", $display_options); + } + } + + // Remove the 'display' key and save the record back into the table. + unset($data['display']); + db_update('field_config_instance') + ->condition('id', $record->id) + ->fields(array( + 'data' => serialize($data), + )) + ->execute(); + } + + // Migration of 'extra_fields' display settings. Avoid calling + // entity_get_info() by fetching the relevant variables directly in the + // cariables table. + $variables = array_map('unserialize', db_query("SELECT name, value FROM {variable} WHERE name LIKE '%field_bundle_settings_%'")->fetchAllKeyed()); + foreach ($variables as $variable_name => $variable_value) { + if (preg_match('/field_bundle_settings_(.*)__(.*)/', $variable_name, $matches)) { + $entity_type = $matches[1]; + $bundle = $matches[2]; + if (isset($variable_value['extra_fields']['display'])) { + foreach ($variable_value['extra_fields']['display'] as $field_name => $field_settings) { + foreach ($field_settings as $view_mode => $display_options) { + // Determine name and create initial entry in the $displays array + // if it does not exist yet. + $display_id = $entity_type . '.' . $bundle . '.' . $view_mode; + if (!isset($displays[$display_id])) { + $displays[$display_id] = _update_8000_entity_get_display($entity_type, $bundle, $view_mode); + } + + // Set options in the display. + $new_options = array('visible' => $display_options['visible']); + // The display object only stores the weight for 'visible' extra + // fields. + if ($display_options['visible']) { + $new_options['weight'] = $display_options['weight']; + } + $displays[$display_id]->set("content.$field_name", $new_options); + + // Remove the old entry. + unset($variable_value['extra_fields']['display']); + variable_set($variable_name, $variable_value); + } + } + } + } + } + + // Save the displays to configuration. + foreach ($displays as $config) { + $config->save(); + } + update_config_manifest_add('entity.display', array_keys($displays)); +} + +/** * @} End of "addtogroup updates-7.x-to-8.x". * The next series of updates should start at 9000. */ + diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 487878f..bb522db 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -682,7 +682,6 @@ function field_bundle_settings($entity_type, $bundle, $settings = NULL) { ); $settings['extra_fields'] += array( 'form' => array(), - 'display' => array(), ); return $settings; @@ -725,39 +724,30 @@ function field_view_mode_settings($entity_type, $bundle) { } /** - * Returns the display settings to use for pseudo-fields in a given view mode. + * Returns the display options to use for pseudo-fields in a given view mode. * - * @param $entity_type - * The type of $entity; e.g., 'node' or 'user'. - * @param $bundle - * The bundle name. + * @todo Remove when all steps in the view callstack receive the + * entity_display. + * + * @param $entity + * The entity. * @param $view_mode * The view mode. * * @return - * The display settings to be used when viewing the bundle's pseudo-fields. + * The display options to be used when viewing the entity's pseudo-fields in + * the view mode. */ -function field_extra_fields_get_display($entity_type, $bundle, $view_mode) { - // Check whether the view mode uses custom display settings or the 'default' - // mode. - $view_mode_settings = field_view_mode_settings($entity_type, $bundle); - $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings'])) ? $view_mode : 'default'; - $extra_fields = field_info_extra_fields($entity_type, $bundle, 'display'); - - $displays = array(); +function field_extra_fields_get_display($entity, $view_mode) { + $entity_display = entity_get_render_display($entity, $view_mode); + $extra_fields = field_info_extra_fields($entity->entityType(), $entity->bundle(), 'display'); + + $options = array(); foreach ($extra_fields as $name => $value) { - $displays[$name] = $extra_fields[$name]['display'][$actual_mode]; + $options[$name] = $entity_display->getComponent($name); } - // Let modules alter the display settings. - $context = array( - 'entity_type' => $entity_type, - 'bundle' => $bundle, - 'view_mode' => $view_mode, - ); - drupal_alter('field_extra_fields_display', $displays, $context); - - return $displays; + return $options; } /** @@ -767,23 +757,10 @@ function _field_extra_fields_pre_render($elements) { $entity_type = $elements['#entity_type']; $bundle = $elements['#bundle']; - if (isset($elements['#type']) && $elements['#type'] == 'form') { - $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form'); - foreach ($extra_fields as $name => $settings) { - if (isset($elements[$name])) { - $elements[$name]['#weight'] = $settings['weight']; - } - } - } - elseif (isset($elements['#view_mode'])) { - $view_mode = $elements['#view_mode']; - $extra_fields = field_extra_fields_get_display($entity_type, $bundle, $view_mode); - foreach ($extra_fields as $name => $settings) { - if (isset($elements[$name])) { - $elements[$name]['#weight'] = $settings['weight']; - // Visibility: make sure we do not accidentally show a hidden element. - $elements[$name]['#access'] = isset($elements[$name]['#access']) ? ($elements[$name]['#access'] && $settings['visible']) : $settings['visible']; - } + $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form'); + foreach ($extra_fields as $name => $settings) { + if (isset($elements[$name])) { + $elements[$name]['#weight'] = $settings['weight']; } } @@ -902,15 +879,14 @@ function field_view_value($entity_type, $entity, $field_name, $item, $display = * key and the field data to display. * @param $field_name * The name of the field to display. - * @param $display + * @param $display_options * Can be either: * - The name of a view mode. The field will be displayed according to the * display settings specified for this view mode in the $instance * definition for the field in the entity's bundle. If no display settings * are found for the view mode, the settings for the 'default' view mode * will be used. - * - An array of display settings, as found in the 'display' entry of - * $instance definitions. The following key/value pairs are allowed: + * - An array of display options. The following key/value pairs are allowed: * - label: (string) Position of the label. The default 'field' theme * implementation supports the values 'inline', 'above' and 'hidden'. * Defaults to 'above'. @@ -933,51 +909,70 @@ function field_view_value($entity_type, $entity, $field_name, $item, $display = * * @see field_view_value() */ -function field_view_field($entity_type, $entity, $field_name, $display = array(), $langcode = NULL) { +function field_view_field($entity_type, $entity, $field_name, $display_options = array(), $langcode = NULL) { $output = array(); + $bundle = $entity->bundle(); - if ($instance = field_info_instance($entity_type, $field_name, $entity->bundle())) { - if (is_array($display) && empty($display['type'])) { - $field = field_info_field($instance['field_name']); - $field_type_info = field_info_field_types($field['type']); - $display['type'] = $field_type_info['default_formatter']; + // Return nothing if the field doesn't exist. + $instance = field_info_instance($entity_type, $field_name, $bundle); + if (!$instance) { + return $output; + } + + // Get the formatter object. + if (is_string($display_options)) { + $view_mode = $display_options; + $formatter = entity_get_render_display($entity, $view_mode)->getFormatter($field_name); + } + else { + $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($field_name); + $formatter_manager = drupal_container()->get('plugin.manager.field.formatter'); + $display_options = $formatter_manager->prepareConfiguration($field['type'], $display_options); + $formatter = $formatter_manager->getInstance(array( + 'instance' => $instance, + 'view_mode' => $view_mode, + 'prepare' => FALSE, + 'configuration' => $display_options, + )); + } + + if ($formatter) { + $display_langcode = field_language($entity_type, $entity, $field_name, $langcode); + $items = $entity->{$field_name}[$display_langcode]; + + // Invoke prepare_view steps if needed. + if (empty($entity->_field_view_prepared)) { + $id = $entity->id(); + + // First let the field types do their preparation. + $options = array('field_name' => $field_name, 'langcode' => $display_langcode); + $null = NULL; + _field_invoke_multiple('prepare_view', $entity_type, array($id => $entity), $null, $null, $options); + + // Then let the formatter do its own specific massaging. + $items_multi = array($id => $entity->{$field_name}[$display_langcode]); + $formatter->prepareView(array($id => $entity), $display_langcode, $items_multi); + $items = $items_multi[$id]; } - if ($formatter = $instance->getFormatter($display)) { - $display_langcode = field_language($entity_type, $entity, $field_name, $langcode); - $items = $entity->{$field_name}[$display_langcode]; - - // Invoke prepare_view steps if needed. - if (empty($entity->_field_view_prepared)) { - $id = $entity->id(); - - // First let the field types do their preparation. - // @todo invoke hook_field_prepare_view() directly ? - $options = array('field_name' => $field_name, 'langcode' => $display_langcode); - $null = NULL; - _field_invoke_multiple('prepare_view', $entity_type, array($id => $entity), $display, $null, $options); - - // Then let the formatters do their own specific massaging. - $items_multi = array($id => $entity->{$field_name}[$display_langcode]); - $formatter->prepareView(array($id => $entity), $display_langcode, $items_multi); - $items = $items_multi[$id]; - } - // Build the renderable array. - $result = $formatter->view($entity, $display_langcode, $items); + // Build the renderable array. + $result = $formatter->view($entity, $display_langcode, $items); - // Invoke hook_field_attach_view_alter() to let other modules alter the - // renderable array, as in a full field_attach_view() execution. - $context = array( - 'entity_type' => $entity_type, - 'entity' => $entity, - 'view_mode' => '_custom', - 'display' => $display, - ); - drupal_alter('field_attach_view', $result, $context); + // Invoke hook_field_attach_view_alter() to let other modules alter the + // renderable array, as in a full field_attach_view() execution. + $context = array( + 'entity_type' => $entity_type, + 'entity' => $entity, + 'view_mode' => $view_mode, + 'display_options' => $display_options, + ); + drupal_alter('field_attach_view', $result, $context); - if (isset($result[$field_name])) { - $output = $result[$field_name]; - } + if (isset($result[$field_name])) { + $output = $result[$field_name]; } } diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php index 65fce21..7ff6850 100644 --- a/core/modules/field/lib/Drupal/field/FieldInfo.php +++ b/core/modules/field/lib/Drupal/field/FieldInfo.php @@ -549,25 +549,7 @@ public function prepareExtraFields($extra_fields, $entity_type, $bundle) { } // Extra fields in displayed entities. - $data = $extra_fields['display']; - foreach ($extra_fields['display'] as $name => $field_data) { - $settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array(); - $view_modes = array_merge(array('default'), array_keys($entity_type_info['view_modes'])); - foreach ($view_modes as $view_mode) { - if (isset($settings[$view_mode])) { - $field_data['display'][$view_mode] = $settings[$view_mode]; - } - else { - $field_data['display'][$view_mode] = array( - 'weight' => $field_data['weight'], - 'visible' => isset($field_data['visible']) ? $field_data['visible'] : TRUE, - ); - } - } - unset($field_data['weight']); - unset($field_data['visible']); - $result['display'][$name] = $field_data; - } + $result['display'] = $extra_fields['display']; return $result; } diff --git a/core/modules/field/lib/Drupal/field/FieldInstance.php b/core/modules/field/lib/Drupal/field/FieldInstance.php index a1e7a4f..ba6ea44 100644 --- a/core/modules/field/lib/Drupal/field/FieldInstance.php +++ b/core/modules/field/lib/Drupal/field/FieldInstance.php @@ -27,13 +27,6 @@ class FieldInstance implements \ArrayAccess { protected $widget; /** - * The formatter objects used for this instance, keyed by view mode. - * - * @var array - */ - protected $formatters; - - /** * Constructs a FieldInstance object. * * @param array $definition @@ -75,88 +68,6 @@ public function getWidget() { } /** - * Returns a Formatter plugin for the instance. - * - * @param mixed $display_properties - * Can be either: - * - The name of a view mode. - * - An array of display properties, as found in the 'display' entry of - * $instance definitions. - * - * @return Drupal\field\Plugin\Type\Formatter\FormatterInterface|null - * The Formatter plugin to be used for the instance, or NULL if the field - * is hidden. - */ - public function getFormatter($display_properties) { - if (is_string($display_properties)) { - // A view mode was provided. Switch to 'default' if the view mode is not - // configured to use dedicated settings. - $view_mode = $display_properties; - $view_mode_settings = field_view_mode_settings($this->definition['entity_type'], $this->definition['bundle']); - $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default'); - - if (isset($this->formatters[$actual_mode])) { - return $this->formatters[$actual_mode]; - } - - // Switch to 'hidden' if the instance has no properties for the view - // mode. - if (isset($this->definition['display'][$actual_mode])) { - $display_properties = $this->definition['display'][$actual_mode]; - } - else { - $display_properties = array( - 'type' => 'hidden', - 'settings' => array(), - 'label' => 'above', - 'weight' => 0, - ); - } - - // Let modules alter the widget properties. - $context = array( - 'entity_type' => $this->definition['entity_type'], - 'bundle' => $this->definition['bundle'], - 'field' => field_info_field($this->definition['field_name']), - 'instance' => $this, - 'view_mode' => $view_mode, - ); - drupal_alter(array('field_display', 'field_display_' . $this->definition['entity_type']), $display_properties, $context); - } - else { - // Arbitrary display settings. Make sure defaults are present. - $display_properties += array( - 'settings' => array(), - 'label' => 'above', - 'weight' => 0, - ); - $view_mode = '_custom_display'; - } - - if (!empty($display_properties['type']) && $display_properties['type'] != 'hidden') { - $options = array( - 'instance' => $this, - 'type' => $display_properties['type'], - 'settings' => $display_properties['settings'], - 'label' => $display_properties['label'], - 'weight' => $display_properties['weight'], - 'view_mode' => $view_mode, - ); - $formatter = drupal_container()->get('plugin.manager.field.formatter')->getInstance($options); - } - else { - $formatter = NULL; - } - - // Persist the object if we were not passed custom display settings. - if (isset($actual_mode)) { - $this->formatters[$actual_mode] = $formatter; - } - - return $formatter; - } - - /** * Implements ArrayAccess::offsetExists(). */ public function offsetExists($offset) { @@ -185,9 +96,6 @@ public function offsetSet($offset, $value) { if ($offset == 'widget') { unset($this->widget); } - if ($offset == 'display') { - unset($this->formatters); - } } /** @@ -201,9 +109,6 @@ public function offsetUnset($offset) { if ($offset == 'widget') { unset($this->widget); } - if ($offset == 'display') { - unset($this->formatters); - } } /** diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php index 55d0e3f..939df9c 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php @@ -11,8 +11,9 @@ use Drupal\Component\Plugin\Discovery\ProcessDecorator; use Drupal\Core\Plugin\Discovery\CacheDecorator; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; -use Drupal\field\Plugin\Type\Formatter\FormatterLegacyDiscoveryDecorator; use Drupal\Core\Plugin\Discovery\AlterDecorator; +use Drupal\field\Plugin\Type\Formatter\FormatterLegacyDiscoveryDecorator; +use Drupal\field\FieldInstance; /** * Plugin type manager for field formatters. @@ -42,31 +43,87 @@ public function __construct() { /** * Overrides PluginManagerBase::getInstance(). + * + * @param array $options + * An array with the following key/value pairs: + * - instance: (FieldInstance) The field instance. + * - view_mode: (string) The view mode. + * - prepare: (bool, optional) Whether default values should get merged in + * the 'configuration' array. Defaults to TRUE. + * - configuration: (array) the configuration for the formatter. The + * following key value pairs are allowed, and are all optional if + * 'prepare' is TRUE: + * - label: (string) Position of the label. The default 'field' theme + * implementation supports the values 'inline', 'above' and 'hidden'. + * Defaults to 'above'. + * - type: (string) The formatter to use. Defaults to the + * 'default_formatter' for the field type, specified in + * hook_field_info(). The default formatter will also be used if the + * requested formatter is not available. + * - settings: (array) Settings specific to the formatter. Each setting + * defaults to the default value specified in the formatter definition. + * - weight: (float) The weight to assign to the renderable element. + * Defaults to 0. + * + * @return \Drupal\field\Plugin\Type\Formatter\FormatterInterface + * A formatter object. */ public function getInstance(array $options) { + $configuration = $options['configuration']; $instance = $options['instance']; - $type = $options['type']; - - $definition = $this->getDefinition($type); $field = field_info_field($instance['field_name']); + // Fill in default configuration if needed. + if (!isset($options['prepare']) || $options['prepare'] == TRUE) { + $configuration = $this->prepareConfiguration($field['type'], $configuration); + } + + $plugin_id = $configuration['type']; + // Switch back to default formatter if either: // - $type_info doesn't exist (the widget type is unknown), // - the field type is not allowed for the widget. + $definition = $this->getDefinition($configuration['type']); if (!isset($definition['class']) || !in_array($field['type'], $definition['field_types'])) { // Grab the default widget for the field type. $field_type_definition = field_info_field_types($field['type']); - $type = $field_type_definition['default_formatter']; + $plugin_id = $field_type_definition['default_formatter']; } - $configuration = array( + $configuration += array( 'instance' => $instance, - 'settings' => $options['settings'], - 'weight' => $options['weight'], - 'label' => $options['label'], 'view_mode' => $options['view_mode'], ); - return $this->createInstance($type, $configuration); + return $this->createInstance($plugin_id, $configuration); + } + + /** + * Merges default values for formatter configuration. + * + * @param string $field_type + * The field type. + * @param array $properties + * An array of formatter configuration. + * + * @return array + * The display properties with defaults added. + */ + public function prepareConfiguration($field_type, array $configuration) { + // Fill in defaults for missing properties. + $configuration += array( + 'label' => 'above', + 'settings' => array(), + 'weight' => 0, + ); + // If no formatter is specified, use the default formatter. + if (!isset($configuration['type'])) { + $field_type = field_info_field_types($field_type); + $configuration['type'] = $field_type['default_formatter']; + } + // Fill in default settings values for the formatter. + $configuration['settings'] += field_info_formatter_settings($configuration['type']); + + return $configuration; } } diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php index 1c8f166..32f91fd 100644 --- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php @@ -42,23 +42,33 @@ function setUp() { 'entity_type' => 'test_entity', 'bundle' => 'test_bundle', 'label' => $this->label, - 'display' => array( - 'default' => array( - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $this->randomName(), - ), + ); + + $this->display_options = array( + 'default' => array( + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $this->randomName(), ), - 'teaser' => array( - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $this->randomName(), - ), + ), + 'teaser' => array( + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $this->randomName(), ), ), ); + field_create_field($this->field); field_create_instance($this->instance); + // Create a display for the default view mode. + entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'default') + ->setComponent($this->field_name, $this->display_options['default']) + ->save(); + // Create a display for the teaser view mode. + entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'teaser') + ->setComponent($this->field_name, $this->display_options['teaser']) + ->save(); // Create an entity with values. $this->values = $this->_generateTestFieldValues($this->cardinality); @@ -120,11 +130,11 @@ function testFieldViewField() { $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); } - // View mode: check that display settings specified in the instance are - // used. + // View mode: check that display settings specified in the display object + // are used. $output = field_view_field('test_entity', $this->entity, $this->field_name, 'teaser'); $this->drupalSetContent(drupal_render($output)); - $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting']; + $setting = $this->display_options['teaser']['settings']['test_formatter_setting']; $this->assertText($this->label, 'Label was displayed.'); foreach ($this->values as $delta => $value) { $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); @@ -134,7 +144,7 @@ function testFieldViewField() { // are used. $output = field_view_field('test_entity', $this->entity, $this->field_name, 'unknown_view_mode'); $this->drupalSetContent(drupal_render($output)); - $setting = $this->instance['display']['default']['settings']['test_formatter_setting']; + $setting = $this->display_options['default']['settings']['test_formatter_setting']; $this->assertText($this->label, 'Label was displayed.'); foreach ($this->values as $delta => $value) { $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); @@ -189,7 +199,7 @@ function testFieldViewValue() { // View mode: check that display settings specified in the instance are // used. - $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting']; + $setting = $this->display_options['teaser']['settings']['test_formatter_setting']; foreach ($this->values as $delta => $value) { $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta]; $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'teaser'); @@ -199,7 +209,7 @@ function testFieldViewValue() { // Unknown view mode: check that display settings for 'default' view mode // are used. - $setting = $this->instance['display']['default']['settings']['test_formatter_setting']; + $setting = $this->display_options['default']['settings']['test_formatter_setting']; foreach ($this->values as $delta => $value) { $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta]; $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'unknown_view_mode'); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php index 7f87887..bc1a380 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php @@ -49,14 +49,16 @@ function setUp() { 'widget' => array( 'type' => 'text_textfield', ), - 'display' => array( - 'default' => array( - 'type' => 'text_default', - ), - ), ); field_create_instance($this->instance); + // Assign display properties for the 'default' and 'teaser' view modes. + foreach (array('default', 'teaser') as $view_mode) { + entity_get_display('node', $this->content_type, $view_mode) + ->setComponent($this->field['field_name']) + ->save(); + } + // Create test node. $this->test_view_field_value = 'This is some text'; $settings = array(); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php index f971099..5f8ad5d 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php @@ -40,31 +40,32 @@ function testFieldAttachView() { // Simple formatter, label displayed. $entity = clone($entity_init); + $display = entity_get_display($entity_type, $entity->bundle(), 'full'); + $displays = array($entity->bundle() => $display); + $formatter_setting = $this->randomName(); - $this->instance['display'] = array( - 'full' => array( - 'label' => 'above', - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $formatter_setting, - ) + $display_options = array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting, ), ); - field_update_instance($this->instance); + $display->setComponent($this->field['field_name'], $display_options); + $formatter_setting_2 = $this->randomName(); - $this->instance_2['display'] = array( - 'full' => array( - 'label' => 'above', - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $formatter_setting_2, - ) + $display_options_2 = array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting_2, ), ); - field_update_instance($this->instance_2); + $display->setComponent($this->field_2['field_name'], $display_options_2); + // View all fields. - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays); + $entity->content = field_attach_view($entity_type, $entity, $display); $output = drupal_render($entity->content); $this->content = $output; $this->assertRaw($this->instance['label'], "First field's label is displayed."); @@ -78,8 +79,8 @@ function testFieldAttachView() { $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); } // View single field (the second field). - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full', $langcode, $options); - $entity->content = field_attach_view($entity_type, $entity, 'full', $langcode, $options); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays, $langcode, $options); + $entity->content = field_attach_view($entity_type, $entity, $display, $langcode, $options); $output = drupal_render($entity->content); $this->content = $output; $this->assertNoRaw($this->instance['label'], "First field's label is not displayed."); @@ -95,25 +96,19 @@ function testFieldAttachView() { // Label hidden. $entity = clone($entity_init); - $this->instance['display']['full']['label'] = 'hidden'; - field_update_instance($this->instance); - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + $display_options['label'] = 'hidden'; + $display->setComponent($this->field['field_name'], $display_options); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays); + $entity->content = field_attach_view($entity_type, $entity, $display); $output = drupal_render($entity->content); $this->content = $output; $this->assertNoRaw($this->instance['label'], "Hidden label: label is not displayed."); // Field hidden. $entity = clone($entity_init); - $this->instance['display'] = array( - 'full' => array( - 'label' => 'above', - 'type' => 'hidden', - ), - ); - field_update_instance($this->instance); - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + $display->removeComponent($this->field['field_name']); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays); + $entity->content = field_attach_view($entity_type, $entity, $display); $output = drupal_render($entity->content); $this->content = $output; $this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed."); @@ -124,45 +119,38 @@ function testFieldAttachView() { // Multiple formatter. $entity = clone($entity_init); $formatter_setting = $this->randomName(); - $this->instance['display'] = array( - 'full' => array( - 'label' => 'above', - 'type' => 'field_test_multiple', - 'settings' => array( - 'test_formatter_setting_multiple' => $formatter_setting, - ) + $display->setComponent($this->field['field_name'], array( + 'label' => 'above', + 'type' => 'field_test_multiple', + 'settings' => array( + 'test_formatter_setting_multiple' => $formatter_setting, ), - ); - field_update_instance($this->instance); - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + )); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays); + $entity->content = field_attach_view($entity_type, $entity, $display); $output = drupal_render($entity->content); - $display = $formatter_setting; + $expected_output = $formatter_setting; foreach ($values as $delta => $value) { - $display .= "|$delta:{$value['value']}"; + $expected_output .= "|$delta:{$value['value']}"; } $this->content = $output; - $this->assertRaw($display, "Multiple formatter: all values are displayed, formatter settings are applied."); + $this->assertRaw($expected_output, "Multiple formatter: all values are displayed, formatter settings are applied."); // Test a formatter that uses hook_field_formatter_prepare_view(). $entity = clone($entity_init); $formatter_setting = $this->randomName(); - $this->instance['display'] = array( - 'full' => array( - 'label' => 'above', - 'type' => 'field_test_with_prepare_view', - 'settings' => array( - 'test_formatter_setting_additional' => $formatter_setting, - ) + $display->setComponent($this->field['field_name'], array( + 'label' => 'above', + 'type' => 'field_test_with_prepare_view', + 'settings' => array( + 'test_formatter_setting_additional' => $formatter_setting, ), - ); - field_update_instance($this->instance); - field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full'); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + )); + field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays); + $entity->content = field_attach_view($entity_type, $entity, $display); $output = drupal_render($entity->content); $this->content = $output; foreach ($values as $delta => $value) { - $this->content = $output; $expected = $formatter_setting . '|' . $value['value'] . '|' . ($value['value'] + 1); $this->assertRaw($expected, "Value $delta is displayed, formatter settings are applied."); } @@ -191,8 +179,8 @@ function testFieldAttachPrepareViewMultiple() { $langcode = LANGUAGE_NOT_SPECIFIED; // Set the instance to be hidden. - $this->instance['display']['full']['type'] = 'hidden'; - field_update_instance($this->instance); + $display = entity_get_display('test_entity', 'test_bundle', 'full') + ->removeComponent($this->field['field_name']); // Set up a second instance on another bundle, with a formatter that uses // hook_field_formatter_prepare_view(). @@ -200,14 +188,18 @@ function testFieldAttachPrepareViewMultiple() { $formatter_setting = $this->randomName(); $this->instance2 = $this->instance; $this->instance2['bundle'] = 'test_bundle_2'; - $this->instance2['display']['full'] = array( - 'type' => 'field_test_with_prepare_view', - 'settings' => array( - 'test_formatter_setting_additional' => $formatter_setting, - ) - ); field_create_instance($this->instance2); + $display_2 = entity_get_display('test_entity', 'test_bundle_2', 'full') + ->setComponent($this->field['field_name'], array( + 'type' => 'field_test_with_prepare_view', + 'settings' => array( + 'test_formatter_setting_additional' => $formatter_setting, + ), + )); + + $displays = array('test_bundle' => $display, 'test_bundle_2' => $display_2); + // Create one entity in each bundle. $entity1_init = field_test_create_entity(1, 1, 'test_bundle'); $values1 = $this->_generateTestFieldValues($this->field['cardinality']); @@ -220,14 +212,16 @@ function testFieldAttachPrepareViewMultiple() { // Run prepare_view, and check that the entities come out as expected. $entity1 = clone($entity1_init); $entity2 = clone($entity2_init); - field_attach_prepare_view($entity_type, array($entity1->ftid => $entity1, $entity2->ftid => $entity2), 'full'); + $entities = array($entity1->ftid => $entity1, $entity2->ftid => $entity2); + field_attach_prepare_view($entity_type, $entities, $displays); $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.'); $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.'); // Same thing, reversed order. $entity1 = clone($entity1_init); $entity2 = clone($entity2_init); - field_attach_prepare_view($entity_type, array($entity2->ftid => $entity2, $entity1->ftid => $entity1), 'full'); + $entities = array($entity1->ftid => $entity1, $entity2->ftid => $entity2); + field_attach_prepare_view($entity_type, $entities, $displays); $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.'); $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.'); } diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php index 323b8e8..3115851 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php @@ -178,15 +178,13 @@ function testInstancePrepare() { field_create_instance($instance_definition); // Simulate a stored instance definition missing various settings (e.g. a - // third-party module adding instance, widget or display settings has been - // enabled, but existing instances do not know the new settings). + // third-party module adding instance or widget settings has been enabled, + // but existing instances do not know the new settings). $data = db_query('SELECT data FROM {field_config_instance} WHERE field_name = :field_name AND bundle = :bundle', array(':field_name' => $instance_definition['field_name'], ':bundle' => $instance_definition['bundle']))->fetchField(); $data = unserialize($data); $data['settings'] = array(); $data['widget']['settings'] = 'unavailable_widget'; $data['widget']['settings'] = array(); - $data['display']['default']['type'] = 'unavailable_formatter'; - $data['display']['default']['settings'] = array(); db_update('field_config_instance') ->fields(array('data' => serialize($data))) ->condition('field_name', $instance_definition['field_name']) @@ -207,13 +205,6 @@ function testInstancePrepare() { $this->assertIdentical($widget->getPluginId(), $field_type['default_widget'], 'Unavailable widget replaced with default widget.'); $widget_type = $widget->getDefinition(); $this->assertIdentical($widget->getSettings(), $widget_type['settings'] , 'All expected widget settings are present.'); - - // Check that display settings are set for the 'default' mode. - $formatter = $instance->getFormatter('default'); - $this->assertIdentical($formatter->getPluginId(), $field_type['default_formatter'], "Formatter is set for the 'default' view mode"); - $formatter_type = $formatter->getDefinition(); - $this->assertIdentical($formatter->getSettings(), $formatter_type['settings'] , "Formatter settings are set for the 'default' view mode"); - } /** diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php index 84cee72..90fcc05 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php @@ -62,7 +62,6 @@ function testCreateFieldInstance() { $field_type = field_info_field_types($this->field['type']); $widget_type = field_info_widget_types($field_type['default_widget']); - $formatter_type = field_info_formatter_types($field_type['default_formatter']); // Check that the ID key is filled in. $this->assertIdentical($record['id'], $this->instance_definition['id'], 'The instance id is filled in'); @@ -72,13 +71,10 @@ function testCreateFieldInstance() { $this->assertIdentical($record['data']['label'], $this->instance_definition['field_name'], 'Label defaults to field name.'); $this->assertIdentical($record['data']['description'], '', 'Description defaults to empty string.'); $this->assertIdentical($record['data']['widget']['type'], $field_type['default_widget'], 'Default widget has been written.'); - $this->assertTrue(isset($record['data']['display']['default']), 'Display for "full" view_mode has been written.'); - $this->assertIdentical($record['data']['display']['default']['type'], $field_type['default_formatter'], 'Default formatter for "full" view_mode has been written.'); // Check that default settings are set. $this->assertIdentical($record['data']['settings'], $field_type['instance_settings'] , 'Default instance settings have been written.'); $this->assertIdentical($record['data']['widget']['settings'], $widget_type['settings'] , 'Default widget settings have been written.'); - $this->assertIdentical($record['data']['display']['default']['settings'], $formatter_type['settings'], 'Default formatter settings for "full" view_mode have been written.'); // Guarantee that the field/bundle combination is unique. try { @@ -151,7 +147,6 @@ function testReadFieldInstance() { */ function testUpdateFieldInstance() { field_create_instance($this->instance_definition); - $field_type = field_info_field_types($this->field['type']); // Check that basic changes are saved. $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); @@ -161,8 +156,6 @@ function testUpdateFieldInstance() { $instance['settings']['test_instance_setting'] = $this->randomName(); $instance['widget']['settings']['test_widget_setting'] =$this->randomName(); $instance['widget']['weight']++; - $instance['display']['default']['settings']['test_formatter_setting'] = $this->randomName(); - $instance['display']['default']['weight']++; field_update_instance($instance); $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); @@ -171,35 +164,16 @@ function testUpdateFieldInstance() { $this->assertEqual($instance['description'], $instance_new['description'], '"description" change is saved'); $this->assertEqual($instance['widget']['settings']['test_widget_setting'], $instance_new['widget']['settings']['test_widget_setting'], 'Widget setting change is saved'); $this->assertEqual($instance['widget']['weight'], $instance_new['widget']['weight'], 'Widget weight change is saved'); - $this->assertEqual($instance['display']['default']['settings']['test_formatter_setting'], $instance_new['display']['default']['settings']['test_formatter_setting'], 'Formatter setting change is saved'); - $this->assertEqual($instance['display']['default']['weight'], $instance_new['display']['default']['weight'], 'Widget weight change is saved'); - // Check that changing widget and formatter types updates the default settings. + // Check that changing the widget type updates the default settings. $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); $instance['widget']['type'] = 'test_field_widget_multiple'; - $instance['display']['default']['type'] = 'field_test_multiple'; field_update_instance($instance); $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); $this->assertEqual($instance['widget']['type'], $instance_new['widget']['type'] , 'Widget type change is saved.'); $settings = field_info_widget_settings($instance_new['widget']['type']); $this->assertIdentical($settings, array_intersect_key($instance_new['widget']['settings'], $settings) , 'Widget type change updates default settings.'); - $this->assertEqual($instance['display']['default']['type'], $instance_new['display']['default']['type'] , 'Formatter type change is saved.'); - $info = field_info_formatter_types($instance_new['display']['default']['type']); - $settings = $info['settings']; - $this->assertIdentical($settings, array_intersect_key($instance_new['display']['default']['settings'], $settings) , 'Changing formatter type updates default settings.'); - - // Check that adding a new view mode is saved and gets default settings. - $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); - $instance['display']['teaser'] = array(); - field_update_instance($instance); - - $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']); - $this->assertTrue(isset($instance_new['display']['teaser']), 'Display for the new view_mode has been written.'); - $this->assertIdentical($instance_new['display']['teaser']['type'], $field_type['default_formatter'], 'Default formatter for the new view_mode has been written.'); - $info = field_info_formatter_types($instance_new['display']['teaser']['type']); - $settings = $info['settings']; - $this->assertIdentical($settings, $instance_new['display']['teaser']['settings'] , 'Default formatter settings for the new view_mode have been written.'); // TODO: test failures. } diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module index 5b8242f..47d61b1 100644 --- a/core/modules/field/tests/modules/field_test/field_test.module +++ b/core/modules/field/tests/modules/field_test/field_test.module @@ -206,7 +206,7 @@ function field_test_entity_label_callback($entity_type, $entity, $langcode = NUL * Implements hook_field_attach_view_alter(). */ function field_test_field_attach_view_alter(&$output, $context) { - if (!empty($context['display']['settings']['alter'])) { + if (!empty($context['display_options']['settings']['alter'])) { $output['test_field'][] = array('#markup' => 'field_test_field_attach_view_alter'); } } diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc index 00cb8de..27dad1e 100644 --- a/core/modules/field_ui/field_ui.admin.inc +++ b/core/modules/field_ui/field_ui.admin.inc @@ -374,51 +374,6 @@ function field_ui_display_overview($entity_type, $bundle, $view_mode) { } /** - * Populates display settings for a new view mode from the default view mode. - * - * When an administrator decides to use custom display settings for a view mode, - * that view mode needs to be initialized with the display settings for the - * 'default' view mode, which it was previously using. This helper function - * adds the new custom display settings to this bundle's instances, and saves - * them. It also modifies the passed-in $settings array, which the caller can - * then save using field_bundle_settings(). - * - * @param $entity_type - * The bundle's entity type. - * @param $bundle - * The bundle whose view mode is being customized. - * @param $view_mode - * The view mode that the administrator has set to use custom settings. - * @param $settings - * An associative array of bundle settings, as expected by - * field_bundle_settings(). - * - * @see Drupal\field_ui\DisplayOverview::submit(). - * @see field_bundle_settings() - */ -function _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode, &$settings) { - // Update display settings for field instances. - $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle)); - foreach ($instances as $instance) { - // If this field instance has display settings defined for this view mode, - // respect those settings. - if (!isset($instance['display'][$view_mode])) { - // The instance doesn't specify anything for this view mode, so use the - // default display settings. - $instance['display'][$view_mode] = $instance['display']['default']; - field_update_instance($instance); - } - } - - // Update display settings for 'extra fields'. - foreach (array_keys($settings['extra_fields']['display']) as $name) { - if (!isset($settings['extra_fields']['display'][$name][$view_mode])) { - $settings['extra_fields']['display'][$name][$view_mode] = $settings['extra_fields']['display'][$name]['default']; - } - } -} - -/** * Returns an array of field_type options. */ function field_ui_field_type_options() { diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php index 6117de9..0a86f78 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php @@ -49,6 +49,7 @@ public function form(array $form, array &$form_state) { $instances = field_info_instances($this->entity_type, $this->bundle); $field_types = field_info_field_types(); $extra_fields = field_info_extra_fields($this->entity_type, $this->bundle, 'display'); + $entity_display = entity_get_display($this->entity_type, $this->bundle, $this->view_mode); $form_state += array( 'formatter_settings_edit' => NULL, @@ -94,24 +95,14 @@ public function form(array $form, array &$form_state) { 'hidden' => t(''), ); $extra_visibility_options = array( - 'content' => t('Visible'), + 'visible' => t('Visible'), 'hidden' => t('Hidden'), ); // Field rows. foreach ($instances as $name => $instance) { - $field = field_info_field($instance['field_name']); - - if (isset($instance['display'][$this->view_mode])) { - $display = $instance['display'][$this->view_mode]; - } - else { - $display = array( - 'type' => 'hidden', - 'label' => 'above', - 'weight' => 0, - ); - } + $field = field_info_field($name); + $display_options = $entity_display->getComponent($name); $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), @@ -128,7 +119,7 @@ public function form(array $form, array &$form_state) { '#type' => 'textfield', '#title' => t('Weight for @title', array('@title' => $instance['label'])), '#title_display' => 'invisible', - '#default_value' => $display['weight'], + '#default_value' => $display_options ? $display_options['weight'] : '0', '#size' => 3, '#attributes' => array('class' => array('field-weight')), ), @@ -153,7 +144,7 @@ public function form(array $form, array &$form_state) { '#title' => t('Label display for @title', array('@title' => $instance['label'])), '#title_display' => 'invisible', '#options' => $field_label_options, - '#default_value' => $display['label'], + '#default_value' => $display_options ? $display_options['label'] : 'above', ), ); @@ -165,7 +156,7 @@ public function form(array $form, array &$form_state) { '#title' => t('Formatter for @title', array('@title' => $instance['label'])), '#title_display' => 'invisible', '#options' => $formatter_options, - '#default_value' => $display['type'], + '#default_value' => $display_options ? $display_options['type'] : 'hidden', '#parents' => array('fields', $name, 'type'), '#attributes' => array('class' => array('field-formatter-type')), ), @@ -175,12 +166,23 @@ public function form(array $form, array &$form_state) { // Check the currently selected formatter, and merge persisted values for // formatter settings. if (isset($form_state['values']['fields'][$name]['type'])) { - $display['type'] = $form_state['values']['fields'][$name]['type']; + $display_options['type'] = $form_state['values']['fields'][$name]['type']; } if (isset($form_state['formatter_settings'][$name])) { - $display['settings'] = $form_state['formatter_settings'][$name]; + $display_options['settings'] = $form_state['formatter_settings'][$name]; + } + + // Get the corresponding formatter object. + if ($display_options && $display_options['type'] != 'hidden') { + $formatter = drupal_container()->get('plugin.manager.field.formatter')->getInstance(array( + 'instance' => $instance, + 'view_mode' => $this->view_mode, + 'configuration' => $display_options + )); + } + else { + $formatter = NULL; } - $formatter = $instance->getFormatter($display); // Base button element for the various formatter settings actions. $base_button = array( @@ -287,7 +289,8 @@ public function form(array $form, array &$form_state) { // Non-field elements. foreach ($extra_fields as $name => $extra_field) { - $display = $extra_field['display'][$this->view_mode]; + $display_options = $entity_display->getComponent($name); + $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'extra_field', @@ -300,7 +303,7 @@ public function form(array $form, array &$form_state) { '#type' => 'textfield', '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), '#title_display' => 'invisible', - '#default_value' => $display['weight'], + '#default_value' => $display_options ? $display_options['weight'] : 0, '#size' => 3, '#attributes' => array('class' => array('field-weight')), ), @@ -329,7 +332,7 @@ public function form(array $form, array &$form_state) { '#title' => t('Visibility for @title', array('@title' => $extra_field['label'])), '#title_display' => 'invisible', '#options' => $extra_visibility_options, - '#default_value' => $display['visible'] ? 'content' : 'hidden', + '#default_value' => $display_options ? 'visible' : 'hidden', '#parents' => array('fields', $name, 'type'), '#attributes' => array('class' => array('field-formatter-type')), ), @@ -418,73 +421,86 @@ public function form(array $form, array &$form_state) { */ public function submit(array $form, array &$form_state) { $form_values = $form_state['values']; + $display = entity_get_display($this->entity_type, $this->bundle, $this->view_mode); - // Save data for 'regular' fields. + // Collect data for 'regular' fields. foreach ($form['#fields'] as $field_name) { // Retrieve the stored instance settings to merge with the incoming // values. - $instance = field_read_instance($this->entity_type, $field_name, $this->bundle); $values = $form_values['fields'][$field_name]; - // Get formatter settings. They lie either directly in submitted form - // values (if the whole form was submitted while some formatter - // settings were being edited), or have been persisted in - // $form_state. - $settings = array(); - if (isset($values['settings_edit_form']['settings'])) { - $settings = $values['settings_edit_form']['settings']; - } - elseif (isset($form_state['formatter_settings'][$field_name])) { - $settings = $form_state['formatter_settings'][$field_name]; - } - elseif (isset($instance['display'][$this->view_mode]['settings'])) { - $settings = $instance['display'][$this->view_mode]['settings']; + + if ($values['type'] == 'hidden') { + $display->removeComponent($field_name); } + else { + // Get formatter settings. They lie either directly in submitted form + // values (if the whole form was submitted while some formatter + // settings were being edited), or have been persisted in $form_state. + $settings = array(); + if (isset($values['settings_edit_form']['settings'])) { + $settings = $values['settings_edit_form']['settings']; + } + elseif (isset($form_state['formatter_settings'][$field_name])) { + $settings = $form_state['formatter_settings'][$field_name]; + } + elseif ($current_options = $display->getComponent($field_name)) { + $settings = $current_options['settings']; + } - // Only save settings actually used by the selected formatter. - $default_settings = field_info_formatter_settings($values['type']); - $settings = array_intersect_key($settings, $default_settings); + // Only save settings actually used by the selected formatter. + $default_settings = field_info_formatter_settings($values['type']); + $settings = array_intersect_key($settings, $default_settings); - $instance['display'][$this->view_mode] = array( - 'label' => $values['label'], - 'type' => $values['type'], - 'weight' => $values['weight'], - 'settings' => $settings, - ); - field_update_instance($instance); + $display->setComponent($field_name, array( + 'label' => $values['label'], + 'type' => $values['type'], + 'weight' => $values['weight'], + 'settings' => $settings, + )); + } } - // Get current bundle settings. - $bundle_settings = field_bundle_settings($this->entity_type, $this->bundle); - - // Save data for 'extra' fields. + // Collect data for 'extra' fields. foreach ($form['#extra'] as $name) { - $bundle_settings['extra_fields']['display'][$name][$this->view_mode] = array( - 'weight' => $form_values['fields'][$name]['weight'], - 'visible' => $form_values['fields'][$name]['type'] == 'content', - ); + if ($form_values['fields'][$name]['type'] == 'hidden') { + $display->removeComponent($name); + } + else { + $display->setComponent($name, array( + 'weight' => $form_values['fields'][$name]['weight'], + )); + } } - // Save view modes data. + // Save the display. + $display->save(); + + // Handle the 'view modes' checkboxes if present. if ($this->view_mode == 'default' && !empty($form_values['view_modes_custom'])) { $entity_info = entity_get_info($this->entity_type); - foreach ($form_values['view_modes_custom'] as $view_mode_name => $value) { - // Display a message for each view mode newly configured to use custom - // settings. - $view_mode_settings = field_view_mode_settings($this->entity_type, $this->bundle); - if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) { - $view_mode_label = $entity_info['view_modes'][$view_mode_name]['label']; - $path = field_ui_bundle_admin_path($this->entity_type, $this->bundle) . "/display/$view_mode_name"; + $bundle_settings = field_bundle_settings($this->entity_type, $this->bundle); + $view_mode_settings = field_view_mode_settings($this->entity_type, $this->bundle); + + foreach ($form_values['view_modes_custom'] as $view_mode => $value) { + if (!empty($value) && empty($view_mode_settings[$view_mode]['custom_settings'])) { + // If no display exists for the newly enabled view mode, initialize + // it with those from the 'default' view mode, which were used so + // far. + if (!entity_load('entity_display', $this->entity_type . '.' . $this->bundle . '.' . $view_mode)) { + $display = entity_get_display($this->entity_type, $this->bundle, 'default')->createCopy($view_mode); + $display->save(); + } + + $view_mode_label = $entity_info['view_modes'][$view_mode]['label']; + $path = field_ui_bundle_admin_path($this->entity_type, $this->bundle) . "/display/$view_mode"; drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to configure them.', array('%view_mode' => $view_mode_label, '@url' => url($path)))); - // Initialize the newly customized view mode with the display settings - // from the default view mode. - _field_ui_add_default_view_mode_settings($this->entity_type, $this->bundle, $view_mode_name, $bundle_settings); } - $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value); + $bundle_settings['view_modes'][$view_mode]['custom_settings'] = !empty($value); } - } - // Save updated bundle settings. - field_bundle_settings($this->entity_type, $this->bundle, $bundle_settings); + // Save updated bundle settings. + field_bundle_settings($this->entity_type, $this->bundle, $bundle_settings); + } drupal_set_message(t('Your settings have been saved.')); } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php index 2d88051..a977df9 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -586,6 +586,13 @@ public function submit(array $form, array &$form_state) { field_create_field($field); field_create_instance($instance); + // Make sure the field is displayed in the 'default' view mode (using + // default formatter and settings). It stays hidden for other view + // modes until it is explicitly configured. + entity_get_display($this->entity_type, $this->bundle, 'default') + ->setComponent($field['field_name']) + ->save(); + // Always show the field settings step, as the cardinality needs to be // configured for new fields. $destinations[] = $this->adminPath. '/fields/' . $field['field_name'] . '/field-settings'; @@ -620,6 +627,14 @@ public function submit(array $form, array &$form_state) { try { field_create_instance($instance); + + // Make sure the field is displayed in the 'default' view mode (using + // default formatter and settings). It stays hidden for other view + // modes until it is explicitly configured. + entity_get_display($this->entity_type, $this->bundle, 'default') + ->setComponent($field['field_name']) + ->save(); + $destinations[] = $this->adminPath . '/fields/' . $instance['field_name']; // Store new field information for any additional submit handlers. $form_state['fields_added']['_add_existing_field'] = $instance['field_name']; diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php index 8396c7f..45de66e 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php @@ -44,12 +44,12 @@ function testFormatterUI() { $this->fieldUIAddNewField($manage_fields, $edit); // Clear the test-side cache and get the saved field instance. - field_info_cache_clear(); - $instance = field_info_instance('node', 'field_test', $this->type); - $format = $instance['display']['default']['type']; + $display = entity_get_display('node', $this->type, 'default'); + $display_options = $display->getComponent('field_test'); + $format = $display_options['type']; $default_settings = field_info_formatter_settings($format); $setting_name = key($default_settings); - $setting_value = $instance['display']['default']['settings'][$setting_name]; + $setting_value = $display_options['settings'][$setting_name]; // Display the "Manage display" screen and check that the expected formatter is // selected. @@ -67,12 +67,12 @@ function testFormatterUI() { $this->assertFieldByName('fields[field_test][type]', $format, 'The expected formatter is selected.'); $this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.'); - // Submit the form and check that the instance is updated. + // Submit the form and check that the display is updated. $this->drupalPost(NULL, array(), t('Save')); - field_info_cache_clear(); - $instance = field_info_instance('node', 'field_test', $this->type); - $current_format = $instance['display']['default']['type']; - $current_setting_value = $instance['display']['default']['settings'][$setting_name]; + $display = entity_get_display('node', $this->type, 'default'); + $display_options = $display->getComponent('field_test'); + $current_format = $display_options['type']; + $current_setting_value = $display_options['settings'][$setting_name]; $this->assertEqual($current_format, $format, 'The formatter was updated.'); $this->assertEqual($current_setting_value, $setting_value, 'The setting was updated.'); diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install index 728172e..b1e63de 100644 --- a/core/modules/forum/forum.install +++ b/core/modules/forum/forum.install @@ -90,18 +90,22 @@ function forum_enable() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - 'teaser' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - ), ); field_create_instance($instance); + + // Assign display settings for the 'default' and 'teaser' view modes. + entity_get_display('node', 'forum', 'default') + ->setComponent('taxonomy_forums', array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); + entity_get_display('node', 'forum', 'teaser') + ->setComponent('taxonomy_forums', array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); } // Ensure the forum node type is available. diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 221e07c..8312420 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -334,21 +334,23 @@ function image_image_style_save($style) { // Loop through all fields searching for image fields. foreach ($instances as $instance) { if ($instance['widget']['module'] == 'image') { - $instance_changed = FALSE; - foreach ($instance['display'] as $view_mode => $display) { + $entity_info = entity_get_info($instance['entity_type']); + $view_modes = array('default') + array_keys($entity_info['view_modes']); + foreach ($view_modes as $view_mode) { + $display = entity_get_display($instance['entity_type'], $instance['bundle'], $view_mode); + $display_options = $display->getComponent($instance['field_name']); + // Check if the formatter involves an image style. - if ($display['type'] == 'image' && $display['settings']['image_style'] == $style->getOriginalID()) { + if ($display_options && $display_options['type'] == 'image' && $display_options['settings']['image_style'] == $style->getOriginalID()) { // Update display information for any instance using the image // style that was just deleted. - $instance['display'][$view_mode]['settings']['image_style'] = $style->id(); - $instance_changed = TRUE; + $display_options['settings']['image_style'] = $style->id(); + $display->setComponent($instance['field_name'], $display_options) + ->save(); } } if ($instance['widget']['settings']['preview_image_style'] == $style->getOriginalID()) { $instance['widget']['settings']['preview_image_style'] = $style->id(); - $instance_changed = TRUE; - } - if ($instance_changed) { field_update_instance($instance); } } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php index 958610d..0d09461 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php @@ -253,10 +253,12 @@ function testStyleReplacement() { // Create an image field that uses the new style. $field_name = strtolower($this->randomName(10)); $this->createImageField($field_name, 'article'); - $instance = field_info_instance('node', $field_name, 'article'); - $instance['display']['default']['type'] = 'image'; - $instance['display']['default']['settings']['image_style'] = $style_name; - field_update_instance($instance); + entity_get_display('node', 'article', 'default') + ->setComponent($field_name, array( + 'type' => 'image', + 'settings' => array('image_style' => $style_name), + )) + ->save(); // Create a new node with an image attached. $test_image = current($this->drupalGetTestFiles('image')); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php index 46ce6c5..01fa5f4 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php @@ -69,6 +69,9 @@ function testDefaultImages() { ); field_create_instance($instance2); $instance2 = field_info_instance('node', $field_name, 'page'); + entity_get_display('node', 'page', 'default') + ->setComponent($field['field_name']) + ->save(); // Confirm the defaults are present on the article field settings form. $this->drupalGet("admin/structure/types/manage/article/fields/$field_name/field-settings"); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php index 85361ac..924bd2d 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php @@ -49,6 +49,7 @@ function testImageFieldFormattersPrivate() { function _testImageFieldFormatters($scheme) { $field_name = strtolower($this->randomName()); $this->createImageField($field_name, 'article', array('uri_scheme' => $scheme)); + // Create a new node with an image attached. $test_image = current($this->drupalGetTestFiles('image')); $nid = $this->uploadNodeImage($test_image, $field_name, 'article'); @@ -65,10 +66,14 @@ function _testImageFieldFormatters($scheme) { $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.'); // Test the image linked to file formatter. - $instance = field_info_instance('node', $field_name, 'article'); - $instance['display']['default']['type'] = 'image'; - $instance['display']['default']['settings']['image_link'] = 'file'; - field_update_instance($instance); + $display_options = array( + 'type' => 'image', + 'settings' => array('image_link' => 'file'), + ); + $display = entity_get_display('node', $node->type, 'default'); + $display->setComponent($field_name, $display_options) + ->save(); + $default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE)); $this->drupalGet('node/' . $nid); $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.'); @@ -91,16 +96,19 @@ function _testImageFieldFormatters($scheme) { } // Test the image linked to content formatter. - $instance['display']['default']['settings']['image_link'] = 'content'; - field_update_instance($instance); + $display_options['settings']['image_link'] = 'content'; + $display->setComponent($field_name, $display_options) + ->save(); $default_output = l(theme('image', $image_info), 'node/' . $nid, array('html' => TRUE, 'attributes' => array('class' => 'active'))); $this->drupalGet('node/' . $nid); $this->assertRaw($default_output, 'Image linked to content formatter displaying correctly on full node view.'); // Test the image style 'thumbnail' formatter. - $instance['display']['default']['settings']['image_link'] = ''; - $instance['display']['default']['settings']['image_style'] = 'thumbnail'; - field_update_instance($instance); + $display_options['settings']['image_link'] = ''; + $display_options['settings']['image_style'] = 'thumbnail'; + $display->setComponent($field_name, $display_options) + ->save(); + // Ensure the derivative image is generated so we do not have to deal with // image style callback paths. $this->drupalGet(image_style_url('thumbnail', $image_uri)); @@ -264,6 +272,9 @@ function testImageFieldDefaultImage() { 'files[field_settings_default_image]' => drupal_realpath($images[1]->uri), ); $this->drupalPost('admin/structure/types/manage/article/fields/' . $private_field_name . '/field-settings', $edit, t('Save field settings')); + // Clear field info cache so the new default image is detected. + field_info_cache_clear(); + $private_field = field_info_field($private_field_name); $image = file_load($private_field['settings']['default_image']); $this->assertEqual('private', file_uri_scheme($image->uri), 'Default image uses private:// scheme.'); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php index fc964ac..439db01 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php @@ -93,7 +93,15 @@ function createImageField($name, $type_name, $field_settings = array(), $instanc ); $instance['settings'] = array_merge($instance['settings'], $instance_settings); $instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings); - return field_create_instance($instance); + + $field_instance = field_create_instance($instance); + + entity_get_display('node', $type_name, 'default') + ->setComponent($field['field_name']) + ->save(); + + return $field_instance; + } /** diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php index a3366d2..a04a43f 100644 --- a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php +++ b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php @@ -62,13 +62,14 @@ function testURLValidation() { 'placeholder_url' => 'http://example.com', ), ), - 'display' => array( - 'full' => array( - 'type' => 'link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], array( + 'type' => 'link', + )) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form. @@ -130,14 +131,15 @@ function testLinkTitle() { 'placeholder_title' => 'Enter a title for this link', ), ), - 'display' => array( - 'full' => array( - 'type' => 'link', - 'label' => 'hidden', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], array( + 'type' => 'link', + 'label' => 'hidden', + )) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Verify that the title field works according to the field setting. @@ -235,14 +237,16 @@ function testLinkFormatter() { 'widget' => array( 'type' => 'link_default', ), - 'display' => array( - 'full' => array( - 'type' => 'link', - 'label' => 'hidden', - ), - ), + ); + $display_options = array( + 'type' => 'link', + 'label' => 'hidden', ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], $display_options) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Create an entity with two link field values: @@ -288,12 +292,14 @@ function testLinkFormatter() { foreach ($values as $new_value) { // Update the field formatter settings. if (!is_array($new_value)) { - $this->instance['display']['full']['settings'] = array($setting => $new_value); + $display_options['settings'] = array($setting => $new_value); } else { - $this->instance['display']['full']['settings'] = $new_value; + $display_options['settings'] = $new_value; } - field_update_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], $display_options) + ->save(); $this->renderTestEntity($id); switch ($setting) { @@ -367,14 +373,16 @@ function testLinkSeparateFormatter() { 'widget' => array( 'type' => 'link_default', ), - 'display' => array( - 'full' => array( - 'type' => 'link_separate', - 'label' => 'hidden', - ), - ), + ); + $display_options = array( + 'type' => 'link_separate', + 'label' => 'hidden', ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], $display_options) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Create an entity with two link field values: @@ -406,8 +414,10 @@ function testLinkSeparateFormatter() { foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the field formatter settings. - $this->instance['display']['full']['settings'] = array($setting => $new_value); - field_update_instance($this->instance); + $display_options['settings'] = array($setting => $new_value); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field['field_name'], $display_options) + ->save(); $this->renderTestEntity($id); switch ($setting) { @@ -461,8 +471,9 @@ protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) { entity_get_controller('test_entity')->resetCache(array($id)); } $entity = field_test_entity_test_load($id); - field_attach_prepare_view('test_entity', array($entity->id() => $entity), $view_mode); - $entity->content = field_attach_view('test_entity', $entity, $view_mode); + $display = entity_get_display($entity->entityType(), $entity->bundle(), $view_mode); + field_attach_prepare_view('test_entity', array($entity->id() => $entity), array($entity->bundle() => $display)); + $entity->content = field_attach_view('test_entity', $entity, $display); $output = drupal_render($entity->content); $this->drupalSetContent($output); diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index 0b892eb..4f5315e 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -398,4 +398,19 @@ public function delete(array $form, array &$form_state) { $node = $this->getEntity($form_state); $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination)); } + + /** + * Overrides \Drupal\Core\Entity\EntityFormController::buildEntity(). + */ + public function buildEntity(array $form, array &$form_state) { + $node = parent::buildEntity($form, $form_state); + // If the node went through 'Preview', it got stored back in $form_state + // with values out of the 'prepare_view' steps, and with the + // entity_view_prepared flag set. Since buildEntity() resets the values to + // those in the form submission, the entity_view_prepared flag needs to be + // reset too so that the next 'Preview' can work on a consistent $node. + unset($node->entity_view_prepared); + return $node; + } + } diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php index 8dd2ab6..1794e89 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php @@ -45,6 +45,9 @@ public function setUp() { 'bundle' => 'page', ); $this->instance = field_create_instance($instance); + entity_get_display('node', 'page', 'default') + ->setComponent($this->field_name) + ->save(); } /** diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php index 5c906d7..b689141 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php @@ -118,11 +118,11 @@ function testLanguageFieldVisibility() { // Changes Language field visibility to true and check if it is saved. $edit = array( - 'fields[language][type]' => 'content', + 'fields[language][type]' => 'visible', ); $this->drupalPost('admin/structure/types/manage/article/display', $edit, t('Save')); $this->drupalGet('admin/structure/types/manage/article/display'); - $this->assertOptionSelected('edit-fields-language-type', 'content', 'Language field has been set to visible.'); + $this->assertOptionSelected('edit-fields-language-type', 'visible', 'Language field has been set to visible.'); // Loads node page and check if Language field is shown. $this->drupalGet('node/' . $node->nid); diff --git a/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php b/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php index 4276146..6b966e8 100644 --- a/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php @@ -46,9 +46,11 @@ function testSummaryLength() { $this->assertRaw($expected); // Change the teaser length for "Basic page" content type. - $instance = field_info_instance('node', 'body', $node->type); - $instance['display']['teaser']['settings']['trim_length'] = 200; - field_update_instance($instance); + $display = entity_get_display('node', $node->type, 'teaser'); + $display_options = $display->getComponent('body'); + $display_options['settings']['trim_length'] = 200; + $display->setComponent('body', $display_options) + ->save(); // Render the node as a teaser again and check that the summary is now only // 200 characters in length and so does not include 'What is a Drupalism?'. diff --git a/core/modules/node/node.module b/core/modules/node/node.module index a37679c..d56bee5 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -19,6 +19,7 @@ use Drupal\node\Plugin\Core\Entity\Node; use Drupal\file\Plugin\Core\Entity\File; use Drupal\Core\Entity\EntityInterface; +use Drupal\entity\Plugin\Core\Entity\EntityDisplay; /** * Denotes that the node is not published. @@ -212,12 +213,17 @@ function node_entity_info(&$info) { } /** - * Implements hook_field_display_ENTITY_TYPE_alter(). + * Implements hook_entity_display_alter(). */ -function node_field_display_node_alter(&$display, $context) { +function node_entity_display_alter(EntityDisplay $display, $context) { // Hide field labels in search index. - if ($context['view_mode'] == 'search_index') { - $display['label'] = 'hidden'; + 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); + } + } } } @@ -559,19 +565,24 @@ function node_add_body_field($type, $label = 'Body') { 'label' => $label, 'widget' => array('type' => 'text_textarea_with_summary'), 'settings' => array('display_summary' => TRUE), - 'display' => array( - 'default' => array( - 'label' => 'hidden', - 'type' => 'text_default', - ), - 'teaser' => array( - 'label' => 'hidden', - 'type' => 'text_summary_or_trimmed', - ), - ), ); $instance = field_create_instance($instance); + + // Assign display settings for the 'default' and 'teaser' view modes. + entity_get_display('node', $type->type, 'default') + ->setComponent($field['field_name'], array( + 'label' => 'hidden', + 'type' => 'text_default', + )) + ->save(); + entity_get_display('node', $type->type, 'teaser') + ->setComponent($field['field_name'], array( + 'label' => 'hidden', + 'type' => 'text_summary_or_trimmed', + )) + ->save(); } + return $instance; } diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 0a18ec1..245fef7 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -144,8 +144,6 @@ function node_preview(Node $node) { } $node->changed = REQUEST_TIME; - $nodes = array($node->nid => $node); - field_attach_prepare_view('node', $nodes, 'full'); // Display a preview of the node. if (!form_get_errors()) { @@ -175,9 +173,7 @@ function theme_node_preview($variables) { $output = ''; - $preview_trimmed_version = FALSE; - - $elements = node_view(clone $node, 'teaser'); + $elements = node_view($node, 'teaser'); $elements['#attached']['library'][] = array('node', 'drupal.node.preview'); $trimmed = drupal_render($elements); $elements = node_view($node, 'full'); diff --git a/core/modules/node/node.tokens.inc b/core/modules/node/node.tokens.inc index 2d783c9..8827b98 100644 --- a/core/modules/node/node.tokens.inc +++ b/core/modules/node/node.tokens.inc @@ -149,7 +149,19 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr // A summary was requested. if ($name == 'summary') { // Generate an optionally trimmed summary of the body field. - $output = text_summary($output, $instance['settings']['text_processing'] ? $items[0]['format'] : NULL, $instance['display']['teaser']['settings']['trim_length']); + + // Get the 'trim_length' size used for the 'teaser' mode, if + // present, or use the default trim_length size. + $display_options = entity_get_display('node', $node->type, 'teaser')->getComponent('body'); + if (isset($display_options['settings']['trim_length'])) { + $length = $display_options['settings']['trim_length']; + } + else { + $settings = field_info_formatter_settings('text_summary_or_trimmed'); + $length = $settings['trim_length']; + } + + $output = text_summary($output, $instance['settings']['text_processing'] ? $items[0]['format'] : NULL, $length); } } $replacements[$original] = $output; diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php index 7588942..232acea 100644 --- a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php +++ b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php @@ -70,6 +70,9 @@ function testNumberDecimalField() { ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'default') + ->setComponent($this->field['field_name']) + ->save(); // Display creation form. $this->drupalGet('test-entity/add/test_bundle'); diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php index d61eebb..6804b6a 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php @@ -489,9 +489,9 @@ function testOnOffCheckbox() { 'entity_type' => 'node', 'bundle' => 'page', 'widget' => array( - 'type' => 'options_onoff', - 'module' => 'options', - ), + 'type' => 'options_onoff', + 'module' => 'options', + ), ); field_create_instance($instance); diff --git a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php index 69b0231..de0f782 100644 --- a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php +++ b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php @@ -120,11 +120,6 @@ public function _testPictureFieldFormatters($scheme) { $nid = $this->uploadNodeImage($test_image, $field_name, 'article'); $node = node_load($nid, TRUE); - // Use the picture formatter. - $instance = field_info_instance('node', $field_name, 'article'); - $instance['display']['default']['type'] = 'picture'; - $instance['display']['default']['module'] = 'picture'; - // Test that the default formatter is being used. $image_uri = file_load($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid'])->uri; $image_info = array( @@ -136,11 +131,15 @@ public function _testPictureFieldFormatters($scheme) { $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.'); // Use the picture formatter linked to file formatter. - $instance = field_info_instance('node', $field_name, 'article'); - $instance['display']['default']['type'] = 'picture'; - $instance['display']['default']['module'] = 'picture'; - $instance['display']['default']['settings']['image_link'] = 'file'; - field_update_instance($instance); + $display_options = array( + 'type' => 'picture', + 'module' => 'picture', + 'settings' => array('image_link' => 'file'), + ); + $display = entity_get_display('node', 'article', 'default'); + $display->setComponent($field_name, $display_options) + ->save(); + $default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE)); $this->drupalGet('node/' . $nid); $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.'); @@ -163,8 +162,10 @@ public function _testPictureFieldFormatters($scheme) { } // Use the picture formatter with a picture mapping. - $instance['display']['default']['settings']['picture_mapping'] = 'mapping_one'; - field_update_instance($instance); + $display_options['settings']['picture_mapping'] = 'mapping_one'; + $display->setComponent($field_name, $display_options) + ->save(); + // Output should contain all image styles and all breakpoints. $this->drupalGet('node/' . $nid); $this->assertRaw('/styles/thumbnail/'); @@ -175,9 +176,10 @@ public function _testPictureFieldFormatters($scheme) { $this->assertRaw('media="(min-width: 600px)"'); // Test the fallback image style. - $instance['display']['default']['settings']['image_link'] = ''; - $instance['display']['default']['settings']['fallback_image_style'] = 'large'; - field_update_instance($instance); + $display_options['settings']['image_link'] = ''; + $display_options['settings']['fallback_image_style'] = 'large'; + $display->setComponent($field_name, $display_options) + ->save(); $this->drupalGet(image_style_url('large', $image_uri)); $image_info['uri'] = $image_uri; diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php index db24097..368d221 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php @@ -115,13 +115,13 @@ function testAttributesInMarkupFile() { 'field_name' => $field_name, 'entity_type' => 'node', 'bundle' => $bundle_name, - 'display' => array( - 'teaser' => array( - 'type' => 'file_default', - ), - ), ); field_create_instance($instance); + entity_get_display('node', $bundle_name, 'teaser') + ->setComponent($field_name, array( + 'type' => 'file_default', + )) + ->save(); // Set the RDF mapping for the new field. $rdf_mapping = rdf_mapping_load('node', $bundle_name); diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php new file mode 100644 index 0000000..c0de21b --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php @@ -0,0 +1,90 @@ + 'Field upgrade test', + 'description' => 'Tests upgrade of Field API.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + $this->databaseDumpFiles = array( + drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz', + drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.field.database.php', + ); + parent::setUp(); + } + + /** + * Tests upgrade of entity displays. + */ + public function testEntityDisplayUpgrade() { + $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); + + // Check that the configuration entries were created. + $displays = array( + 'default' => config('entity.display.node.article.default')->get(), + 'teaser' => config('entity.display.node.article.teaser')->get(), + ); + $this->assertTrue(!empty($displays['default'])); + $this->assertTrue(!empty($displays['teaser'])); + + // Check that manifest entries for the 'article' node type were correctly + // created. + $manifest = config('manifest.entity.display'); + $data = $manifest->get(); + $this->assertEqual($data['node.article.default'], array('name' => 'entity.display.node.article.default')); + $this->assertEqual($data['node.article.teaser'], array('name' => 'entity.display.node.article.teaser')); + + // Check that the 'body' field is configured as expected. + $expected = array( + 'default' => array( + 'label' => 'hidden', + 'type' => 'text_default', + 'weight' => 0, + 'settings' => array(), + ), + 'teaser' => array( + 'label' => 'hidden', + 'type' => 'text_summary_or_trimmed', + 'weight' => 0, + 'settings' => array( + 'trim_length' => 600, + ), + ), + ); + $this->assertEqual($displays['default']['content']['body'], $expected['default']); + $this->assertEqual($displays['teaser']['content']['body'], $expected['teaser']); + + // Check that the display key in the instance data was removed. + $body_instance = field_info_instance('node', 'body', 'article'); + $this->assertTrue(!isset($body_instance['display'])); + + // Check that the 'language' extra field is configured as expected. + $expected = array( + 'default' => array( + 'weight' => -1, + 'visible' => 1, + ), + 'teaser' => array( + 'visible' => 0, + ), + ); + $this->assertEqual($displays['default']['content']['language'], $expected['default']); + $this->assertEqual($displays['teaser']['content']['language'], $expected['teaser']); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php index d86f7cd..04070c9 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php @@ -57,7 +57,9 @@ public function testUserPictureUpgrade() { $this->assertEqual($instance['settings']['max_filesize'], '700 KB', 'User picture maximum filesize has been migrated.'); $this->assertEqual($instance['description'], 'These are user picture guidelines.', 'User picture guidelines are now the user picture field description.'); $this->assertEqual($instance['settings']['file_directory'], 'user_pictures_dir', 'User picture directory path has been migrated.'); - $this->assertEqual($instance['display']['default']['settings']['image_style'], 'thumbnail', 'User picture image style setting has been migrated.'); + + $display_options = entity_get_display('user', 'user', 'default')->getComponent('user_picture'); + $this->assertEqual($display_options['settings']['image_style'], 'thumbnail', 'User picture image style setting has been migrated.'); // Verify compact view mode default settings. $this->drupalGet('admin/config/people/accounts/display/compact'); diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index dcc020a..f2b5b38 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -19,6 +19,32 @@ function entity_test_entity_info_alter(&$info) { } /** + * Implements hook_field_extra_fields(). + */ +function entity_test_field_extra_fields() { + $extra['entity_test']['entity_test'] = array( + 'display' => array( + // Note: those extra fields do not currently display anything, they are + // just used in \Drupal\entity\Tests\EntityDisplayTest to test the + // behavior of entity display objects, + 'display_extra_field' => array( + 'label' => t('Display extra field'), + 'description' => t('An extra field on the display side.'), + 'weight' => 5, + 'visible' => TRUE, + ), + 'display_extra_field_hidden' => array( + 'label' => t('Display extra field (hidden)'), + 'description' => t('An extra field on the display side, hidden by default.'), + 'visible' => FALSE, + ), + ) + ); + + return $extra; +} + +/** * Implements hook_permission(). */ function entity_test_permission() { diff --git a/core/modules/system/tests/upgrade/drupal-7.field.database.php b/core/modules/system/tests/upgrade/drupal-7.field.database.php new file mode 100644 index 0000000..0862650 --- /dev/null +++ b/core/modules/system/tests/upgrade/drupal-7.field.database.php @@ -0,0 +1,51 @@ + array( + 'teaser' => array( + 'custom_settings' => 1, + ), + 'full' => array( + 'custom_settings' => 0, + ), + 'rss' => array( + 'custom_settings' => 0, + ), + 'search_index' => array( + 'custom_settings' => 0, + ), + 'search_result' => array( + 'custom_settings' => 0, + ), + ), + 'extra_fields' => array( + 'form' => array(), + 'display' => array( + 'language' => array( + 'default' => array( + 'weight' => -1, + 'visible' => 1, + ), + 'teaser' => array( + 'weight' => 0, + 'visible' => 0, + ), + ), + ), + ), +); +db_insert('variable') + ->fields(array( + 'name' => 'field_bundle_settings_node__article', + 'value' => serialize($value), + )) + ->execute(); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermRenderController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermRenderController.php index c22f6e3..ac44448 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermRenderController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermRenderController.php @@ -23,13 +23,12 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la foreach ($entities as $entity) { // Add the description if enabled. - $bundle = $entity->bundle(); $entity_view_mode = $entity->content['#view_mode']; - $fields = field_extra_fields_get_display($this->entityType, $bundle, $entity_view_mode); - if (!empty($entity->description) && isset($fields['description']) && $fields['description']['visible']) { + $display = field_extra_fields_get_display($entity, $entity_view_mode); + if (!empty($entity->description) && !empty($display['description'])) { $entity->content['description'] = array( '#markup' => check_markup($entity->description, $entity->format, '', TRUE), - '#weight' => $fields['description']['weight'], + '#weight' => $display['description']['weight'], '#prefix' => '
', '#suffix' => '
', ); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php index 505f850..278db90 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php @@ -56,13 +56,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('node', 'article', 'default') + ->setComponent('taxonomy_' . $this->vocabulary->id(), array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php index 565bb98..25bcc07 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php @@ -66,13 +66,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'full' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field_name, array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** @@ -98,8 +98,9 @@ function testTaxonomyTermFieldMultipleVocabularies() { // Render the entity. $entity = field_test_entity_test_load($id); $entities = array($id => $entity); - field_attach_prepare_view('test_entity', $entities, 'full'); - $entity->content = field_attach_view('test_entity', $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display)); + $entity->content = field_attach_view('test_entity', $entity, $display); $this->content = drupal_render($entity->content); $this->assertText($term1->name, 'Term 1 name is displayed.'); $this->assertText($term2->name, 'Term 2 name is displayed.'); @@ -110,8 +111,9 @@ function testTaxonomyTermFieldMultipleVocabularies() { // Re-render the content. $entity = field_test_entity_test_load($id); $entities = array($id => $entity); - field_attach_prepare_view('test_entity', $entities, 'full'); - $entity->content = field_attach_view('test_entity', $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display)); + $entity->content = field_attach_view('test_entity', $entity, $display); $this->plainTextContent = FALSE; $this->content = drupal_render($entity->content); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php index a82a1fa..c20acf7 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php @@ -61,13 +61,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'full' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field_name, array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** @@ -123,8 +123,9 @@ function testTaxonomyTermFieldWidgets() { // Display the object. $entity = field_test_entity_test_load($id); $entities = array($id => $entity); - field_attach_prepare_view('test_entity', $entities, 'full'); - $entity->content = field_attach_view('test_entity', $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display)); + $entity->content = field_attach_view('test_entity', $entity, $display); $this->content = drupal_render($entity->content); $this->assertText($term->label(), 'Term label is displayed.'); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php index fe91863..f9cba0d 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php @@ -52,13 +52,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance_1); + entity_get_display('node', 'article', 'default') + ->setComponent($this->field_name_1, array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); $this->field_name_2 = drupal_strtolower($this->randomName()); $this->field_2 = array( @@ -82,13 +82,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance_2); + entity_get_display('node', 'article', 'default') + ->setComponent($this->field_name_2, array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php index 1dbe5f8..93cc8d4 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php @@ -48,13 +48,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('node', 'article', 'default') + ->setComponent($this->instance['field_name'], array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php index 6a28ca3..ea73152 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php @@ -49,13 +49,13 @@ function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('node', 'article', 'default') + ->setComponent('taxonomy_' . $this->vocabulary->id(), array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); } /** diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php index e1b3935..67adc3a 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php @@ -104,18 +104,21 @@ protected function mockStandardInstall() { 'type' => 'taxonomy_autocomplete', 'weight' => -4, ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - 'teaser' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - ), ); field_create_instance($instance); + + entity_get_display('node', 'article', 'default') + ->setComponent($instance['field_name'], array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); + entity_get_display('node', 'article', 'teaser') + ->setComponent($instance['field_name'], array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); } /** diff --git a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php index 8efc516..6bf7fe4 100644 --- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php @@ -65,13 +65,12 @@ function testTextFieldValidation() { 'widget' => array( 'type' => 'text_textfield', ), - 'display' => array( - 'default' => array( - 'type' => 'text_default', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'default') + ->setComponent($this->field['field_name']) + ->save(); + // Test valid and invalid values with field_attach_validate(). $entity = field_test_create_entity(); $langcode = LANGUAGE_NOT_SPECIFIED; @@ -118,13 +117,12 @@ function _testTextfieldWidgets($field_type, $widget_type) { 'placeholder' => 'A placeholder on ' . $widget_type, ), ), - 'display' => array( - 'full' => array( - 'type' => 'text_default', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field_name) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form. @@ -145,7 +143,8 @@ function _testTextfieldWidgets($field_type, $widget_type) { // Display the entity. $entity = field_test_entity_test_load($id); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + $entity->content = field_attach_view($entity_type, $entity, $display); $this->content = drupal_render($entity->content); $this->assertText($value, 'Filtered tags are not displayed'); } @@ -178,13 +177,12 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) { 'widget' => array( 'type' => $widget_type, ), - 'display' => array( - 'full' => array( - 'type' => 'text_default', - ), - ), ); field_create_instance($this->instance); + entity_get_display('test_entity', 'test_bundle', 'full') + ->setComponent($this->field_name) + ->save(); + $langcode = LANGUAGE_NOT_SPECIFIED; // Disable all text formats besides the plain text fallback format. @@ -214,7 +212,8 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) { // Display the entity. $entity = field_test_entity_test_load($id); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + $entity->content = field_attach_view($entity_type, $entity, $display); $this->content = drupal_render($entity->content); $this->assertNoRaw($value, 'HTML tags are not displayed.'); $this->assertRaw(check_plain($value), 'Escaped HTML is displayed correctly.'); @@ -254,7 +253,8 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) { // Display the entity. entity_get_controller('test_entity')->resetCache(array($id)); $entity = field_test_entity_test_load($id); - $entity->content = field_attach_view($entity_type, $entity, 'full'); + $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full'); + $entity->content = field_attach_view($entity_type, $entity, $display); $this->content = drupal_render($entity->content); $this->assertRaw($value, 'Value is displayed unfiltered'); } diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 705a725..cc0bfeb 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -388,34 +388,32 @@ function user_install_picture_field() { ), 'weight' => -1, ), - 'display' => array( - 'default' => array( - 'label' => 'hidden', - 'type' => 'image', - 'settings' => array( - 'image_style' => 'thumbnail', - 'image_link' => 'content', - ), - ), - 'compact' => array( - 'label' => 'hidden', - 'type' => 'image', - 'settings' => array( - 'image_style' => 'thumbnail', - 'image_link' => 'content', - ), - ), - ), ); field_create_instance($instance); - // Remove 'summary' pseudo-field from compact view mode on the User entity. - $bundle_settings = field_bundle_settings('user', 'user'); - $bundle_settings['extra_fields']['display']['member_for']['compact'] = array( - 'visible' => FALSE, - 'weight' => 10, - ); - field_bundle_settings('user', 'user', $bundle_settings); + // Assign display settings for the 'default' and 'compact' view modes. + entity_get_display('user', 'user', 'default') + ->setComponent('user_picture', array( + 'label' => 'hidden', + 'type' => 'image', + 'settings' => array( + 'image_style' => 'thumbnail', + 'image_link' => 'content', + ), + )) + ->save(); + entity_get_display('user', 'user', 'compact') + ->setComponent('user_picture', array( + 'label' => 'hidden', + 'type' => 'image', + 'settings' => array( + 'image_style' => 'thumbnail', + 'image_link' => 'content', + ), + )) + // Additionally, hide 'summary' pseudo-field from compact view mode.. + ->removeComponent('member_for') + ->save(); } /** @@ -761,14 +759,6 @@ function user_update_8011() { ); _update_7000_field_create_field($field); - // In D7, user pictures did not require Image module to work. Image module - // only allowed usage of an image style to format user pictures in the - // output. The 'user_pictures' variable had a global effect on the presence - // of the user picture functionality before. The new user picture image field - // is created regardless of that global setting, which means the field - // appears on the user account form after migration, even if user pictures - // were disabled previously. The picture is only hidden in the output. - $formatter = update_variable_get('user_pictures', 0) ? 'image' : 'hidden'; $instance = array( 'field_name' => 'user_picture', 'entity_type' => 'user', @@ -795,27 +785,46 @@ function user_update_8011() { ), 'weight' => -1, ), - 'display' => array( - 'default' => array( - 'label' => 'hidden', - 'type' => $formatter, - 'settings' => array( - 'image_style' => 'thumbnail', - 'image_link' => 'content', - ), - ), - 'compact' => array( - 'label' => 'hidden', - 'type' => $formatter, - 'settings' => array( - 'image_style' => update_variable_get('user_picture_style', ''), - 'image_link' => 'content', - ), - ), - ), ); _update_7000_field_create_instance($field, $instance); + // Assign display settings for the 'default' and 'compact' view modes. In D7, + // user pictures did not require Image module to work. Image module only + // allowed usage of an image style to format user pictures in the output. + // The 'user_pictures' variable had a global effect on the presence of the + // user picture functionality before. The new user picture image field is + // created regardless of that global setting, which means the field appears + // on the user account form after migration, even if user pictures were + // disabled previously. The picture is only hidden in the output. + $formatter = update_variable_get('user_pictures', 0) ? 'image' : 'hidden'; + module_load_install('entity'); + + $display = _update_8000_entity_get_display('user', 'user', 'default'); + $display->set('content.user_picture', array( + 'label' => 'hidden', + 'type' => $formatter, + 'settings' => array( + 'image_style' => 'thumbnail', + 'image_link' => 'content', + ), + 'weight' => 0, + )) + ->save(); + update_config_manifest_add('entity.display', array($display->get('id'))); + + $display = _update_8000_entity_get_display('user', 'user', 'compact'); + $display->set('content.user_picture', array( + 'label' => 'hidden', + 'type' => $formatter, + 'settings' => array( + 'image_style' => update_variable_get('user_picture_style', ''), + 'image_link' => 'content', + ), + 'weight' => 0, + )) + ->save(); + update_config_manifest_add('entity.display', array($display->get('id'))); + // Add file usage for the default field. if (!empty($default_image_fid)) { db_insert('file_usage') diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php index 201fdae..1e5b72f 100644 --- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php @@ -77,13 +77,13 @@ protected function setUp() { 'widget' => array( 'type' => 'options_select', ), - 'display' => array( - 'full' => array( - 'type' => 'taxonomy_term_reference_link', - ), - ), ); field_create_instance($this->instance); + entity_get_display('node', 'page', 'full') + ->setComponent($this->field_name, array( + 'type' => 'taxonomy_term_reference_link', + )) + ->save(); // Create a time in the past for the archive. $time = time() - 3600; diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php index 8e51e56..693ed68 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php @@ -77,18 +77,21 @@ function setUp() { 'widget' => array( 'type' => 'taxonomy_autocomplete', ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - 'teaser' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - ), ); field_create_instance($this->tag_instance); + + entity_get_display('node', $this->node_type_with_tags->type, 'default') + ->setComponent('field_views_testing_tags', array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); + entity_get_display('node', $this->node_type_with_tags->type, 'teaser') + ->setComponent('field_views_testing_tags', array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); } /** diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install index 48da6b1..0961820 100644 --- a/core/profiles/standard/standard.install +++ b/core/profiles/standard/standard.install @@ -295,19 +295,22 @@ function standard_install() { 'type' => 'taxonomy_autocomplete', 'weight' => -4, ), - 'display' => array( - 'default' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - 'teaser' => array( - 'type' => 'taxonomy_term_reference_link', - 'weight' => 10, - ), - ), ); field_create_instance($instance); + // Assign display settings for the 'default' and 'teaser' view modes. + entity_get_display('node', 'article', 'default') + ->setComponent($instance['field_name'], array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); + entity_get_display('node', 'article', 'teaser') + ->setComponent($instance['field_name'], array( + 'type' => 'taxonomy_term_reference_link', + 'weight' => 10, + )) + ->save(); // Create an image field named "Image", enabled for the 'article' content type. // Many of the following values will be defaulted, they're included here as an illustrative examples. @@ -359,24 +362,27 @@ function standard_install() { ), 'weight' => -1, ), - - 'display' => array( - 'default' => array( - 'label' => 'hidden', - 'type' => 'image', - 'settings' => array('image_style' => 'large', 'image_link' => ''), - 'weight' => -1, - ), - 'teaser' => array( - 'label' => 'hidden', - 'type' => 'image', - 'settings' => array('image_style' => 'medium', 'image_link' => 'content'), - 'weight' => -1, - ), - ), ); field_create_instance($instance); + // Assign display settings for the 'default' and 'teaser' view modes. + entity_get_display('node', 'article', 'default') + ->setComponent($instance['field_name'], array( + 'label' => 'hidden', + 'type' => 'image', + 'settings' => array('image_style' => 'large', 'image_link' => ''), + 'weight' => -1, + )) + ->save(); + entity_get_display('node', 'article', 'teaser') + ->setComponent($instance['field_name'], array( + 'label' => 'hidden', + 'type' => 'image', + 'settings' => array('image_style' => 'medium', 'image_link' => 'content'), + 'weight' => -1, + )) + ->save(); + // Create user picture field. module_load_install('user'); user_install_picture_field();