Project

General

Profile

Paste
Download (19.1 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / file_entity / file_entity.field.inc @ 7b2d1845

1
<?php
2

    
3
/**
4
 * @file
5
 * Field API integration for the file_entity module.
6
 */
7

    
8
/**
9
 * Implements hook_field_formatter_info().
10
 */
11
function file_entity_field_formatter_info() {
12
  $info['file_rendered'] = array(
13
    'label' => t('Rendered file'),
14
    'description' => t('Display the file in a specific view mode'),
15
    'field types' => array('file', 'image'),
16
    'settings' => array(
17
      'file_view_mode' => 'default',
18
    ),
19
    'file formatter' => array(
20
      'hidden' => TRUE,
21
    ),
22
  );
23
  $info['file_download_link'] = array(
24
    'label' => t('Download link'),
25
    'description' => t('Displays a link that will force the browser to download the file.'),
26
    'field types' => array('file', 'image'),
27
    'settings' => array(
28
      'text' => t('Download [file:name]'),
29
    ),
30
  );
31
  $info['file_audio'] = array(
32
    'label' => t('Audio'),
33
    'description' => t('Render the file using an HTML5 audio tag.'),
34
    'field types' => array('file'),
35
    'settings' => array(
36
      'controls' => TRUE,
37
      'controls_list' => array(
38
        'download' => 'download',
39
        'remote_playback' => 'remote_playback',
40
      ),
41
      'autoplay' => FALSE,
42
      'loop' => FALSE,
43
      'preload' => '',
44
      'multiple_file_behavior' => 'tags',
45
    ),
46
    'file formatter' => array(
47
      'mime types' => array('audio/*'),
48
    ),
49
  );
50
  $info['file_video'] = array(
51
    'label' => t('Video'),
52
    'description' => t('Render the file using an HTML5 video tag.'),
53
    'field types' => array('file'),
54
    'settings' => array(
55
      'controls' => TRUE,
56
      'controls_list' => array(
57
        'fullscreen' => 'fullscreen',
58
        'download' => 'download',
59
        'remote_playback' => 'remote_playback',
60
      ),
61
      'autoplay' => FALSE,
62
      'playsinline' => FALSE,
63
      'loop' => FALSE,
64
      'muted' => FALSE,
65
      'width' => NULL,
66
      'height' => NULL,
67
      'preload' => '',
68
      'multiple_file_behavior' => 'tags',
69
    ),
70
    'file formatter' => array(
71
      'mime types' => array('video/*'),
72
    ),
73
  );
74
  return $info;
75
}
76

    
77
/**
78
 * Implements hook_field_formatter_info_alter().
79
 */
80
function file_entity_field_formatter_info_alter(&$info) {
81
  // Add descriptions to core formatters.
82
  $descriptions = array(
83
    'file_default' => t('Create a simple link to the file. The link is prefixed by a file type icon and the name of the file is used as the link text'),
84
    'file_table' => t('Build a two-column table where the first column contains a generic link to the file and the second column displays the size of the file.'),
85
    'file_url_plain' => t('Display a plain text URL to the file.'),
86
    'image' => t('Format the file as an image. The image can be displayed using an image style and can optionally be linked to the image file itself or its parent content.'),
87
  );
88
  foreach ($descriptions as $key => $description) {
89
    if (isset($info[$key]) && empty($info[$key]['description'])) {
90
      $info[$key]['description'] = $description;
91
    }
92
  }
93

    
94
  // Formatters that can be used for images but not files, should have a
95
  // default mimetype restriction added to the image/* mime type for use with
96
  // file formatters.
97
  foreach ($info as &$formatter) {
98
    if (!isset($formatter['file formatter']) && in_array('image', $formatter['field types']) && !in_array('file', $formatter['field types'])) {
99
      $formatter['file formatter']['mime types'] = array('image/*');
100
    }
101
  }
102
}
103

    
104
/**
105
 * Implements hook_field_formatter_settings_form().
106
 */
107
function file_entity_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
108
  $display = $instance['display'][$view_mode];
109
  $settings = $display['settings'];
110
  $element = array();
111

    
112
  if ($display['type'] == 'file_rendered') {
113
    $element['file_view_mode'] = array(
114
      '#title'   => t('View mode'),
115
      '#type'    => 'select',
116
      '#options' => file_entity_view_mode_labels(),
117
      '#default_value' => $settings['file_view_mode'],
118
      // Never empty, so no #empty_option
119
    );
120
  }
121
  elseif ($display['type'] == 'file_download_link') {
122
    $element['text'] = array(
123
      '#type' => 'textfield',
124
      '#title' => t('Link text'),
125
      '#description' => t('This field support tokens.'),
126
      '#default_value' => $settings['text'],
127
      '#required' => TRUE,
128
    );
129
  }
130
  elseif ($display['type'] == 'file_audio') {
131
    $element['controls'] = array(
132
      '#title' => t('Show audio controls'),
133
      '#type' => 'checkbox',
134
      '#default_value' => $settings['controls'],
135
    );
136
    $element['controls_list'] = array(
137
      '#title' => t('Controls list'),
138
      '#type' => 'checkboxes',
139
      '#options' => array(
140
        'download' => t('Download'),
141
        'remote_playback' => t('Remote playback'),
142
      ),
143
      '#default_value' => $settings['controls_list'],
144
      '#description' => t("Customize native media controls such as the download and remoteplayback buttons. Valid only if above \"Show audio controls\" setting is enabled.<br>Please note that not all browsers support this feature. Only Chrome 58+ and Opera 45+ supports it."),
145
    );
146
    $element['autoplay'] = array(
147
      '#title' => t('Autoplay'),
148
      '#type' => 'checkbox',
149
      '#default_value' => $settings['autoplay'],
150
    );
151
    $element['loop'] = array(
152
      '#title' => t('Loop'),
153
      '#type' => 'checkbox',
154
      '#default_value' => $settings['loop'],
155
    );
156
    $element['preload'] = array(
157
      '#title' => t('Preload'),
158
      '#type' => 'select',
159
      '#default_value' => $settings['preload'],
160
      '#options' => drupal_map_assoc(array('none', 'auto', 'metadata')),
161
      '#empty_option' => 'unspecified',
162
    );
163
    $element['multiple_file_behavior'] = array(
164
      '#title' => t('Display of multiple files'),
165
      '#type' => 'radios',
166
      '#options' => array(
167
        'tags' => t('Use multiple @tag tags, each with a single source', array('@tag' => '<audio>')),
168
        'sources' => t('Use multiple sources within a single @tag tag', array('@tag' => '<audio>')),
169
      ),
170
      '#default_value' => $settings['multiple_file_behavior'],
171
      // Hide this setting in the manage file display configuration.
172
      '#access' => !empty($field),
173
    );
174

    
175
  }
176
  elseif ($display['type'] == 'file_video') {
177
    $element['controls'] = array(
178
      '#title' => t('Show video controls'),
179
      '#type' => 'checkbox',
180
      '#default_value' => $settings['controls'],
181
    );
182
    $element['controls_list'] = array(
183
      '#title' => t('Controls list'),
184
      '#type' => 'checkboxes',
185
      '#options' => array(
186
        'fullscreen' => t('Fullscreen'),
187
        'download' => t('Download'),
188
        'remote_playback' => t('Remote playback'),
189
      ),
190
      '#default_value' => $settings['controls_list'],
191
      '#description' => t("Customize native media controls such as the download, fullscreen and remoteplayback buttons. Valid only if above \"Show video controls\" setting is enabled.<br>Please note that not all browsers support this feature. Only Chrome 58+ and Opera 45+ supports it."),
192
    );
193
    $element['autoplay'] = array(
194
      '#title' => t('Autoplay'),
195
      '#type' => 'checkbox',
196
      '#default_value' => $settings['autoplay'],
197
    );
198
    $element['playsinline'] = array(
199
      '#title' => t('Plays inline'),
200
      '#type' => 'checkbox',
201
      '#default_value' => $settings['playsinline'],
202
    );
203
    $element['loop'] = array(
204
      '#title' => t('Loop'),
205
      '#type' => 'checkbox',
206
      '#default_value' => $settings['loop'],
207
    );
208
    $element['muted'] = array(
209
      '#title' => t('Muted'),
210
      '#type' => 'checkbox',
211
      '#default_value' => $settings['muted'],
212
    );
213
    $element['width'] = array(
214
      '#type' => 'textfield',
215
      '#title' => t('Width'),
216
      '#default_value' => $settings['width'],
217
      '#size' => 5,
218
      '#maxlength' => 5,
219
      '#field_suffix' => t('pixels'),
220
    );
221
    $element['height'] = array(
222
      '#type' => 'textfield',
223
      '#title' => t('Height'),
224
      '#default_value' => $settings['height'],
225
      '#size' => 5,
226
      '#maxlength' => 5,
227
      '#field_suffix' => t('pixels'),
228
    );
229
    $element['preload'] = array(
230
      '#title' => t('Preload'),
231
      '#type' => 'select',
232
      '#default_value' => $settings['preload'],
233
      '#options' => drupal_map_assoc(array('none', 'auto', 'metadata')),
234
      '#empty_option' => 'unspecified',
235
    );
236
    $element['multiple_file_behavior'] = array(
237
      '#title' => t('Display of multiple files'),
238
      '#type' => 'radios',
239
      '#options' => array(
240
        'tags' => t('Use multiple @tag tags, each with a single source', array('@tag' => '<video>')),
241
        'sources' => t('Use multiple sources within a single @tag tag', array('@tag' => '<video>')),
242
      ),
243
      '#default_value' => $settings['multiple_file_behavior'],
244
      // Hide this setting in the manage file display configuration.
245
      '#access' => !empty($field),
246
    );
247
  }
248

    
249
  return $element;
250
}
251

    
252
/**
253
 * Implements hook_field_formatter_settings_summary().
254
 */
