diff --git a/core/modules/field_ui/field_ui.local_actions.yml b/core/modules/field_ui/field_ui.local_actions.yml
new file mode 100644
index 0000000..2939522
--- /dev/null
+++ b/core/modules/field_ui/field_ui.local_actions.yml
@@ -0,0 +1,3 @@
+field_ui.add:
+ class: \Drupal\Core\Menu\LocalActionDefault
+ derivative: \Drupal\field_ui\Plugin\Derivative\FieldUiLocalAction
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 2033cf6..eb6c68a 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -164,6 +164,7 @@ function field_ui_element_info() {
*/
function field_ui_entity_info(&$entity_info) {
$entity_info['field_instance']['controllers']['form']['delete'] = 'Drupal\field_ui\Form\FieldDeleteForm';
+ $entity_info['field_instance']['controllers']['list'] = 'Drupal\field_ui\FieldInstanceListController';
$entity_info['field_entity']['controllers']['list'] = 'Drupal\field_ui\FieldListController';
}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldInstanceListController.php b/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldInstanceListController.php
new file mode 100644
index 0000000..3d32c17
--- /dev/null
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldInstanceListController.php
@@ -0,0 +1,39 @@
+entityManager()->getDefinition($entity_type);
+ $bundle = $request->attributes->get('_raw_variables')->get($entity_info['bundle_entity_type']);
+ }
+ return $this->entityManager()->getListController('field_instance')->render($entity_type, $bundle, $request);
+ }
+
+}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
index 31a08ec..005237b 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
@@ -12,7 +12,6 @@
use Drupal\Core\Field\FieldTypePluginManager;
use Drupal\entity\EntityDisplayBaseInterface;
use Drupal\field\FieldInstanceInterface;
-use Drupal\field_ui\OverviewBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -21,6 +20,41 @@
abstract class DisplayOverviewBase extends OverviewBase {
/**
+ * The name of the entity type.
+ *
+ * @var string
+ */
+ protected $entity_type = '';
+
+ /**
+ * The entity bundle.
+ *
+ * @var string
+ */
+ protected $bundle = '';
+
+ /**
+ * The entity view or form mode.
+ *
+ * @var string
+ */
+ protected $mode = '';
+
+ /**
+ * The admin path of the overview page.
+ *
+ * @var string
+ */
+ protected $adminPath = NULL;
+
+ /**
+ * The entity manager.
+ *
+ * @var \Drupal\Core\Entity\EntityManagerInterface
+ */
+ protected $entityManager;
+
+ /**
* The widget or formatter plugin manager.
*
* @var \Drupal\Component\Plugin\PluginManagerBase
@@ -45,8 +79,7 @@
* The widget or formatter plugin manager.
*/
public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManager $field_type_manager, PluginManagerBase $plugin_manager) {
- parent::__construct($entity_manager);
-
+ $this->entityManager = $entity_manager;
$this->fieldTypes = $field_type_manager->getConfigurableDefinitions();
$this->pluginManager = $plugin_manager;
}
@@ -65,25 +98,23 @@ public static function create(ContainerInterface $container) {
/**
* {@inheritdoc}
*/
- public function getRegions() {
- return array(
- 'content' => array(
- 'title' => $this->t('Content'),
- 'invisible' => TRUE,
- 'message' => $this->t('No field is displayed.')
- ),
- 'hidden' => array(
- 'title' => $this->t('Disabled'),
- 'message' => $this->t('No field is hidden.')
- ),
- );
- }
-
- /**
- * {@inheritdoc}
- */
public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) {
- parent::buildForm($form, $form_state, $entity_type, $bundle);
+ if (!isset($form_state['bundle'])) {
+ if (!$bundle) {
+ $entity_info = $this->entityManager->getDefinition($entity_type);
+ $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($entity_info['bundle_entity_type']);
+ }
+ $form_state['bundle'] = $bundle;
+ }
+
+ $this->entity_type = $entity_type;
+ $this->bundle = $form_state['bundle'];
+ $this->adminPath = $this->entityManager->getAdminPath($this->entity_type, $this->bundle);
+
+ // When displaying the form, make sure the list of fields is up-to-date.
+ if (empty($form_state['post'])) {
+ field_info_cache_clear();
+ }
if (empty($this->mode)) {
$this->mode = 'default';
@@ -621,6 +652,136 @@ public function multistepAjax($form, &$form_state) {
}
/**
+ * Returns the regions needed to create the overview form.
+ *
+ * @return array
+ * Example usage:
+ * @code
+ * return array(
+ * 'content' => array(
+ * // label for the region.
+ * 'title' => $this->t('Content'),
+ * // Indicates if the region is visible in the UI.
+ * 'invisible' => TRUE,
+ * // A message to indicate that there is nothing to be displayed in
+ * // the region.
+ * 'message' => $this->t('No field is displayed.'),
+ * ),
+ * );
+ * @endcode
+ */
+ protected function getRegions() {
+ return array(
+ 'content' => array(
+ 'title' => $this->t('Content'),
+ 'invisible' => TRUE,
+ 'message' => $this->t('No field is displayed.')
+ ),
+ 'hidden' => array(
+ 'title' => $this->t('Disabled'),
+ 'message' => $this->t('No field is hidden.')
+ ),
+ );
+ }
+
+ /**
+ * 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().
+ */
+ public function tablePreRender($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.
+ $region_name = call_user_func($row['#region_callback'], $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);
+ $indentation = array(
+ '#theme' => 'indentation',
+ '#size' => $depth,
+ );
+ $row[$cell]['#prefix'] = drupal_render($indentation) . (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], array($this, 'reduceOrder'));
+ }
+
+ $elements['#attached']['js'][] = array(
+ 'type' => 'setting',
+ 'data' => array('fieldUIRowsData' => $js_settings),
+ );
+
+ return $elements;
+ }
+
+ /**
+ * Determines the rendering order of an array representing a tree.
+ *
+ * Callback for array_reduce() within self::tablePreRender().
+ */
+ public function reduceOrder($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'], array($this, 'reduceOrder')));
+ }
+ return $array;
+ }
+
+ /**
* Returns the entity display object used by this form.
*
* @param string $mode
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceListController.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceListController.php
new file mode 100644
index 0000000..e807d68
--- /dev/null
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceListController.php
@@ -0,0 +1,196 @@
+get('entity.manager')->getStorageController($entity_type),
+ $container->get('module_handler'),
+ $container->get('field.info'),
+ $container->get('plugin.manager.field.field_type')
+ );
+ }
+
+ /**
+ * Constructs a new EntityListController object.
+ *
+ * @param string $entity_type
+ * The type of entity to be listed.
+ * @param array $entity_info
+ * An array of entity info for the entity type.
+ * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
+ * The entity storage controller class.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler to invoke hooks on.
+ * @param \Drupal\field\FieldInfo $field_info
+ * The field info service.
+ * @param \Drupal\Core\Field\FieldTypePluginManager $field_type_manager
+ * The field type manager
+ */
+ public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, FieldInfo $field_info, FieldTypePluginManager $field_type_manager) {
+ parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+
+ $this->fieldInfo = $field_info;
+ $this->fieldTypeManager = $field_type_manager;
+ }
+
+ /**
+ * {inheritdoc}
+ */
+ public function render($entity_type = NULL, $bundle = NULL, Request $request = NULl) {
+ $this->entityType = $entity_type;
+ $this->bundle = $bundle;
+
+ $this->fieldTypes = $this->fieldTypeManager->getConfigurableDefinitions();
+ $this->currentPath = $request->attributes->get('_system_path');
+
+ $build = array(
+ '#theme' => 'table',
+ '#header' => $this->buildHeader(),
+ '#title' => $this->getTitle(),
+ '#rows' => array(),
+ '#empty' => $this->t('No fields are present yet.'),
+ );
+ foreach ($this->load() as $entity) {
+ if ($row = $this->buildRow($entity)) {
+ $build['#rows'][$entity->id()] = $row;
+ }
+ }
+ return $build;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load() {
+ $entities = $this->fieldInfo->getBundleInstances($this->entityType, $this->bundle);
+ uasort($entities, array($this->entityInfo['class'], 'sort'));
+ return $entities;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildHeader() {
+ $header = array(
+ 'label' => $this->t('Label'),
+ 'machine_name' => $this->t('Machine name'),
+ 'field_type' => $this->t('Field type'),
+ );
+ return $header + parent::buildHeader();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildRow(EntityInterface $field_instance) {
+ $row['label'] = String::checkPlain($field_instance->getFieldLabel());
+ $row['machine_name'] = $field_instance->getFieldName();
+ $field_type = array(
+ '#type' => 'link',
+ '#title' => $this->fieldTypes[$field_instance->getField()->getFieldType()]['label'],
+ '#href' => $this->currentPath . '/' . $field_instance->id() . '/field',
+ '#options' => array('attributes' => array('title' => $this->t('Edit field settings.'))),
+ );
+ $row['field_type'] = drupal_render($field_type);
+
+ return $row += parent::buildRow($field_instance);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOperations(EntityInterface $entity) {
+ $operations = array();
+ $admin_field_path = $this->currentPath . '/' . $entity->id();
+
+ $operations['edit'] = array(
+ 'title' => $this->t('Edit'),
+ 'href' => $admin_field_path,
+ 'attributes' => array('title' => $this->t('Edit instance settings.')),
+ 'weight' => 10,
+ );
+ $operations['field-settings'] = array(
+ 'title' => $this->t('Field settings'),
+ 'href' => $admin_field_path . '/field',
+ 'attributes' => array('title' => $this->t('Edit field settings.')),
+ 'weight' => 20,
+ );
+ $operations['delete'] = array(
+ 'title' => $this->t('Delete'),
+ 'href' => "$admin_field_path/delete",
+ 'attributes' => array('title' => $this->t('Delete instance.')),
+ 'weight' => 30,
+ );
+
+ return $operations;
+ }
+
+}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
deleted file mode 100644
index 0068a44..0000000
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
+++ /dev/null
@@ -1,456 +0,0 @@
-fieldTypeManager = $field_type_manager;
- $this->moduleHandler = $module_handler;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('entity.manager'),
- $container->get('plugin.manager.field.field_type'),
- $container->get('module_handler')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRegions() {
- return array(
- 'content' => array(
- 'title' => $this->t('Content'),
- 'invisible' => TRUE,
- 'rows_order' => array(),
- // @todo Bring back this message in https://drupal.org/node/1963340.
- //'message' => $this->t('No fields are present yet.'),
- ),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormId() {
- return 'field_ui_field_overview_form';
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) {
- parent::buildForm($form, $form_state, $entity_type, $bundle);
-
- // Gather bundle information.
- $instances = field_info_instances($this->entity_type, $this->bundle);
- $field_types = $this->fieldTypeManager->getConfigurableDefinitions();
-
- // Field prefix.
- $field_prefix = \Drupal::config('field_ui.settings')->get('field_prefix');
-
- $form += array(
- '#entity_type' => $this->entity_type,
- '#bundle' => $this->bundle,
- '#fields' => array_keys($instances),
- );
-
- $table = array(
- '#type' => 'field_ui_table',
- '#tree' => TRUE,
- '#header' => array(
- $this->t('Label'),
- $this->t('Machine name'),
- $this->t('Field type'),
- $this->t('Operations'),
- ),
- '#regions' => $this->getRegions(),
- '#attributes' => array(
- 'class' => array('field-ui-overview'),
- 'id' => 'field-overview',
- ),
- );
-
- // @todo
- $form['inline_actions'] = array(
- '#prefix' => '
',
- );
- $form['inline_actions']['add'] = array(
- '#theme' => 'menu_local_action',
- '#link' => array(
- 'href' => $this->adminPath . '/add-field',
- 'title' => t('Add field'),
- ),
- );
-
- // Fields.
- foreach ($instances as $name => $instance) {
- $field = $instance->getField();
- $admin_field_path = $this->adminPath . '/fields/' . $instance->id();
- $table[$name] = array(
- '#attributes' => array(
- 'id' => drupal_html_class($name),
- ),
- 'label' => array(
- '#markup' => check_plain($instance->getFieldLabel()),
- ),
- 'field_name' => array(
- '#markup' => $instance->getFieldName(),
- ),
- 'type' => array(
- '#type' => 'link',
- '#title' => $field_types[$field->getFieldType()]['label'],
- '#href' => $admin_field_path . '/field',
- '#options' => array('attributes' => array('title' => $this->t('Edit field settings.'))),
- ),
- );
-
- $links = array();
- $links['edit'] = array(
- 'title' => $this->t('Edit'),
- 'href' => $admin_field_path,
- 'attributes' => array('title' => $this->t('Edit instance settings.')),
- );
- $links['field-settings'] = array(
- 'title' => $this->t('Field settings'),
- 'href' => $admin_field_path . '/field',
- 'attributes' => array('title' => $this->t('Edit field settings.')),
- );
- $links['delete'] = array(
- 'title' => $this->t('Delete'),
- 'href' => "$admin_field_path/delete",
- 'attributes' => array('title' => $this->t('Delete instance.')),
- );
- // Allow altering the operations on this entity listing.
- $this->moduleHandler->alter('entity_operation', $links, $instance);
- $table[$name]['operations']['data'] = array(
- '#type' => 'operations',
- '#links' => $links,
- );
-
- if (!empty($field->locked)) {
- $table[$name]['operations'] = array('#markup' => $this->t('Locked'));
- $table[$name]['#attributes']['class'][] = 'menu-disabled';
- }
- }
-
- // We can set the 'rows_order' element, needed by theme_field_ui_table(),
- // here instead of a #pre_render callback because this form doesn't have the
- // tabledrag behavior anymore.
- foreach (element_children($table) as $name) {
- $table['#regions']['content']['rows_order'][] = $name;
- }
-
- $form['fields'] = $table;
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save'));
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateForm(array &$form, array &$form_state) {
- $this->validateAddNew($form, $form_state);
- $this->validateAddExisting($form, $form_state);
- }
-
- /**
- * Validates the 'add new field' row.
- *
- * @param array $form
- * An associative array containing the structure of the form.
- * @param array $form_state
- * A reference to a keyed array containing the current state of the form.
- *
- * @see \Drupal\field_ui\FieldOverview::validateForm()
- */
- protected function validateAddNew(array $form, array &$form_state) {
- $field = $form_state['values']['fields']['_add_new_field'];
-
- // Validate if any information was provided in the 'add new field' row.
- if (array_filter(array($field['label'], $field['field_name'], $field['type']))) {
- // Missing label.
- if (!$field['label']) {
- form_set_error('fields][_add_new_field][label', $form_state, $this->t('Add new field: you need to provide a label.'));
- }
-
- // Missing field name.
- if (!$field['field_name']) {
- form_set_error('fields][_add_new_field][field_name', $form_state, $this->t('Add new field: you need to provide a field name.'));
- }
- // Field name validation.
- else {
- $field_name = $field['field_name'];
-
- // Add the field prefix.
- $field_name = \Drupal::config('field_ui.settings')->get('field_prefix') . $field_name;
- form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state);
- }
-
- // Missing field type.
- if (!$field['type']) {
- form_set_error('fields][_add_new_field][type', $form_state, $this->t('Add new field: you need to select a field type.'));
- }
- }
- }
-
- /**
- * Validates the 're-use existing field' row.
- *
- * @param array $form
- * An associative array containing the structure of the form.
- * @param array $form_state
- * A reference to a keyed array containing the current state of the form.
- *
- * @see \Drupal\field_ui\FieldOverview::validate()
- */
- protected function validateAddExisting(array $form, array &$form_state) {
- // The form element might be absent if no existing fields can be added to
- // this bundle.
- if (isset($form_state['values']['fields']['_add_existing_field'])) {
- $field = $form_state['values']['fields']['_add_existing_field'];
-
- // Validate if any information was provided in the
- // 're-use existing field' row.
- if (array_filter(array($field['label'], $field['field_name']))) {
- // Missing label.
- if (!$field['label']) {
- form_set_error('fields][_add_existing_field][label', $form_state, $this->t('Re-use existing field: you need to provide a label.'));
- }
-
- // Missing existing field name.
- if (!$field['field_name']) {
- form_set_error('fields][_add_existing_field][field_name', $form_state, $this->t('Re-use existing field: you need to select a field.'));
- }
- }
- }
- }
-
- /**
- * Overrides \Drupal\field_ui\OverviewBase::submitForm().
- */
- public function submitForm(array &$form, array &$form_state) {
- $form_values = $form_state['values']['fields'];
- $destinations = array();
-
- // Create new field.
- if (!empty($form_values['_add_new_field']['field_name'])) {
- $values = $form_values['_add_new_field'];
-
- $field = array(
- 'name' => $values['field_name'],
- 'entity_type' => $this->entity_type,
- 'type' => $values['type'],
- 'translatable' => $values['translatable'],
- );
- $instance = array(
- 'field_name' => $values['field_name'],
- 'entity_type' => $this->entity_type,
- 'bundle' => $this->bundle,
- 'label' => $values['label'],
- );
-
- // Create the field and instance.
- try {
- $this->entityManager->getStorageController('field_entity')->create($field)->save();
- $new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
- $new_instance->save();
-
- // Make sure the field is displayed in the 'default' form mode (using
- // default widget and settings). It stays hidden for other form modes
- // until it is explicitly configured.
- entity_get_form_display($this->entity_type, $this->bundle, 'default')
- ->setComponent($values['field_name'])
- ->save();
-
- // 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($values['field_name'])
- ->save();
-
- // Always show the field settings step, as the cardinality needs to be
- // configured for new fields.
- $destinations[] = $this->adminPath. '/fields/' . $new_instance->id() . '/field';
- $destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
-
- // Store new field information for any additional submit handlers.
- $form_state['fields_added']['_add_new_field'] = $values['field_name'];
- }
- catch (\Exception $e) {
- drupal_set_message($this->t('There was a problem creating field %label: !message', array('%label' => $instance->getFieldLabel(), '!message' => $e->getMessage())), 'error');
- }
- }
-
- // Re-use existing field.
- if (!empty($form_values['_add_existing_field']['field_name'])) {
- $values = $form_values['_add_existing_field'];
- $field_name = $values['field_name'];
- $field = field_info_field($this->entity_type, $field_name);
- if (!empty($field->locked)) {
- drupal_set_message($this->t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error');
- }
- else {
- $instance = array(
- 'field_name' => $field_name,
- 'entity_type' => $this->entity_type,
- 'bundle' => $this->bundle,
- 'label' => $values['label'],
- );
-
- try {
- $new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
- $new_instance->save();
-
- // Make sure the field is displayed in the 'default' form mode (using
- // default widget and settings). It stays hidden for other form modes
- // until it is explicitly configured.
- entity_get_form_display($this->entity_type, $this->bundle, 'default')
- ->setComponent($field_name)
- ->save();
-
- // 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_name)
- ->save();
-
- $destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
- // Store new field information for any additional submit handlers.
- $form_state['fields_added']['_add_existing_field'] = $instance['field_name'];
- }
- catch (\Exception $e) {
- drupal_set_message($this->t('There was a problem creating field instance %label: @message.', array('%label' => $instance->getFieldLabel(), '@message' => $e->getMessage())), 'error');
- }
- }
- }
-
- if ($destinations) {
- $destination = drupal_get_destination();
- $destinations[] = $destination['destination'];
- $this->getRequest()->query->remove('destination');
- $path = array_shift($destinations);
- $options = drupal_parse_url($path);
- $options['query']['destinations'] = $destinations;
- $form_state['redirect'] = array($options['path'], $options);
- }
- else {
- drupal_set_message($this->t('Your settings have been saved.'));
- }
- }
-
- /**
- * Returns an array of existing fields to be added to a bundle.
- *
- * @return array
- * An array of existing fields keyed by field name.
- */
- protected function getExistingFieldOptions() {
- $options = array();
-
- // Collect candidate field instances: all instances of fields for this
- // entity type that are not already present in the current bundle.
- $field_map = field_info_field_map();
- $instance_ids = array();
- if (!empty($field_map[$this->entity_type])) {
- foreach ($field_map[$this->entity_type] as $field_name => $data) {
- if (!in_array($this->bundle, $data['bundles'])) {
- $bundle = reset($data['bundles']);
- $instance_ids[] = $this->entity_type . '.' . $bundle . '.' . $field_name;
- }
- }
- }
-
- // Load the instances and build the list of options.
- if ($instance_ids) {
- $field_types = $this->fieldTypeManager->getDefinitions();
- $instances = $this->entityManager->getStorageController('field_instance')->loadMultiple($instance_ids);
- foreach ($instances as $instance) {
- // Do not show:
- // - locked fields,
- // - fields that should not be added via user interface.
- $field_type = $instance->getFieldType();
- $field = $instance->getField();
- if (empty($field->locked) && empty($field_types[$field_type]['no_ui'])) {
- $options[$instance->getFieldName()] = array(
- 'type' => $field_type,
- 'type_label' => $field_types[$field_type]['label'],
- 'field' => $instance->getFieldName(),
- 'label' => $instance->getFieldLabel(),
- );
- }
- }
- }
-
- return $options;
- }
-
- /**
- * Checks if a field machine name is taken.
- *
- * @param string $value
- * The machine name, not prefixed with 'field_'.
- *
- * @return bool
- * Whether or not the field machine name is taken.
- */
- public function fieldNameExists($value) {
- // Prefix with 'field_'.
- $field_name = 'field_' . $value;
-
- return (bool) field_info_field($this->entity_type, $field_name);
- }
-
-}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php
index e3f5cb0..32ac16b 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php
@@ -9,8 +9,10 @@
use Drupal\Component\Utility\Url;
use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Entity\Field\FieldTypePluginManager;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldTypePluginManager;
use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormBuilderInterface;
use Drupal\field\Entity\Field;
use Drupal\field\FieldInfo;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -32,21 +34,14 @@ class FieldAddForm extends FormBase {
*
* @var string
*/
- protected $entity_type = '';
+ protected $entityType;
/**
* The entity bundle.
*
* @var string
*/
- protected $bundle = '';
-
- /**
- * The entity view or form mode.
- *
- * @var string
- */
- protected $mode = '';
+ protected $bundle;
/**
* The admin path of the overview page.
@@ -72,24 +67,34 @@ class FieldAddForm extends FormBase {
/**
* The field type plugin manager.
*
- * @var \Drupal\Core\Entity\Field\FieldTypePluginManager
+ * @var \Drupal\Core\Field\FieldTypePluginManager
*/
protected $fieldTypePluginManager;
/**
+ * The form builder being tested.
+ *
+ * @var \Drupal\Core\Form\FormBuilderInterface
+ */
+ protected $formBuilder;
+
+ /**
* Constructs a new FieldAddForm object.
*
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
* @param \Drupal\field\FieldInfo $field_info
* The field info service.
- * @param \Drupal\Core\Entity\Field\FieldTypePluginManager $field_type_plugin_manager
+ * @param \Drupal\Core\Field\FieldTypePluginManager $field_type_plugin_manager
* The field type plugin manager.
+ * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
+ * The form builder.
*/
- public function __construct(EntityManager $entity_manager, FieldInfo $field_info, FieldTypePluginManager $field_type_plugin_manager) {
+ public function __construct(EntityManager $entity_manager, FieldInfo $field_info, FieldTypePluginManager $field_type_plugin_manager, FormBuilderInterface $form_builder) {
$this->entityManager = $entity_manager;
$this->fieldInfo = $field_info;
$this->fieldTypePluginManager = $field_type_plugin_manager;
+ $this->formBuilder = $form_builder;
}
/**
@@ -106,51 +111,36 @@ public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('field.info'),
- $container->get('plugin.manager.entity.field.field_type')
+ $container->get('plugin.manager.field.field_type'),
+ $container->get('form_builder')
);
}
/**
* {@inheritdoc}
*/
- public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL, $form_mode = NULL) {
- $entity_info = $this->entityManager->getDefinition($entity_type);
- if (!empty($entity_info['bundle_prefix'])) {
- $bundle = $entity_info['bundle_prefix'] . $bundle;
+ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) {
+ if (!isset($form_state['bundle'])) {
+ if (!$bundle) {
+ $entity_info = $this->entityManager->getDefinition($entity_type);
+ $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($entity_info['bundle_entity_type']);
+ }
+ $form_state['bundle'] = $bundle;
}
- $this->entity_type = $entity_type;
- $this->bundle = $bundle;
- $this->mode = $form_mode;
- $this->adminPath = $this->entityManager->getAdminPath($this->entity_type, $this->bundle);
-
- // Gather bundle information.
- $instances = $this->fieldInfo->getBundleInstances($entity_type, $bundle);
- $field_types = $this->fieldTypePluginManager->getDefinitions();
- $extra_fields = $this->fieldInfo->getBundleExtraFields($entity_type, $bundle);
- $extra_fields = isset($extra_fields['form']) ? $extra_fields['form'] : array();
-
- // Field prefix.
- $field_prefix = $this->config('field_ui.settings')->get('field_prefix');
+ $this->entityType = $entity_type;
+ $this->bundle = $form_state['bundle'];
+ $this->adminPath = $this->entityManager->getAdminPath($this->entityType, $this->bundle);
$form = array(
- '#entity_type' => $this->entity_type,
- '#bundle' => $this->bundle,
- '#fields' => array_keys($instances),
- '#extra' => array_keys($extra_fields),
- '#tree' => TRUE,
'#attributes' => array(
- 'class' => array('field-ui-overview'),
- 'id' => 'field-display-overview',
+ 'id' => 'field-add-wrapper',
),
- // @todo Remove once _title from \Drupal\field_ui\Routing\RouteSubscriber
- // will start to work.
- '#title' => 'Add a new field',
);
// Gather valid field types to add.
$field_type_options = array();
- foreach ($field_types as $name => $field_type) {
+ foreach ($this->fieldTypePluginManager->getConfigurableDefinitions() as $name => $field_type) {
// Skip field types which should not be added via user interface.
if (empty($field_type['no_ui'])) {
$field_type_options[$name] = $field_type['label'];
@@ -165,7 +155,39 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
'#options' => $field_type_options,
'#empty_option' => $this->t('- Select a field type -'),
'#description' => $this->t('Type of data to store.'),
- '#attributes' => array('class' => array('field-type-select')),
+ );
+
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => $this->t('Label'),
+ '#size' => 15,
+ '#weight' => 20,
+ );
+
+ $field_prefix = $this->config('field_ui.settings')->get('field_prefix');
+ $form['field_name'] = array(
+ '#type' => 'machine_name',
+ // This field should stay LTR even for RTL languages.
+ '#field_prefix' => '' . $field_prefix,
+ '#field_suffix' => '',
+ '#size' => 15,
+ '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
+ // Calculate characters depending on the length of the field prefix
+ // setting. Maximum length is 32.
+ '#maxlength' => Field::NAME_MAX_LENGTH - strlen($field_prefix),
+ '#machine_name' => array(
+ 'source' => array('label'),
+ 'exists' => array($this, 'fieldNameExists'),
+ ),
+ '#required' => FALSE,
+ '#weight' => 25,
+ );
+
+ // Place the 'translatable' property as an explicit value so that
+ // contrib modules can form_alter() the value for newly created fields.
+ $form['translatable'] = array(
+ '#type' => 'value',
+ '#value' => FALSE,
);
// Determine which options from the 'type' field already have existing
@@ -178,74 +200,41 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
$states[] = array('value' => $field['type']);
}
- $form['new-or-existing'] = array(
- '#type' => 'select',
- '#title' => $this->t('New or Existing'),
- '#options' => array(
- $this->t('New'),
- $this->t('Existing'),
- ),
- '#empty_option' => $this->t('- New or Existing -'),
+ // #states don't work if they are used on a 'radios' element so we have to
+ // use a wrapper.
+ $form['new_or_existing_wrapper'] = array(
+ '#type' => 'container',
'#states' => array(
'visible' => array(
'select[name="type"]' => $states,
),
),
);
+ $form['new_or_existing_wrapper']['new_or_existing'] = array(
+ '#type' => 'radios',
+ '#options' => array(
+ 'new' => $this->t('Create a new field'),
+ 'existing' => $this->t('Create a new instance of an existing field'),
+ ),
+ '#default_value' => 'new',
+ '#weight' => 10,
+ '#ajax' => array(
+ 'callback' => array(get_class($this), 'updateForm'),
+ 'wrapper' => 'field-add-wrapper',
+ ),
+ );
- if ($field_type_options) {
- $states[] = array('value' => '');
- $name = '_add_new_field';
- $form[$name] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('new-field-settings')),
- // Only show this field if a type has been selected and 'Existing'
- // has not explicitly been selected.
- '#states' => array(
- 'invisible' => array(
- 'select[name="type"]' => $states,
- 'select[name="new-or-existing"]' => array('!value' => 0),
- ),
- ),
- 'label' => array(
- '#type' => 'textfield',
- '#title' => $this->t('New field label'),
- '#size' => 15,
- '#description' => $this->t('Label'),
- ),
- 'field_name' => array(
- '#type' => 'machine_name',
- '#title' => $this->t('New field name'),
- // This field should stay LTR even for RTL languages.
- '#field_prefix' => '' . $field_prefix,
- '#field_suffix' => '',
- '#size' => 15,
- '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
- // Calculate characters depending on the length of the field prefix
- // setting. Maximum length is 32.
- '#maxlength' => Field::NAME_MAX_LENGTH - strlen($field_prefix),
- '#machine_name' => array(
- 'source' => array($name, 'label'),
- 'exists' => array($this, 'fieldNameExists'),
- 'standalone' => TRUE,
- 'label' => '',
- ),
- '#required' => FALSE,
- ),
- // Place the 'translatable' property as an explicit value so that
- // contrib modules can form_alter() the value for newly created fields.
- 'translatable' => array(
- '#type' => 'value',
- '#value' => FALSE,
- ),
- );
- }
-
- // Additional row: re-use existing field.
- if ($existing_fields) {
- // Build list of options.
+ // Update the 'field_name' element if we are adding a new instance of an
+ // existing field.
+ if (isset($form_state['values']['new_or_existing']) && $form_state['values']['new_or_existing'] == 'existing') {
$existing_field_options = array();
foreach ($existing_fields as $field_name => $info) {
+ // Show only existing fields of the same type as the one selected by the
+ // user.
+ if (isset($form_state['values']['type']) && $form_state['values']['type'] != $info['type']) {
+ continue;
+ }
+
$text = $this->t('@type: @field (@label)', array(
'@type' => $info['type_label'],
'@label' => $info['label'],
@@ -255,42 +244,29 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
}
asort($existing_field_options);
- $name = '_add_existing_field';
- $form[$name] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('existing-field-settings')),
- // Only show this field if 'Existing' has explicitly been selected.
- '#states' => array(
- 'invisible' => array(
- 'select[name="new-or-existing"]' => array('!value' => 1),
- ),
- ),
- 'field_name' => array(
- '#type' => 'select',
- '#title' => $this->t('Existing field to share'),
- '#options' => $existing_field_options,
- '#empty_option' => $this->t('- Select an existing field -'),
- '#description' => $this->t('Field to share'),
- '#attributes' => array('class' => array('field-select')),
- ),
- 'label' => array(
- '#type' => 'textfield',
- '#title' => $this->t('Existing field label'),
- '#size' => 15,
- '#description' => $this->t('Label'),
- '#attributes' => array('class' => array('label-textfield')),
- ),
+ $form['field_name'] = array(
+ '#type' => 'select',
+ '#title' => $this->t('Existing field to share'),
+ '#options' => $existing_field_options,
+ '#empty_option' => $this->t('- Select an existing field -'),
+ '#weight' => 15,
);
}
- // This key is used to store the current updated field.
- $form_state += array(
- 'formatter_settings_edit' => NULL,
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->t('Add field'),
+ '#button_type' => 'primary',
);
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save field settings'));
+ return $form;
+ }
+ /**
+ * Handles switching the 'new_or_existing' selector.
+ */
+ public static function updateForm($form, &$form_state) {
return $form;
}
@@ -298,18 +274,19 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
- switch($form_state['values']['new-or-existing']) {
- case 0:
- $this->validateAddNew($form, $form_state);
- break;
- case 1:
- $this->validateAddExisting($form, $form_state);
- break;
+ $values = $form_state['values'];
+
+ // Missing field type.
+ if (!$values['type']) {
+ $this->formBuilder->setErrorByName('type', $form_state, $this->t('You need to select a field type.'));
}
+
+ $this->validateAddNew($form, $form_state);
+ $this->validateAddExisting($form, $form_state);
}
/**
- * Validates the 'add new field' row.
+ * Validates the 'add new field' case.
*
* @param array $form
* An associative array containing the structure of the form.
@@ -319,45 +296,34 @@ public function validateForm(array &$form, array &$form_state) {
* @see \Drupal\field_ui\Form\FieldAddForm::validateForm()
*/
protected function validateAddNew(array $form, array &$form_state) {
- $field = $form_state['values']['_add_new_field'];
$values = $form_state['values'];
- // Validate if any information was provided in the 'add new field' row.
- if (array_filter(array($field['label'], $field['field_name'], $values['type']))) {
+ // Validate if any information was provided in the 'add new field' case.
+ if ($values['new_or_existing'] == 'new' && array_filter(array($values['label'], $values['field_name']))) {
// Missing label.
- if (!$field['label']) {
- form_set_error('_add_new_field][label', $this->t('Add new field: you need to provide a label.'));
+ if (!$values['label']) {
+ $this->formBuilder->setErrorByName('label', $form_state, $this->t('You need to provide a label.'));
}
// Missing field name.
- if (!$field['field_name']) {
- form_set_error('_add_new_field][field_name', $this->t('Add new field: you need to provide a field name.'));
+ if (!$values['field_name']) {
+ $this->formBuilder->setErrorByName('field_name', $form_state, $this->t('You need to provide a field name.'));
}
// Field name validation.
else {
- $field_name = $field['field_name'];
-
- // Add the field prefix.
+ $field_name = $values['field_name'];
$field_prefix = $this->config('field_ui.settings')->get('field_prefix');
// Check if the field name is not longer then the max_length.
if(Field::NAME_MAX_LENGTH - (strlen($field_prefix) + strlen($field_name)) < 0) {
- form_set_error('_add_new_field][field_name', $this->t('New field name cannot be longer than %max_length characters but is currently %current_length characters long.', array('%max_length' => Field::NAME_MAX_LENGTH - strlen($field_prefix), 'current_length' => strlen($field_name))));
+ $this->formBuilder->setErrorByName('field_name', $form_state, $this->t('New field name cannot be longer than %max_length characters but is currently %current_length characters long.', array('%max_length' => Field::NAME_MAX_LENGTH - strlen($field_prefix), 'current_length' => strlen($field_name))));
}
-
- $field_name = $field_prefix . $field_name;
- form_set_value($form['_add_new_field']['field_name'], $field_name, $form_state);
- }
-
- // Missing field type.
- if (!$values['type']) {
- form_set_error('_add_new_field][type', $this->t('Add new field: you need to select a field type.'));
}
}
}
/**
- * Validates the 're-use existing field' row.
+ * Validates the 're-use existing field' case.
*
* @param array $form
* An associative array containing the structure of the form.
@@ -367,23 +333,18 @@ protected function validateAddNew(array $form, array &$form_state) {
* @see \Drupal\field_ui\Form\FieldAddForm::validateForm()
*/
protected function validateAddExisting(array $form, array &$form_state) {
- // The form element might be absent if no existing fields can be added to
- // this bundle.
- if (isset($form_state['values']['_add_existing_field'])) {
- $field = $form_state['values']['_add_existing_field'];
-
- // Validate if any information was provided in the
- // 're-use existing field' row.
- if (array_filter(array($field['label'], $field['field_name']))) {
- // Missing label.
- if (!$field['label']) {
- form_set_error('_add_existing_field][label', $this->t('Re-use existing field: you need to provide a label.'));
- }
+ $values = $form_state['values'];
- // Missing existing field name.
- if (!$field['field_name']) {
- form_set_error('_add_existing_field][field_name', $this->t('Re-use existing field: you need to select a field.'));
- }
+ // Validate if any information was provided.
+ if ($values['new_or_existing'] == 'existing' && array_filter(array($values['label'], $values['field_name']))) {
+ // Missing label.
+ if (!$values['label']) {
+ $this->formBuilder->setErrorByName('label', $form_state, $this->t('You need to provide a label.'));
+ }
+
+ // Missing existing field name.
+ if (!$values['field_name']) {
+ $this->formBuilder->setErrorByName('field_name', $form_state, $this->t('You need to select an existing field.'));
}
}
}
@@ -392,52 +353,40 @@ protected function validateAddExisting(array $form, array &$form_state) {
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
+ $values = $form_state['values'];
$destinations = array();
// Create new field.
- if (!empty($form_state['values']['_add_new_field']['field_name'])) {
- $values = $form_state['values']['_add_new_field'];
+ if ($values['new_or_existing'] == 'new') {
+ $field_prefix = $this->config('field_ui.settings')->get('field_prefix');
$field = array(
- 'entity_type' => $this->entity_type,
- 'name' => $form_state['values']['_add_new_field']['field_name'],
+ 'entity_type' => $this->entityType,
+ 'name' => $field_prefix . $form_state['values']['field_name'],
'type' => $form_state['values']['type'],
- 'translatable' => $form_state['values']['_add_new_field']['translatable'],
+ 'translatable' => $form_state['values']['translatable'],
);
$instance = array(
'field_name' => $field['name'],
- 'entity_type' => $this->entity_type,
+ 'entity_type' => $this->entityType,
'bundle' => $this->bundle,
'label' => $values['label'],
);
// Create the field and instance.
try {
- $this->entityManager->getStorageController('field_entity')->create($field)->save();
+ $new_field = $this->entityManager->getStorageController('field_entity')->create($field);
+ $new_field->save();
$new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
$new_instance->save();
- // Make sure the field is displayed in the 'default' form mode (using
- // default widget and settings). It stays hidden for other form modes
- // until it is explicitly configured.
- entity_get_form_display($this->entity_type, $this->bundle, 'default')
- ->setComponent($field['name'])
- ->save();
-
- // 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['name'])
- ->save();
+ $this->configureEntityDisplays($new_field);
// Always show the field settings step, as the cardinality needs to be
// configured for new fields.
$destinations[] = $this->adminPath. '/fields/' . $new_instance->id() . '/field';
$destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
-
- // Store new field information for any additional submit handlers.
- $form_state['fields_added']['_add_new_field'] = $field['name'];
+ $destinations[] = $this->adminPath . '/fields';
}
catch (\Exception $e) {
drupal_set_message($this->t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error');
@@ -445,16 +394,15 @@ public function submitForm(array &$form, array &$form_state) {
}
// Re-use existing field.
- if (!empty($form_state['values']['_add_existing_field']['field_name'])) {
- $values = $form_state['values']['_add_existing_field'];
- $field = $this->fieldInfo->getField($this->entity_type, $values['field_name']);
+ if ($values['new_or_existing'] == 'existing') {
+ $field = $this->fieldInfo->getField($this->entityType, $values['field_name']);
if (!empty($field->locked)) {
drupal_set_message($this->t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error');
}
else {
$instance = array(
'field_name' => $field->getFieldName(),
- 'entity_type' => $this->entity_type,
+ 'entity_type' => $this->entityType,
'bundle' => $this->bundle,
'label' => $values['label'],
);
@@ -463,23 +411,10 @@ public function submitForm(array &$form, array &$form_state) {
$new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
$new_instance->save();
- // Make sure the field is displayed in the 'default' form mode (using
- // default widget and settings). It stays hidden for other form modes
- // until it is explicitly configured.
- entity_get_form_display($this->entity_type, $this->bundle, 'default')
- ->setComponent($field->getFieldName())
- ->save();
-
- // 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->getFieldName())
- ->save();
+ $this->configureEntityDisplays($field);
$destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
- // Store new field information for any additional submit handlers.
- $form_state['fields_added']['_add_existing_field'] = $instance['field_name'];
+ $destinations[] = $this->adminPath . '/fields';
}
catch (\Exception $e) {
drupal_set_message($this->t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())), 'error');
@@ -502,39 +437,71 @@ public function submitForm(array &$form, array &$form_state) {
}
/**
+ * Configures the newly created field for the default view and form modes.
+ *
+ * @param FieldDefinitionInterface $field
+ * The field definition.
+ */
+ protected function configureEntityDisplays(FieldDefinitionInterface $field) {
+ // Make sure the field is displayed in the 'default' form mode (using
+ // default widget and settings). It stays hidden for other form modes
+ // until it is explicitly configured.
+ entity_get_form_display($this->entityType, $this->bundle, 'default')
+ ->setComponent($field->getFieldName())
+ ->save();
+
+ // 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->entityType, $this->bundle, 'default')
+ ->setComponent($field->getFieldName())
+ ->save();
+ }
+
+ /**
* Returns an array of existing fields to be added to a bundle.
*
* @return array
* An array of existing fields keyed by field name.
*/
protected function getExistingFieldOptions() {
- $info = array();
- $field_types = $this->fieldTypePluginManager->getDefinitions();
-
- $instances = $this->fieldInfo->getInstances($this->entity_type);
- foreach ($instances as $instance) {
- foreach ($instance as $field_name => $instance_settings) {
- if (!($instance_settings->bundle == $this->bundle && $instance_settings->entity_type == $this->entity_type)) {
- $field = $this->fieldInfo->getField($instance_settings->entity_type, $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)
- && !$this->fieldInfo->getInstance($this->entity_type, $this->bundle, $field->id())
- && empty($field_types[$field->getFieldType()]['no_ui'])) {
- $info[$instance_settings->getFieldName()] = array(
- 'type' => $field->getFieldType(),
- 'type_label' => $field_types[$field->getFieldType()]['label'],
- 'field' => $field->id(),
- 'label' => $instance_settings->label(),
- );
- }
+ $options = array();
+
+ // Collect candidate field instances: all instances of fields for this
+ // entity type that are not already present in the current bundle.
+ $field_map = $this->fieldInfo->getFieldMap();
+ $instance_ids = array();
+ if (!empty($field_map[$this->entityType])) {
+ foreach ($field_map[$this->entityType] as $field_name => $data) {
+ if (!in_array($this->bundle, $data['bundles'])) {
+ $bundle = reset($data['bundles']);
+ $instance_ids[] = $this->entityType . '.' . $bundle . '.' . $field_name;
}
}
}
- return $info;
+
+ // Load the instances and build the list of options.
+ if ($instance_ids) {
+ $field_types = $this->fieldTypePluginManager->getConfigurableDefinitions();
+ $instances = $this->entityManager->getStorageController('field_instance')->loadMultiple($instance_ids);
+ foreach ($instances as $instance) {
+ // Do not show:
+ // - locked fields,
+ // - fields that should not be added via user interface.
+ $field_type = $instance->getFieldType();
+ $field = $instance->getField();
+ if (empty($field->locked) && empty($field_types[$field_type]['no_ui'])) {
+ $options[$instance->getFieldName()] = array(
+ 'type' => $field_type,
+ 'type_label' => $field_types[$field_type]['label'],
+ 'field' => $instance->getFieldName(),
+ 'label' => $instance->getFieldLabel(),
+ );
+ }
+ }
+ }
+
+ return $options;
}
/**
@@ -550,15 +517,7 @@ public function fieldNameExists($value) {
// Get the configured field prefix.
$field_prefix = $this->config('field_ui.settings')->get('field_prefix');
- // We need to check inactive fields as well, so we can't use
- // field_info_fields().
- return (bool) $this->entityManager
- ->getStorageController('field_entity')
- ->loadByProperties(array(
- 'field_name' => $field_prefix . $value,
- 'include_inactive' => TRUE,
- 'include_deleted' => TRUE)
- );
+ return (bool) $this->fieldInfo->getField($this->entityType, $field_prefix . $value);
}
}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
index 5551232..fc1e445 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
@@ -160,7 +160,11 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
$form['field']['settings'] += $entity->get($field->getFieldName())->offsetGet(0)->settingsForm($form, $form_state, $field->hasData());
$form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save field settings'));
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->t('Save field settings'),
+ '#button_type' => 'primary',
+ );
return $form;
}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
index 8a7650f..8f9e919 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
@@ -149,7 +149,8 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
- '#value' => $this->t('Save settings')
+ '#value' => $this->t('Save settings'),
+ '#button_type' => 'primary',
);
$form['actions']['delete'] = array(
'#type' => 'submit',
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php
deleted file mode 100644
index aad6599..0000000
--- a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php
+++ /dev/null
@@ -1,231 +0,0 @@
-entityManager = $entity_manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('entity.manager')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) {
- if (!isset($form_state['bundle'])) {
- if (!$bundle) {
- $entity_info = $this->entityManager->getDefinition($entity_type);
- $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($entity_info['bundle_entity_type']);
- }
- $form_state['bundle'] = $bundle;
- }
-
- $this->entity_type = $entity_type;
- $this->bundle = $form_state['bundle'];
- $this->adminPath = $this->entityManager->getAdminPath($this->entity_type, $this->bundle);
-
- // When displaying the form, make sure the list of fields is up-to-date.
- if (empty($form_state['post'])) {
- field_info_cache_clear();
- }
- }
-
- /**
- * Implements \Drupal\Core\Form\FormInterface::submitForm().
- */
- public function submitForm(array &$form, array &$form_state) {
- }
-
- /**
- * Get the regions needed to create the overview form.
- *
- * @return array
- * Example usage:
- * @code
- * return array(
- * 'content' => array(
- * // label for the region.
- * 'title' => $this->t('Content'),
- * // Indicates if the region is visible in the UI.
- * 'invisible' => TRUE,
- * // A message to indicate that there is nothing to be displayed in
- * // the region.
- * 'message' => $this->t('No field is displayed.'),
- * ),
- * );
- * @endcode
- */
- abstract public function getRegions();
-
- /**
- * Returns an associative array of all regions.
- */
- public function getRegionOptions() {
- $options = array();
- foreach ($this->getRegions() as $region => $data) {
- $options[$region] = $data['title'];
- }
- return $options;
- }
-
- /**
- * 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().
- */
- public function tablePreRender($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.
- $region_name = call_user_func($row['#region_callback'], $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);
- $indentation = array(
- '#theme' => 'indentation',
- '#size' => $depth,
- );
- $row[$cell]['#prefix'] = drupal_render($indentation) . (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], array($this, 'reduceOrder'));
- }
-
- $elements['#attached']['js'][] = array(
- 'type' => 'setting',
- 'data' => array('fieldUIRowsData' => $js_settings),
- );
-
- return $elements;
- }
-
- /**
- * Determines the rendering order of an array representing a tree.
- *
- * Callback for array_reduce() within
- * \Drupal\field_ui\OverviewBase::tablePreRender().
- */
- public function reduceOrder($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'], array($this, 'reduceOrder')));
- }
- return $array;
- }
-
-}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Plugin/Derivative/FieldUiLocalAction.php b/core/modules/field_ui/lib/Drupal/field_ui/Plugin/Derivative/FieldUiLocalAction.php
new file mode 100644
index 0000000..5ac6a06
--- /dev/null
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Plugin/Derivative/FieldUiLocalAction.php
@@ -0,0 +1,90 @@
+entityManager = $entity_manager;
+ $this->translationManager = $translation_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, $base_plugin_id) {
+ return new static(
+ $container->get('entity.manager'),
+ $container->get('string_translation')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDerivativeDefinitions(array $base_plugin_definition) {
+ $this->derivatives = array();
+
+ foreach ($this->entityManager->getDefinitions() as $entity_type => $entity_info) {
+ if ($entity_info['fieldable'] && isset($entity_info['links']['admin-form'])) {
+ $this->derivatives["add_$entity_type"] = array(
+ 'route_name' => "field_ui.add_$entity_type",
+ 'title' => $this->t('Add field'),
+ 'appears_on' => array("field_ui.overview_$entity_type"),
+ );
+ }
+ }
+
+ foreach ($this->derivatives as &$entry) {
+ $entry += $base_plugin_definition;
+ }
+
+ return $this->derivatives;
+ }
+
+ /**
+ * Translates a string to the current language or to a given language.
+ *
+ * See the t() documentation for details.
+ */
+ protected function t($string, array $args = array(), array $options = array()) {
+ return $this->translationManager->translate($string, $args, $options);
+ }
+
+}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
index 6fa3111..00ce3e8 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php
@@ -97,7 +97,7 @@ protected function routes(RouteCollection $collection) {
$route = new Route(
"$path/fields",
array(
- '_form' => '\Drupal\field_ui\FieldOverview',
+ '_content' => '\Drupal\field_ui\Controller\FieldInstanceListController::listing',
'_title' => 'Manage fields',
) + $defaults,
array('_permission' => 'administer ' . $entity_type . ' fields')
@@ -108,7 +108,7 @@ protected function routes(RouteCollection $collection) {
"$path/add-field",
array(
'_form' => '\Drupal\field_ui\Form\FieldAddForm',
- '_title' => 'Add a new field',
+ '_title' => 'Add field',
) + $defaults,
array('_permission' => 'administer ' . $entity_type . ' fields')
);
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
index b9ff9c0..d53dafd 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
@@ -46,9 +46,7 @@ public function setUp() {
*/
public function testFieldUIRoutes() {
$this->drupalGet('field-ui-test-no-bundle/manage/fields');
- // @todo Bring back this assertion in https://drupal.org/node/1963340.
- // @see \Drupal\field_ui\FieldOverview::getRegions()
- //$this->assertText('No fields are present yet.');
+ $this->assertText('No fields are present yet.');
$this->drupalGet('admin/structure/types/manage/article/fields');
$this->assertTitle('Manage fields | Drupal');