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 2260610..70aa871 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 @@ -20,6 +20,13 @@ class FormatterPluginManager extends PluginManagerBase { /** + * An array of formatter options for each field type. + * + * @var array + */ + protected $formatterOptions; + + /** * Overrides Drupal\Component\Plugin\PluginManagerBase:$defaults. */ protected $defaults = array( @@ -125,4 +132,34 @@ public function prepareConfiguration($field_type, array $configuration) { return $configuration; } + /** + * Returns an array of formatter options for a field type. + * + * @param string|null $field_type + * (optional) The name of a field type, or NULL to retrieve all formatters. + * + * @return array + * If no field type is provided, returns a nested array of all formatters, + * keyed by field type. + */ + public function getFormatterOptions($field_type = NULL) { + if (!isset($this->formatterOptions)) { + $field_types = field_info_field_types(); + $options = array(); + foreach ($this->getDefinitions() as $name => $formatter) { + foreach ($formatter['field_types'] as $formatter_field_type) { + // Check that the field type exists. + if (isset($field_types[$formatter_field_type])) { + $options[$formatter_field_type][$name] = $formatter['label']; + } + } + } + $this->formatterOptions = $options; + } + if ($field_type) { + return !empty($this->formatterOptions[$field_type]) ? $this->formatterOptions[$field_type] : array(); + } + return $this->formatterOptions; + } + } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php index bb85736..129230c 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php @@ -19,6 +19,13 @@ class WidgetPluginManager extends PluginManagerBase { /** + * An array of widget options for each field type. + * + * @var array + */ + protected $widgetOptions; + + /** * Overrides Drupal\Component\Plugin\PluginManagerBase:$defaults. */ protected $defaults = array( @@ -120,4 +127,39 @@ public function prepareConfiguration($field_type, array $configuration) { return $configuration; } + + /** + * Returns an array of widget type options for a field type. + * + * @param string|null $field_type + * (optional) The name of a field type, or NULL to retrieve all widget + * options. Defaults to NULL. + * + * @return array + * If no field type is provided, returns a nested array of all widget types, + * keyed by field type human name. + */ + public function getWidgetOptions($field_type = NULL) { + if (!isset($this->widgetOptions)) { + $options = array(); + $field_types = field_info_field_types(); + $widget_types = $this->getDefinitions(); + uasort($widget_types, 'drupal_sort_weight'); + foreach ($widget_types as $name => $widget_type) { + foreach ($widget_type['field_types'] as $widget_field_type) { + // Check that the field type exists. + if (isset($field_types[$widget_field_type])) { + $options[$widget_field_type][$name] = $widget_type['label']; + } + } + } + $this->widgetOptions = $options; + } + if (isset($field_type)) { + return !empty($this->widgetOptions[$field_type]) ? $this->widgetOptions[$field_type] : array(); + } + + return $this->widgetOptions; + } + } diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc index 3ee1eaa..2804657 100644 --- a/core/modules/field_ui/field_ui.admin.inc +++ b/core/modules/field_ui/field_ui.admin.inc @@ -58,155 +58,6 @@ function field_ui_fields_list() { } /** - * Displays a message listing the inactive fields of a given bundle. - */ -function field_ui_inactive_message($entity_type, $bundle) { - $inactive_instances = field_ui_inactive_instances($entity_type, $bundle); - if (!empty($inactive_instances)) { - $field_types = field_info_field_types(); - - foreach ($inactive_instances as $field_name => $instance) { - $field = field_info_field($instance['field_name']); - $list[] = t('%field (@field_name) field requires the %field_type field type provided by %field_type_module module', array( - '%field' => $instance['label'], - '@field_name' => $instance['field_name'], - '%field_type' => isset($field_types[$field['type']]) ? $field_types[$field['type']]['label'] : $field['type'], - '%field_type_module' => $field['module'], - )); - } - drupal_set_message(t('Inactive fields are not shown unless their providing modules are enabled. The following fields are not enabled: !list', array('!list' => theme('item_list', array('items' => $list)))), 'error'); - } -} - -/** - * Determines the rendering order of an array representing a tree. - * - * Callback for array_reduce() within field_ui_table_pre_render(). - */ -function _field_ui_reduce_order($array, $a) { - $array = !isset($array) ? array() : $array; - if ($a['name']) { - $array[] = $a['name']; - } - if (!empty($a['children'])) { - uasort($a['children'], 'drupal_sort_weight'); - $array = array_merge($array, array_reduce($a['children'], '_field_ui_reduce_order')); - } - return $array; -} - -/** - * Returns the region to which a row in the 'Manage fields' screen belongs. - * - * This function is used as a #region_callback in - * Drupal\field_ui\DisplayOverview::form(). It is called during - * field_ui_table_pre_render(). - */ -function field_ui_field_overview_row_region($row) { - switch ($row['#row_type']) { - case 'field': - case 'extra_field': - return 'content'; - case 'add_new_field': - // If no input in 'label', assume the row has not been dragged out of the - // 'add new' section. - return (!empty($row['label']['#value']) ? 'content' : 'hidden'); - } -} - -/** - * Returns the region to which a row in the 'Manage display' screen belongs. - * - * This function is used as a #region_callback in - * Drupal\field_ui\FieldOverview::form(), and is called during - * field_ui_table_pre_render(). - */ -function field_ui_display_overview_row_region($row) { - switch ($row['#row_type']) { - case 'field': - case 'extra_field': - return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'content'); - } -} - -/** - * Render API callback: Performs pre-render tasks on field_ui_table elements. - * - * This function is assigned as a #pre_render callback in - * field_ui_element_info(). - * - * @see drupal_render(). - */ -function field_ui_table_pre_render($elements) { - $js_settings = array(); - - // For each region, build the tree structure from the weight and parenting - // data contained in the flat form structure, to determine row order and - // indentation. - $regions = $elements['#regions']; - $tree = array('' => array('name' => '', 'children' => array())); - $trees = array_fill_keys(array_keys($regions), $tree); - - $parents = array(); - $list = drupal_map_assoc(element_children($elements)); - - // Iterate on rows until we can build a known tree path for all of them. - while ($list) { - foreach ($list as $name) { - $row = &$elements[$name]; - $parent = $row['parent_wrapper']['parent']['#value']; - // Proceed if parent is known. - if (empty($parent) || isset($parents[$parent])) { - // Grab parent, and remove the row from the next iteration. - $parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array(); - unset($list[$name]); - - // Determine the region for the row. - $function = $row['#region_callback']; - $region_name = $function($row); - - // Add the element in the tree. - $target = &$trees[$region_name]['']; - foreach ($parents[$name] as $key) { - $target = &$target['children'][$key]; - } - $target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']); - - // Add tabledrag indentation to the first row cell. - if ($depth = count($parents[$name])) { - $children = element_children($row); - $cell = current($children); - $row[$cell]['#prefix'] = theme('indentation', array('size' => $depth)) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : ''); - } - - // Add row id and associate JS settings. - $id = drupal_html_class($name); - $row['#attributes']['id'] = $id; - if (isset($row['#js_settings'])) { - $row['#js_settings'] += array( - 'rowHandler' => $row['#row_type'], - 'name' => $name, - 'region' => $region_name, - ); - $js_settings[$id] = $row['#js_settings']; - } - } - } - } - // Determine rendering order from the tree structure. - foreach ($regions as $region_name => $region) { - $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], '_field_ui_reduce_order'); - } - - $elements['#attached']['js'][] = array( - 'type' => 'setting', - 'data' => array('fieldUIRowsData' => $js_settings), - ); - - return $elements; -} - -/** * Returns HTML for Field UI overview tables. * * @param $variables @@ -287,175 +138,3 @@ function theme_field_ui_table($variables) { return theme('table', $table); } - -/** - * Render API callback: Checks if a field machine name is taken. - * - * @param $value - * The machine name, not prefixed with 'field_'. - * - * @return - * Whether or not the field machine name is taken. - */ -function _field_ui_field_name_exists($value) { - // Prefix with 'field_'. - $field_name = 'field_' . $value; - - // We need to check inactive fields as well, so we can't use - // field_info_fields(). - return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); -} - -/** - * Returns an array of field_type options. - */ -function field_ui_field_type_options() { - $options = &drupal_static(__FUNCTION__); - - if (!isset($options)) { - $options = array(); - $field_types = field_info_field_types(); - $field_type_options = array(); - foreach ($field_types as $name => $field_type) { - // Skip field types which have no widget types, or should not be add via - // uesr interface. - if (field_ui_widget_type_options($name) && empty($field_type['no_ui'])) { - $options[$name] = $field_type['label']; - } - } - asort($options); - } - return $options; -} - -/** - * Returns an array of widget type options for a field type. - * - * If no field type is provided, returns a nested array of all widget types, - * keyed by field type human name. - */ -function field_ui_widget_type_options($field_type = NULL, $by_label = FALSE) { - $options = &drupal_static(__FUNCTION__); - - if (!isset($options)) { - $options = array(); - $field_types = field_info_field_types(); - $widget_types = field_info_widget_types(); - uasort($widget_types, 'drupal_sort_weight'); - foreach ($widget_types as $name => $widget_type) { - foreach ($widget_type['field_types'] as $widget_field_type) { - // Check that the field type exists. - if (isset($field_types[$widget_field_type])) { - $options[$widget_field_type][$name] = $widget_type['label']; - } - } - } - } - - if (isset($field_type)) { - return !empty($options[$field_type]) ? $options[$field_type] : array(); - } - if ($by_label) { - $field_types = field_info_field_types(); - $options_by_label = array(); - foreach ($options as $field_type => $widgets) { - $options_by_label[$field_types[$field_type]['label']] = $widgets; - } - return $options_by_label; - } - return $options; -} - -/** - * Returns an array of formatter options for a field type. - * - * If no field type is provided, returns a nested array of all formatters, keyed - * by field type. - */ -function field_ui_formatter_options($field_type = NULL) { - $options = &drupal_static(__FUNCTION__); - - if (!isset($options)) { - $field_types = field_info_field_types(); - $options = array(); - foreach (field_info_formatter_types() as $name => $formatter) { - foreach ($formatter['field_types'] as $formatter_field_type) { - // Check that the field type exists. - if (isset($field_types[$formatter_field_type])) { - $options[$formatter_field_type][$name] = $formatter['label']; - } - } - } - } - - if ($field_type) { - return !empty($options[$field_type]) ? $options[$field_type] : array(); - } - return $options; -} - -/** - * Returns an array of existing fields to be added to a bundle. - */ -function field_ui_existing_field_options($entity_type, $bundle) { - $info = array(); - $field_types = field_info_field_types(); - - foreach (field_info_instances() as $existing_entity_type => $bundles) { - foreach ($bundles as $existing_bundle => $instances) { - // No need to look in the current bundle. - if (!($existing_bundle == $bundle && $existing_entity_type == $entity_type)) { - foreach ($instances as $instance) { - $field = field_info_field($instance['field_name']); - // Don't show - // - locked fields, - // - fields already in the current bundle, - // - fields that cannot be added to the entity type, - // - fields that should not be added via user interface. - - if (empty($field['locked']) - && !field_info_instance($entity_type, $field['field_name'], $bundle) - && (empty($field['entity_types']) || in_array($entity_type, $field['entity_types'])) - && empty($field_types[$field['type']]['no_ui'])) { - $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']); - $info[$instance['field_name']] = array( - 'type' => $field['type'], - 'type_label' => $field_types[$field['type']]['label'], - 'field' => $field['field_name'], - 'label' => $instance['label'], - 'widget_type' => $widget['type'], - ); - } - } - } - } - } - return $info; -} - -/** - * Extracts next redirect path from an array of multiple destinations. - * - * @see field_ui_next_destination() - */ -function field_ui_get_destinations($destinations) { - $path = array_shift($destinations); - $options = drupal_parse_url($path); - if ($destinations) { - $options['query']['destinations'] = $destinations; - } - return array($options['path'], $options); -} - -/** - * Returns the next redirect path in a multipage sequence. - */ -function field_ui_next_destination($entity_type, $bundle) { - $destinations = !empty($_REQUEST['destinations']) ? $_REQUEST['destinations'] : array(); - if (!empty($destinations)) { - unset($_REQUEST['destinations']); - return field_ui_get_destinations($destinations); - } - $admin_path = Drupal::entityManager()->getAdminPath($entity_type, $bundle); - return $admin_path . '/fields'; -} diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index cce8734..f9aefe3 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -237,7 +237,6 @@ function field_ui_element_info() { return array( 'field_ui_table' => array( '#theme' => 'field_ui_table', - '#pre_render' => array('field_ui_table_pre_render'), '#regions' => array('' => array()), ), ); @@ -262,40 +261,6 @@ function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) { } /** - * Identifies inactive fields within a bundle. - */ -function field_ui_inactive_instances($entity_type, $bundle_name = NULL) { - $params = array('entity_type' => $entity_type); - - if (empty($bundle_name)) { - $active = field_info_instances($entity_type); - $inactive = array(); - } - else { - // Restrict to the specified bundle. For consistency with the case where - // $bundle_name is NULL, the $active and $inactive arrays are keyed by - // bundle name first. - $params['bundle'] = $bundle_name; - $active = array($bundle_name => field_info_instances($entity_type, $bundle_name)); - $inactive = array($bundle_name => array()); - } - - // Iterate on existing definitions, and spot those that do not appear in the - // $active list collected earlier. - $all_instances = field_read_instances($params, array('include_inactive' => TRUE)); - foreach ($all_instances as $instance) { - if (!isset($active[$instance['bundle']][$instance['field_name']])) { - $inactive[$instance['bundle']][$instance['field_name']] = $instance; - } - } - - if (!empty($bundle_name)) { - return $inactive[$bundle_name]; - } - return $inactive; -} - -/** * Implements hook_form_FORM_ID_alter(). * * Adds a button 'Save and manage fields' to the 'Create content type' form. 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 e6caf4e..cc699a6 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php @@ -8,6 +8,9 @@ namespace Drupal\field_ui; use Drupal\field_ui\OverviewBase; +use Drupal\Core\Entity\EntityManager; +use Drupal\field\Plugin\Type\Formatter\FormatterPluginManager; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Field UI display overview form. @@ -15,6 +18,37 @@ class DisplayOverview extends OverviewBase { /** + * The formatter plugin manager. + * + * @var \Drupal\field\Plugin\Type\Formatter\FormatterPluginManager + */ + protected $formatterManager; + + /** + * Constructs a new DisplayOverview. + * + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager. + * @param \Drupal\field\Plugin\Type\Formatter\FormatterPluginManager $formatter_manager + * The formatter plugin manager. + */ + public function __construct(EntityManager $entity_manager, FormatterPluginManager $formatter_manager) { + parent::__construct($entity_manager); + + $this->formatterManager = $formatter_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.entity'), + $container->get('plugin.manager.field.formatter') + ); + } + + /** * Implements Drupal\field_ui\OverviewBase::getRegions(). */ public function getRegions() { @@ -70,6 +104,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table = array( '#type' => 'field_ui_table', + '#pre_render' => array(array($this, 'tablePreRender')), '#tree' => TRUE, '#header' => array( t('Field'), @@ -107,7 +142,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'field', - '#region_callback' => 'field_ui_display_overview_row_region', + '#region_callback' => array($this, 'getRowRegion'), '#js_settings' => array( 'rowHandler' => 'field', 'defaultFormatter' => $field_types[$field['type']]['default_formatter'], @@ -148,7 +183,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, ), ); - $formatter_options = field_ui_formatter_options($field['type']); + $formatter_options = $this->formatterManager->getFormatterOptions($field['type']); $formatter_options['hidden'] = '<' . t('Hidden') . '>'; $table[$name]['format'] = array( 'type' => array( @@ -174,7 +209,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, // Get the corresponding formatter object. if ($display_options && $display_options['type'] != 'hidden') { - $formatter = drupal_container()->get('plugin.manager.field.formatter')->getInstance(array( + $formatter = $this->formatterManager->getInstance(array( 'instance' => $instance, 'view_mode' => $this->mode, 'configuration' => $display_options @@ -294,7 +329,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'extra_field', - '#region_callback' => 'field_ui_display_overview_row_region', + '#region_callback' => array($this, 'getRowRegion'), '#js_settings' => array('rowHandler' => 'field'), 'human_name' => array( '#markup' => check_plain($extra_field['label']), @@ -576,4 +611,22 @@ public function multistepAjax($form, &$form_state) { // Return the whole table. return $form['fields']; } + + /** + * Returns the region to which a row in the display overview belongs. + * + * @param array $row + * The row element. + * + * @return string|null + * The region name this row belongs to. + */ + public function getRowRegion($row) { + switch ($row['#row_type']) { + case 'field': + case 'extra_field': + return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'content'); + } + } + } 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 44e4be7..1bef718 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -8,6 +8,9 @@ namespace Drupal\field_ui; use Drupal\field_ui\OverviewBase; +use Drupal\Core\Entity\EntityManager; +use Drupal\field\Plugin\Type\Widget\WidgetPluginManager; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Field UI field overview form. @@ -15,6 +18,37 @@ class FieldOverview extends OverviewBase { /** + * The widget plugin manager. + * + * @var \Drupal\field\Plugin\Type\Widget\WidgetPluginManager + */ + protected $widgetManager; + + /** + * Constructs a new DisplayOverview. + * + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager. + * @param \Drupal\field\Plugin\Type\Widget\WidgetPluginManager $widget_manager + * The widget plugin manager. + */ + public function __construct(EntityManager $entity_manager, WidgetPluginManager $widget_manager) { + parent::__construct($entity_manager); + + $this->widgetManager = $widget_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.entity'), + $container->get('plugin.manager.field.widget') + ); + } + + /** * Implements Drupal\field_ui\OverviewBase::getRegions(). */ public function getRegions() { @@ -67,6 +101,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table = array( '#type' => 'field_ui_table', + '#pre_render' => array(array($this, 'tablePreRender')), '#tree' => TRUE, '#header' => array( t('Label'), @@ -93,7 +128,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'field', - '#region_callback' => 'field_ui_field_overview_row_region', + '#region_callback' => array($this, 'getRowRegion'), 'label' => array( '#markup' => check_plain($instance['label']), ), @@ -165,7 +200,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'extra_field', - '#region_callback' => 'field_ui_field_overview_row_region', + '#region_callback' => array($this, 'getRowRegion'), 'label' => array( '#markup' => check_plain($extra_field['label']), ), @@ -208,14 +243,31 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, // Additional row: add new field. $max_weight = $entity_form_display->getHighestWeight(); - $field_type_options = field_ui_field_type_options(); - $widget_type_options = field_ui_widget_type_options(NULL, TRUE); + + // Prepare the widget types to be display as options. + $widget_options = $this->widgetManager->getWidgetOptions(); + $widget_type_options = array(); + foreach ($widget_options as $field_type => $widgets) { + $widget_type_options[$field_types[$field_type]['label']] = $widgets; + } + + // Gather valid field types. + $field_type_options = array(); + foreach ($field_types as $name => $field_type) { + // Skip field types which have no widget types, or should not be added via + // user interface. + if (isset($widget_options[$name]) && empty($field_type['no_ui'])) { + $field_type_options[$name] = $field_type['label']; + } + } + asort($field_type_options); + if ($field_type_options && $widget_type_options) { $name = '_add_new_field'; $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), '#row_type' => 'add_new_field', - '#region_callback' => 'field_ui_field_overview_row_region', + '#region_callback' => array($this, 'getRowRegion'), 'label' => array( '#type' => 'textfield', '#title' => t('New field label'), @@ -265,7 +317,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, '#prefix' => '