255
function file_entity_field_formatter_settings_summary($field, $instance, $view_mode) {
256
  $display = $instance['display'][$view_mode];
257
  $settings = $display['settings'];
258
  $summary = array();
259

    
260
  if ($display['type'] === 'file_rendered') {
261
    $view_mode_label = file_entity_view_mode_label($settings['file_view_mode'], t('Unknown'));
262
    $summary[] = t('View mode: %mode', array('%mode' => $view_mode_label));
263
  }
264
  elseif ($display['type'] == 'file_download_link') {
265
    $summary[] = t('Link text: %text', array('%text' => $settings['text']));
266
  }
267
  elseif ($display['type'] === 'file_audio') {
268
    if (isset($settings['controls'])) {
269
      $summary[] = t('Controls: %controls', array('%controls' => $settings['controls'] ? 'visible' : 'hidden'));
270
      if (!empty($settings['controls_list'])) {
271
        $controls_list = array();
272
        foreach ($settings['controls_list'] as $key => $value) {
273
          if ($value) {
274
            $controls_list[] = ucfirst(str_replace('_', ' ', $key));
275
          }
276
        }
277
        if (!empty($controls_list)) {
278
          $summary[] = t('Controls list: %controls_list', array('%controls_list' => implode(', ', $controls_list)));
279
        }
280
      }
281
    }
282
    if (isset($settings['autoplay'])) {
283
      $summary[] = t('Autoplay: %autoplay', array('%autoplay' => $settings['autoplay'] ? t('yes') : t('no')));
284
    }
285
    if (isset($settings['loop'])) {
286
      $summary[] = t('Loop: %loop', array('%loop' => $settings['loop'] ? t('yes') : t('no')));
287
    }
288
    if (!empty($settings['preload'])) {
289
      $summary[] = t('Preload: %preload', array('%preload' => $settings['preload']));
290
    }
291
    if (isset($settings['multiple_file_behavior'])) {
292
      $summary[] = t('Multiple files: %multiple', array('%multiple' => $settings['multiple_file_behavior']));
293
    }
294
  }
295
  elseif ($display['type'] === 'file_video') {
296
    if (isset($settings['controls'])) {
297
      $summary[] = t('Controls: %controls', array('%controls' => $settings['controls'] ? 'visible' : 'hidden'));
298
      if (!empty($settings['controls_list'])) {
299
        $controls_list = array();
300
        foreach ($settings['controls_list'] as $key => $value) {
301
          if ($value) {
302
            $controls_list[] = ucfirst(str_replace('_', ' ', $key));
303
          }
304
        }
305
        if (!empty($controls_list)) {
306
          $summary[] = t('Controls list: %controls_list', array('%controls_list' => implode(', ', $controls_list)));
307
        }
308
      }
309
    }
310
    if (isset($settings['autoplay'])) {
311
      $summary[] = t('Autoplay: %autoplay', array('%autoplay' => $settings['autoplay'] ? t('yes') : t('no')));
312
    }
313
    if (isset($settings['playsinline'])) {
314
      $summary[] = t('Plays inline: %playsinline', array('%playsinline' => $settings['playsinline'] ? t('yes') : t('no')));
315
    }
316
    if (isset($settings['loop'])) {
317
      $summary[] = t('Loop: %loop', array('%loop' => $settings['loop'] ? t('yes') : t('no')));
318
    }
319
    if (isset($settings['muted'])) {
320
      $summary[] = t('Muted: %muted', array('%muted' => $settings['muted'] ? t('yes') : t('no')));
321
    }
322
    if ($settings['width'] && $settings['height']) {
323
      $summary[] = t('Size: %width x %height', array('%width' => $settings['width'], '%height' => $settings['height']));
324
    }
325
    if (!empty($settings['preload'])) {
326
      $summary[] = t('Preload: %preload', array('%preload' => $settings['preload']));
327
    }
328
    if (isset($settings['multiple_file_behavior'])) {
329
      $summary[] = t('Multiple files: %multiple', array('%multiple' => $settings['multiple_file_behavior']));
330
    }
331
  }
332

    
333
  return implode('<br />', $summary);
334
}
335

    
336
/**
337
 * Implements hook_field_formatter_prepare_view().
338
 */
