FileWidget.php 9.41 KB
Newer Older
1
2
3
4
<?php

/**
 * @file
5
 * Contains \Drupal\file\Plugin\Field\FieldWidget\FileWidget.
6
7
 */

8
namespace Drupal\file\Plugin\Field\FieldWidget;
9

10
use Drupal\Core\Field\FieldDefinitionInterface;
11
use Drupal\Core\Field\WidgetBase;
12
use Drupal\Core\Field\FieldItemListInterface;
13
14
15
16

/**
 * Plugin implementation of the 'file_generic' widget.
 *
17
 * @FieldWidget(
18
19
20
21
22
23
24
 *   id = "file_generic",
 *   label = @Translation("File"),
 *   field_types = {
 *     "file"
 *   },
 *   settings = {
 *     "progress_indicator" = "throbber"
25
 *   }
26
27
28
29
30
 * )
 */
class FileWidget extends WidgetBase {

  /**
31
   * {@inheritdoc}
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   */
  public function settingsForm(array $form, array &$form_state) {
    $element['progress_indicator'] = array(
      '#type' => 'radios',
      '#title' => t('Progress indicator'),
      '#options' => array(
        'throbber' => t('Throbber'),
        'bar' => t('Bar with progress meter'),
      ),
      '#default_value' => $this->getSetting('progress_indicator'),
      '#description' => t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
      '#weight' => 16,
      '#access' => file_progress_implementation(),
    );
    return $element;
  }

  /**
50
   * {@inheritdoc}
51
52
53
54
55
56
57
58
   */
  public function settingsSummary() {
    $summary = array();
    $summary[] = t('Progress indicator: @progress_indicator', array('@progress_indicator' => $this->getSetting('progress_indicator')));
    return $summary;
  }

  /**
59
   * Overrides \Drupal\Core\Field\WidgetBase::formMultipleElements().
60
61
62
   *
   * Special handling for draggable multiple widgets and 'add more' button.
   */
63
  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
64
    $field_name = $this->fieldDefinition->getName();
65
66
67
68
69
    $parents = $form['#parents'];

    // Load the items for form rebuilds from the field state as they might not be
    // in $form_state['values'] because of validation limitations. Also, they are
    // only passed in as $items when editing existing entities.
70
    $field_state = field_form_get_state($parents, $field_name, $form_state);
71
    if (isset($field_state['items'])) {
72
      $items->setValue($field_state['items']);
73
74
75
    }

    // Determine the number of widgets to display.
76
    $cardinality = $this->fieldDefinition->getCardinality();
77
    switch ($cardinality) {
78
      case FieldDefinitionInterface::CARDINALITY_UNLIMITED:
79
80
81
82
83
        $max = count($items);
        $is_multiple = TRUE;
        break;

      default:
84
85
        $max = $cardinality - 1;
        $is_multiple = ($cardinality > 1);
86
87
88
        break;
    }

89
90
    $title = check_plain($this->fieldDefinition->getLabel());
    $description = field_filter_xss($this->fieldDefinition->getDescription());
91
92
93
94
95
96
97
98
99
100

    $elements = array();

    $delta = 0;
    // Add an element for every existing item.
    foreach ($items as $item) {
      $element = array(
        '#title' => $title,
        '#description' => $description,
      );
101
      $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
102
103
104
105
106
107
108
109
110
111
112
113

      if ($element) {
        // Input field for the delta (drag-n-drop reordering).
        if ($is_multiple) {
          // We name the element '_weight' to avoid clashing with elements
          // defined by widget.
          $element['_weight'] = array(
            '#type' => 'weight',
            '#title' => t('Weight for row @number', array('@number' => $delta + 1)),
            '#title_display' => 'invisible',
            // Note: this 'delta' is the FAPI #type 'weight' element's property.
            '#delta' => $max,
114
            '#default_value' => $item->_weight ?: $delta,
115
116
117
118
119
120
121
122
123
            '#weight' => 100,
          );
        }

        $elements[$delta] = $element;
        $delta++;
      }
    }

124
    $empty_single_allowed = ($cardinality == 1 && $delta == 0);
125
    $empty_multiple_allowed = ($cardinality == FieldDefinitionInterface::CARDINALITY_UNLIMITED || $delta < $cardinality) && empty($form_state['programmed']);
126
127
128
129
130
131
132
133

    // Add one more empty row for new uploads except when this is a programmed
    // multiple form as it is not necessary.
    if ($empty_single_allowed || $empty_multiple_allowed) {
      $element = array(
        '#title' => $title,
        '#description' => $description,
      );
134
      $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
135
136
137
138
139
140
141
142
143
144
      if ($element) {
        $element['#required'] = ($element['#required'] && $delta == 0);
        $elements[$delta] = $element;
      }
    }

