OverviewBase.php 7.27 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\field_ui\OverviewBase.
6 7 8 9
 */

namespace Drupal\field_ui;

10
use Drupal\Core\Entity\EntityManagerInterface;
11
use Drupal\Core\Form\FormBase;
12
use Drupal\Core\Render\Element;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14

15 16 17
/**
 * Abstract base class for Field UI overview forms.
 */
18
abstract class OverviewBase extends FormBase {
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

  /**
   * The name of the entity type.
   *
   * @var string
   */
  protected $entity_type = '';

  /**
   * The entity bundle.
   *
   * @var string
   */
  protected $bundle = '';

  /**
35
   * The entity type of the entity bundle.
36 37 38
   *
   * @var string
   */
39
  protected $bundleEntityType;
40 41

  /**
42
   * The entity view or form mode.
43 44 45
   *
   * @var string
   */
46
  protected $mode = '';
47 48

  /**
49
   * The entity manager.
50
   *
51
   * @var \Drupal\Core\Entity\EntityManagerInterface
52
   */
53 54 55 56 57
  protected $entityManager;

  /**
   * Constructs a new OverviewBase.
   *
58
   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
59 60
   *   The entity manager.
   */
61
  public function __construct(EntityManagerInterface $entity_manager) {
62 63 64 65 66 67 68 69
    $this->entityManager = $entity_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
70
      $container->get('entity.manager')
71 72 73 74 75 76
    );
  }

  /**
   * {@inheritdoc}
   */
77 78 79
  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
    $entity_type = $this->entityManager->getDefinition($entity_type_id);
    $this->bundleEntityType = $entity_type->getBundleEntityType();
80 81
    if (!isset($form_state['bundle'])) {
      if (!$bundle) {
82
        $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($this->bundleEntityType);
83 84 85
      }
      $form_state['bundle'] = $bundle;
    }
86

87
    $this->entity_type = $entity_type_id;
88
    $this->bundle = $form_state['bundle'];
89 90 91 92 93

    // When displaying the form, make sure the list of fields is up-to-date.
    if (empty($form_state['post'])) {
      field_info_cache_clear();
    }
94 95 96
  }

  /**
97
   * Implements \Drupal\Core\Form\FormInterface::submitForm().
98
   */
99
  public function submitForm(array &$form, array &$form_state) {
100 101 102 103 104 105 106 107 108 109 110
  }

  /**
   * Get the regions needed to create the overview form.
   *
   * @return array
   *   Example usage:
   *   @code
   *     return array(
   *       'content' => array(
   *         // label for the region.
111
   *         'title' => $this->t('Content'),
112 113
   *         // Indicates if the region is visible in the UI.
   *         'invisible' => TRUE,
114
   *         // A message to indicate that there is nothing to be displayed in
115
   *         // the region.
116
   *         'message' => $this->t('No field is displayed.'),
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
   *       ),
   *     );
   *   @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;
  }

134 135 136 137 138 139
  /**
   * Performs pre-render tasks on field_ui_table elements.
   *
   * This function is assigned as a #pre_render callback in
   * field_ui_element_info().
   *
140 141 142 143 144 145 146 147 148
   * @param array $element
   *   A structured array containing two sub-levels of elements. Properties
   *   used:
   *   - #tabledrag: The value is a list of $options arrays that are passed to
   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
   *     $options array.
   *
   * @see drupal_render()
   * @see drupal_pre_render_table()
149 150 151 152 153 154 155 156 157 158 159 160
   */
  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();
161 162
    $children = Element::children($elements);
    $list = array_combine($children, $children);
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

    // 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])) {
187
            $children = Element::children($row);
188
            $cell = current($children);
189 190 191 192 193
            $indentation = array(
              '#theme' => 'indentation',
              '#size' => $depth,
            );
            $row[$cell]['#prefix'] = drupal_render($indentation) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
          }

          // 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),
    );

220 221 222 223 224 225 226 227 228 229
    // If the custom #tabledrag is set and there is a HTML ID, add the table's
    // HTML ID to the options and attach the behavior.
    // @see drupal_pre_render_table()
    if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
      foreach ($elements['#tabledrag'] as $options) {
        $options['table_id'] = $elements['#attributes']['id'];
        drupal_attach_tabledrag($elements, $options);
      }
    }

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    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'])) {
245
      uasort($a['children'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
246 247 248 249 250
      $array = array_merge($array, array_reduce($a['children'], array($this, 'reduceOrder')));
    }
    return $array;
  }

251
}