339
function file_entity_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
340
  // File and image fields set item values to NULL if a file cannot be loaded.
341
  // Remove those empty items so we can simply iterate through $items normally
342
  // in file_entity_field_formatter_view().
343
  foreach (array_keys($entities) as $id) {
344
    $items[$id] = array_filter($items[$id]);
345
  }
346
}
347

    
348
/**
349
 * Implements hook_field_formatter_view().
350
 */
351
function file_entity_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
352
  $element = array();
353
  $settings = $display['settings'];
354

    
355
  switch ($display['type']) {
356
    case 'file_rendered':
357
      foreach ($items as $delta => $item) {
358
        if (!empty($item)) {
359
          // The repeat-rendering protection may be disabled if necessary.
360
          if (variable_get('file_entity_protect_repeated_render', TRUE)) {
361
            // Protect ourselves from repeated rendering.
362
            static $repeated_render_depth = array();
363
            list($entity_id) = entity_extract_ids($entity_type, $entity);
364
            $repeated_render_id = $entity_type . $entity_id . $field['field_name'] . $item['fid'];
365
            if (isset($repeated_render_depth[$repeated_render_id])) {
366
              $repeated_render_depth[$repeated_render_id]++;
367
            }
368
            else {
369
              $repeated_render_depth[$repeated_render_id] = 1;
370
            }
371

    
372
            if ($repeated_render_depth[$repeated_render_id] > 20) {
373
              watchdog(
374
                'file_entity',
375
                'Repeated rendering detected when rendering entity %entity_type: %entity_id, using the %field_name field. Aborting rendering.',
376
                array(
377
                  '%entity_type' => 'file',
378
                  '%entity_id' => $item['fid'],
379
                  '%field_name' => $field['field_name'],
380
                ),
381
                WATCHDOG_ERROR
382
              );
383
              return $element;
384
            }
385
          }
386

    
387
          $file = file_load($item['fid']);
388
          if (isset($item['display'])) {
389
            $file->display = $item['display'];
390
          }
391
          if (isset($item['description'])) {
392
            $file->description = $item['description'];
393
          }
394

    
395
          // Add some references to the referencing entity.
396
          // @see https://www.drupal.org/node/2333107
397
          $file->referencing_entity = $entity;
398
          $file->referencing_entity_type = $entity_type;
399
          $file->referencing_field = $field['field_name'];
400

    
401
          // Prevent recursion by checking if the referencing entity is itself
402
          // do not display it again (return an empty array).
403
          // This senario is created a few lines below when file_view is called
404
          // it returns an array containing a referncing entity that is itself.
405
          // This is likely treating the symptom and not the root cause which is
406
          // probably buried in some hook_file_view() setting the referencing
407
          // entity.
408
          if (!empty($entity->fid) && $entity->fid === $item['fid']) {
409
            return $element;
410
          }
411
          // Untranslatable fields are rendered with no language code, fall back
412
          // to the content language in that case.
413
          $element[$delta] = file_view($file, $settings['file_view_mode'], $langcode !== LANGUAGE_NONE ? $langcode : NULL);
414
        } else {
415
          watchdog(
416
            'file_entity',
417
            'In the %referencing_entity_type, the %field_name field refers to a %entity_type which does not exist. Aborting the render for it.',
418
            array(
419
              '%referencing_entity_type' => $entity_type,
420
              '%field_name' => $field['field_name'],
421
              '%entity_type' => 'file',
422
            ),
423
            WATCHDOG_ERROR
424
          );
425
        }
426
      }
427
      break;
428

    
429
    case 'file_download_link':
430
      // Prevent 'empty' fields from causing a WSOD.
431
      $items = array_filter($items);
432
      foreach ($items as $delta => $item) {
433
        if (!empty($item['fid']) && ($file = file_load($item['fid'])) && file_entity_access('download', $file)) {
434
          if (isset($item['display'])) {
435
            $file->display = $item['display'];
436
          }
437
          if (isset($item['description'])) {
438
            $file->description = $item['description'];
439
          }
440
          $element[$delta] = array(
441
            '#theme' => 'file_entity_download_link',
442
            '#file' => $file,
443
            '#text' => $settings['text'],
444
          );
445
        }
446
      }
447
      break;
448

    
449
    case 'file_audio':
450
      $multiple_file_behavior = $settings['multiple_file_behavior'];
451

    
452
      // Build an array of sources for each <audio> element.
453
      $source_lists = array();
454
      if ($multiple_file_behavior == 'tags') {
455
        foreach ($items as $delta => $item) {
456
          if (file_entity_file_get_mimetype_type($item) == 'audio') {
457
            $source_lists[$delta] = array($item);
458
          }
459
        }
460
      }
461
      else {
462
        foreach ($items as $delta => $item) {
463
          if (file_entity_file_get_mimetype_type($item) == 'audio') {
464
            $source_lists[0][$delta] = $item;
465
          }
466
        }
467
      }
468

    
469
      // Render each source list as an <audio> element.
470
      foreach ($source_lists as $delta => $sources) {
471
        $element[$delta] = array(
472
          '#theme' => 'file_entity_file_audio',
473
          '#files' => $sources,
474
          '#controls' => $settings['controls'],
475
          '#controls_list' => $settings['controls_list'],
476
          '#autoplay' => $settings['autoplay'],
477
          '#loop' => $settings['loop'],
478
          '#preload' => $settings['preload'],
479
        );
480
      }
481
      break;
482

    
483
    case 'file_video':
484
      $multiple_file_behavior = $settings['multiple_file_behavior'];
485

    
486
      // Build an array of sources for each <video> element.
487
      $source_lists = array();
488
      if ($multiple_file_behavior == 'tags') {
489
        foreach ($items as $delta => $item) {
490
          if (file_entity_file_get_mimetype_type($item) == 'video') {
491
            $source_lists[$delta] = array($item);
492
          }
493
        }
494
      }
495
      else {
496
        foreach ($items as $delta => $item) {
497
          if (file_entity_file_get_mimetype_type($item) == 'video') {
498
            $source_lists[0][$delta] = $item;
499
          }
500
        }
501
      }
502

    
503
      // Render each source list as an <video> element.
504
      foreach ($source_lists as $delta => $sources) {
505
        $element[$delta] = array(
506
          '#theme' => 'file_entity_file_video',
507
          '#files' => $sources,
508
          '#controls' => $settings['controls'],
509
          '#controls_list' => $settings['controls_list'],
510
          '#autoplay' => $settings['autoplay'],
511
          '#playsinline' => $settings['playsinline'],
512
          '#loop' => $settings['loop'],
513
          '#muted' => $settings['muted'],
514
          '#width' => $settings['width'],
515
          '#height' => $settings['height'],
516
          '#preload' => $settings['preload'],
517
        );
518
      }
519
      break;
520
  }
521

    
522
  return $element;
523
}