    if ($is_multiple) {
      // The group of elements all-together need some extra functionality after
      // building up the full list (like draggable table rows).
      $elements['#file_upload_delta'] = $delta;
145
      $elements['#type'] = 'details';
146
      $elements['#theme'] = 'file_widget_multiple';
147
      $elements['#theme_wrappers'] = array('details');
148
149
150
151
152
153
      $elements['#process'] = array('file_field_widget_process_multiple');
      $elements['#title'] = $title;

      $elements['#description'] = $description;
      $elements['#field_name'] = $element['#field_name'];
      $elements['#language'] = $element['#language'];
154
      $elements['#display_field'] = (bool) $this->getFieldSetting('display_field');
155
156
157
158
159
      // The field settings include defaults for the field type. However, this
      // widget is a base class for other widgets (e.g., ImageWidget) that may
      // act on field types without these expected settings.
      $field_settings = $this->getFieldSettings() + array('display_field' => NULL);
      $elements['#display_field'] = (bool) $field_settings['display_field'];
160
161
162
163
164

      // Add some properties that will eventually be added to the file upload
      // field. These are added here so that they may be referenced easily
      // through a hook_form_alter().
      $elements['#file_upload_title'] = t('Add a new file');
165
166
167
168
169
170
      $elements['#file_upload_description'] = array(
        '#theme' => 'file_upload_help',
        '#description' => '',
        '#upload_validators' => $elements[0]['#upload_validators'],
        '#cardinality' => $cardinality,
      );
171
172
173
174
175
176
    }

    return $elements;
  }

  /**
177
   * {@inheritdoc}
178
   */
179
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
180
181
182
183
184
185
186
187
188
189
190
    $field_settings = $this->getFieldSettings();

    // The field settings include defaults for the field type. However, this
    // widget is a base class for other widgets (e.g., ImageWidget) that may act
    // on field types without these expected settings.
    $field_settings += array(
      'display_default' => NULL,
      'display_field' => NULL,
      'description_field' => NULL,
    );

191
    $cardinality = $this->fieldDefinition->getCardinality();
192
    $defaults = array(
193
      'fids' => array(),
194
      'display' => (bool) $field_settings['display_default'],
195
196
197
198
199
200
201
202
      'description' => '',
    );

    // Essentially we use the managed_file type, extended with some
    // enhancements.
    $element_info = element_info('managed_file');
    $element += array(
      '#type' => 'managed_file',
203
204
      '#upload_location' => $items[$delta]->getUploadLocation(),
      '#upload_validators' => $items[$delta]->getUploadValidators(),
205
206
207
208
209
      '#value_callback' => 'file_field_widget_value',
      '#process' => array_merge($element_info['#process'], array('file_field_widget_process')),
      '#progress_indicator' => $this->getSetting('progress_indicator'),
      // Allows this field to return an array instead of a single value.
      '#extended' => TRUE,
210
211
212
213
214
215
      // Add properties needed by file_field_widget_value() and
      // file_field_widget_process().
      '#display_field' => (bool) $field_settings['display_field'],
      '#display_default' => $field_settings['display_default'],
      '#description_field' => $field_settings['description_field'],
      '#cardinality' => $cardinality,
216
217
218
    );

    $element['#weight'] = $delta;
219
220
221

    // Field stores FID value in a single mode, so we need to transform it for
    // form element to recognize it correctly.
222
223
    if (!isset($items[$delta]->fids) && isset($items[$delta]->target_id)) {
      $items[$delta]->fids = array($items[$delta]->target_id);
224
    }
225
    $element['#default_value'] = $items[$delta]->getValue() + $defaults;
226

227
228
    $default_fids = $element['#extended'] ? $element['#default_value']['fids'] : $element['#default_value'];
    if (empty($default_fids)) {
229
230
231
232
233
234
235
      $file_upload_help = array(
        '#theme' => 'file_upload_help',
        '#description' => $element['#description'],
        '#upload_validators' => $element['#upload_validators'],
        '#cardinality' => $cardinality,
      );
      $element['#description'] = drupal_render($file_upload_help);
236
237
238
239
      $element['#multiple'] = $cardinality != 1 ? TRUE : FALSE;
      if ($cardinality != 1 && $cardinality != -1) {
        $element['#element_validate'] = array('file_field_widget_multiple_count_validate');
      }
240
241
242
243
244
    }

    return $element;
  }

245
  /**
246
   * {@inheritdoc}
247
248
249
250
251
252
253
254
255
   */
  public function massageFormValues(array $values, array $form, array &$form_state) {
    // Since file upload widget now supports uploads of more than one file at a
    // time it always returns an array of fids. We have to translate this to a
    // single fid, as field expects single value.
    $new_values = array();
    foreach ($values as &$value) {
      foreach ($value['fids'] as $fid) {
        $new_value = $value;
256
        $new_value['target_id'] = $fid;
257
258
259
260
261
262
263
264
        unset($new_value['fids']);
        $new_values[] = $new_value;
      }
    }

    return $new_values;
  }

265
}