Commit 7f99ae9e authored by alexpott's avatar alexpott
Browse files

Issue #1982138 by tim.plunkett, amateescu, swentel, yched: Clean out field_ui().admin.inc.

parent c3938baa
......@@ -19,6 +19,13 @@
*/
class FormatterPluginManager extends PluginManagerBase {
/**
* An array of formatter options for each field type.
*
* @var array
*/
protected $formatterOptions;
/**
* Overrides Drupal\Component\Plugin\PluginManagerBase:$defaults.
*/
......@@ -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 getOptions($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;
}
}
......@@ -18,6 +18,13 @@
*/
class WidgetPluginManager extends PluginManagerBase {
/**
* An array of widget options for each field type.
*
* @var array
*/
protected $widgetOptions;
/**
* Overrides Drupal\Component\Plugin\PluginManagerBase:$defaults.
*/
......@@ -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 getOptions($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;
}
}
......@@ -57,155 +57,6 @@ function field_ui_fields_list() {
return $output;
}
/**
* 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.
*
......@@ -219,7 +70,6 @@ function field_ui_table_pre_render($elements) {
function theme_field_ui_table($variables) {
$elements = $variables['elements'];
$table = array();
$js_settings = array();
// Add table headers and attributes.
foreach (array('header', 'attributes') as $key) {
......@@ -287,175 +137,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';
}
......@@ -226,6 +226,7 @@ function field_ui_theme() {
return array(
'field_ui_table' => array(
'render element' => 'elements',
'file' => 'field_ui.admin.inc',
),
);
}
......@@ -237,7 +238,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()),
),
);
......@@ -261,40 +261,6 @@ function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
Drupal::state()->set('menu_rebuild_needed', TRUE);
}
/**
* 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().
*
......
......@@ -8,12 +8,46 @@
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.
*/
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().
*/
......@@ -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->getOptions($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