diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 9c9d123..85aa4a7 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -535,3 +535,91 @@ function hook_entity_field_info_alter(&$info, $entity_type) { $info['definitions']['mymodule_text']['class'] = '\Drupal\anothermodule\EntityComputedText'; } } + +/** + * Act on view modes when loaded. + * + * @param array $entities + * The view modes keyed by name. + */ +function hook_view_mode_load($entities) { + foreach ($entities as $entity) { + $entity->foo = mymodule_add_something($entity); + } +} + +/** + * Act on an view mode before it is about to be created or updated. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The view mode object. + */ +function hook_view_mode_presave(Drupal\Core\Entity\EntityInterface $entity) { + entity_info_cache_clear(); + state()->set('menu_rebuild_needed', TRUE); +} + +/** + * Act on view modes when inserted. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The view mode object. + */ +function hook_view_mode_insert(Drupal\Core\Entity\EntityInterface $entity) { + // Insert the new view mode into a fictional table of all view modes. + db_insert('example_view_mode') + ->fields(array( + 'type' => $entity->entityType(), + 'id' => $entity->id(), + 'created' => REQUEST_TIME, + 'updated' => REQUEST_TIME, + )) + ->execute(); +} + +/** + * Act on view modes when updated. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The view mode object. + */ +function hook_view_mode_update(Drupal\Core\Entity\EntityInterface $entity) { + // Update the view mode's entry in a fictional table of all view modes. + db_update('example_view_mode') + ->fields(array( + 'updated' => REQUEST_TIME, + )) + ->condition('type', $entity->entityType()) + ->condition('id', $entity->id()) + ->execute(); +} + +/** + * Act before view mode deletion. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The view mode object for the view mode that is about to be deleted. + */ +function hook_view_mode_predelete(Drupal\Core\Entity\EntityInterface $entity) { + // Count references to this view mode in a custom table before they are + // removed upon view mode deletion. + $id = $entity->id(); + $type = $entity->entityType(); + $count = db_select('example_view_mode_data') + ->condition('type', $type) + ->condition('id', $id) + ->countQuery() + ->execute() + ->fetchField(); +} + +/** + * Respond to view mode deletion. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The view mode object for the view mode that has been deleted. + */ +function hook_view_mode_delete(Drupal\Core\Entity\EntityInterface $entity) { + entity_info_cache_clear(); + state()->set('menu_rebuild_needed', TRUE); +} diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 75c3386..639c53d 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -82,6 +82,20 @@ function entity_get_info($entity_type = NULL) { } } } + + // Add view modes. + $view_modes = drupal_container()->get('config.storage')->listAll('view_mode.'); + foreach ($view_modes as $config_name) { + $view_mode = config($config_name)->get(); + $definition = array( + 'label' => check_plain($view_mode['label']), + 'custom settings' => FALSE, + ); + foreach (array_filter($view_mode['entityTypes']) as $key => $value) { + $entity_info[$key]['view modes'][$view_mode['name']] = $definition; + } + } + // Let other modules alter the entity info. drupal_alter('entity_info', $entity_info); cache()->set("entity_info:$langcode", $entity_info, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE)); diff --git a/core/lib/Drupal/Core/Entity/EntityViewMode.php b/core/lib/Drupal/Core/Entity/EntityViewMode.php new file mode 100644 index 0000000..564c1ea --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityViewMode.php @@ -0,0 +1,78 @@ +name; + } + + /** + * Overrides Drupal\Core\Core\Entity\Entity::uri(). + */ + public function uri() { + return array( + 'path' => 'admin/config/system/view-modes/' . $this->id(), + 'options' => array( + 'entity_type' => $this->entityType, + 'entity' => $this, + ), + ); + } + + /** + * Returns the entity types that are used by the view mode. + * + * @return array + * An array where both keys and values are entity types for the view mode. + */ + public function getUsedEntityTypes() { + return array_filter($this->entityTypes); + } + +} diff --git a/core/modules/entity_ui/entity_ui.admin.inc b/core/modules/entity_ui/entity_ui.admin.inc new file mode 100644 index 0000000..8b55c90 --- /dev/null +++ b/core/modules/entity_ui/entity_ui.admin.inc @@ -0,0 +1,55 @@ +render(); +} + +/** + * Menu callback: view mode edit form. + */ +function view_mode_add() { + $view_mode = entity_create('view_mode', array()); + return entity_get_form($view_mode); +} + +/** + * Menu callback: view mode delete confirm form. + */ +function view_mode_delete_form($form, $form_state, $view_mode) { + $form['#view_mode'] = $view_mode; + + $form['name'] = array( + '#type' => 'value', + '#value' => $view_mode->id(), + ); + + return confirm_form( + $form, + t('Are you sure you want to delete the %view-mode view mode?', array( + '%view-mode' => $view_mode->label(), + )), + 'admin/config/system/view-modes', + t('Deleting a view mode will cause any output still requesting to use that view mode to use the default display settings.'), + t('Delete'), + t('Cancel') + ); +} + +/** + * Submit handler: delete a view mode. + */ +function view_mode_delete_form_submit($form, &$form_state) { + drupal_set_message(t('Deleted the %view-mode view mode.', array( + '%view-mode' => $form['#view_mode']->label(), + ))); + $form['#view_mode']->delete(); + $form_state['redirect'] = 'admin/config/system/view-modes'; +} diff --git a/core/modules/entity_ui/entity_ui.info b/core/modules/entity_ui/entity_ui.info new file mode 100644 index 0000000..9dcc4e5 --- /dev/null +++ b/core/modules/entity_ui/entity_ui.info @@ -0,0 +1,7 @@ +name = Entity UI +description = User interface for the Entity API. +package = Core +version = VERSION +core = 8.x +recommends[] = field_ui +configure = admin/config/system/view-modes diff --git a/core/modules/entity_ui/entity_ui.module b/core/modules/entity_ui/entity_ui.module new file mode 100644 index 0000000..5c14354 --- /dev/null +++ b/core/modules/entity_ui/entity_ui.module @@ -0,0 +1,88 @@ + array( + 'title' => t('Add, edit and delete custom view modes.'), + ), + ); +} + +/** + * Implements hook_entity_info_alter(). + */ +function entity_ui_entity_info_alter(&$entity_info) { + // Add a list and form controller for the view mode entity type. + $entity_info['view_mode']['list controller class'] = 'Drupal\entity_ui\ViewModeListController'; + $entity_info['view_mode']['form controller class'] = array( + 'default' => 'Drupal\entity_ui\ViewModeFormController', + ); +} + +/** + * Implements hook_menu(). + */ +function entity_ui_menu() { + $items['admin/config/system/view-modes'] = array( + 'title' => 'View modes', + 'description' => 'Manage custom view modes.', + 'page callback' => 'view_mode_list', + 'access arguments' => array('administer view modes'), + 'file' => 'entity_ui.admin.inc', + ); + $items['admin/config/system/view-modes/add'] = array( + 'title' => 'Add view mode', + 'page callback' => 'view_mode_add', + 'access arguments' => array('administer view modes'), + 'file' => 'entity_ui.admin.inc', + 'type' => MENU_LOCAL_ACTION, + ); + $items['admin/config/system/view-modes/%view_mode/edit'] = array( + 'title' => 'Edit view mode', + 'page callback' => 'entity_get_form', + 'page arguments' => array(4), + 'access arguments' => array('administer view modes'), + ); + $items['admin/config/system/view-modes/%view_mode/delete'] = array( + 'title' => 'Delete view mode', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('view_mode_delete_form', 4), + 'access arguments' => array('administer view modes'), + 'file' => 'entity_ui.admin.inc', + ); + + return $items; +} + +/** + * Load a custom view mode by machine name. + */ +function view_mode_load($machine_name) { + return entity_load('view_mode', $machine_name); +} + +/** + * Implements hook_view_mode_presave(). + */ +function entity_ui_view_mode_presave(EntityInterface $entity) { + entity_info_cache_clear(); + state()->set('menu_rebuild_needed', TRUE); +} + +/** + * Implements hook_view_mode_delete(). + */ +function entity_ui_view_mode_delete(EntityInterface $entity) { + entity_info_cache_clear(); + state()->set('menu_rebuild_needed', TRUE); +} diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php b/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php new file mode 100644 index 0000000..e369da4 --- /dev/null +++ b/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php @@ -0,0 +1,91 @@ + 'View modes', + 'description' => 'Tests for managing custom view modes.', + 'group' => 'Entity UI', + ); + } + + function setUp() { + parent::setUp(); + + $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'administer users', 'administer view modes', 'access administration pages'))); + $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); + } + + /** + * Creates a view mode. + * + * @param array $edit + * (optional) An array of view mode properties. Defaults to an empty array. + */ + function createViewMode(&$edit = array()) { + $edit += array( + 'label' => 'Testing', + 'name' => 'testing', + 'entityTypes[node]' => '1' + ); + + $this->drupalPost('admin/config/system/view-modes/add', $edit, t('Save')); + $this->assertText(format_string('Saved the !name view mode.', array('!name' => $edit['label']))); + } + + /** + * Test managing view modes. + */ + function testManageViewModes() { + $edit = array(); + $this->createViewMode($edit); + + // Create the same and assert it already exists. + $this->drupalPost('admin/config/system/view-modes/add', $edit, t('Save')); + $this->assertText('The machine-readable name is already in use. It must be unique.', 'View mode testing already exists.'); + + // Assert it's found on the Field UI for article. + $this->drupalGet('admin/structure/types/manage/article/display'); + $this->assertRaw('view_modes_custom[testing]', 'Testing view mode found on node article.'); + + // Assert it's not found on the Field UI for user. + $this->drupalGet('admin/config/people/accounts/display'); + $this->assertNoRaw('view_modes_custom[testing]', 'Testing view mode not found on user.'); + + // Update view mode label. + $edit = array( + 'label' => 'Testing 2', + ); + $this->drupalPost('admin/config/system/view-modes/testing/edit', $edit, t('Save')); + $this->assertText('Saved the Testing 2 view mode.', 'Testing label updated.'); + + // Remove a view mode. + $this->drupalPost('admin/config/system/view-modes/testing/delete', array(), t('Delete')); + $this->assertText('Deleted the Testing 2 view mode', 'Deleted the Testing view mode.'); + + // Assert the view mode is gone at the manage display screen. + $this->drupalGet('admin/structure/types/manage/article/display'); + $this->assertNoRaw('view_modes_custom[testing]', 'Testing view mode not found on node article.'); + } + +} diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php new file mode 100644 index 0000000..a2e97e2 --- /dev/null +++ b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php @@ -0,0 +1,88 @@ + 'textfield', + '#title' => t('Label'), + '#default_value' => $view_mode->label, + '#required' => TRUE, + ); + + $form['name'] = array( + '#type' => 'machine_name', + '#machine_name' => array( + 'source' => array('label'), + 'exists' => 'view_mode_load', + ), + '#default_value' => $view_mode->name, + '#disabled' => !empty($view_mode->label), + ); + + $options = array(); + $entity_info = entity_get_info(); + foreach ($entity_info as $entity_type => $info) { + if (!empty($info['fieldable'])) { + $options[$entity_type] = $info['label']; + } + } + + $form['entityTypes'] = array( + '#required' => TRUE, + '#type' => 'checkboxes', + '#title' => t('Enable this view mode for the following types'), + '#options' => $options, + '#default_value' => $view_mode->getUsedEntityTypes(), + ); + + return $form; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + * + * @todo Move this code to the base controller: http://drupal.org/node/1728786 + */ + public function save(array $form, array &$form_state) { + $view_mode = $this->getEntity($form_state); + $view_mode->save(); + drupal_set_message(t('Saved the %view-mode view mode.', array( + '%view-mode' => $view_mode->label(), + ))); + + $form_state['redirect'] = 'admin/config/system/view-modes'; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + * + * @todo Move this code to the base controller: http://drupal.org/node/1728786 + */ + public function delete(array $form, array &$form_state) { + $destination = array(); + if (isset($_GET['destination'])) { + $destination = drupal_get_destination(); + unset($_GET['destination']); + } + $view_mode = $this->getEntity($form_state); + $form_state['redirect'] = array('admin/config/system/view-modes/' . $view_mode->id() . '/delete', array('query' => $destination)); + } + +} diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php new file mode 100644 index 0000000..f55f701 --- /dev/null +++ b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php @@ -0,0 +1,45 @@ +getUsedEntityTypes() as $entity_type) { + $entity_types[] = $entity_info[$entity_type]['label']; + } + $row['entities'] = implode(', ', $entity_types); + $row['operations'] = $operations; + return $row; + } + +} diff --git a/core/modules/system/system.module b/core/modules/system/system.module index d1c314d..19afe93 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1079,6 +1079,30 @@ function system_menu() { } /** + * Implements hook_entity_info(). + */ +function system_entity_info() { + // This entity type is provided on behalf of the entity system. + // @todo Remove from system module after http://drupal.org/node/1763974. + $return = array( + 'view_mode' => array( + 'label' => t('View mode'), + 'entity class' => 'Drupal\Core\Entity\EntityViewMode', + 'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController', + 'config prefix' => 'view_mode', + 'fieldable' => FALSE, + 'entity keys' => array( + 'id' => 'name', + 'label' => 'label', + 'uuid' => 'uuid', + ), + ), + ); + + return $return; +} + +/** * Page callback; Execute cron tasks. * * @see system_cron_access().