Projet

Général

Profil

Paste
Télécharger (42 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / file_entity / file_entity.admin.inc @ 66c11afc

1
<?php
2

    
3
/**
4
 * @file
5
 * File administration and module settings UI.
6
 */
7

    
8
require_once dirname(__FILE__) . '/file_entity.pages.inc';
9

    
10
/**
11
 * List file administration filters that can be applied.
12
 */
13
function file_filters() {
14
  $visible_steam_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE);
15
  $options = array();
16
  foreach ($visible_steam_wrappers as $scheme => $information) {
17
    $options[$scheme] = check_plain($information['name']);
18
  }
19
  $filters['uri'] = array(
20
    'title' => t('scheme'),
21
    'options' => array(
22
      '[any]' => t('any'),
23
    ) + $options,
24
  );
25
  $filters['type'] = array(
26
    'title' => t('type'),
27
    'options' => array(
28
      '[any]' => t('any'),
29
    ) + file_entity_type_get_names(),
30
  );
31
  return $filters;
32
}
33

    
34
/**
35
 * Apply filters for file administration filters based on session.
36
 *
37
 * @param object $query
38
 *   A SelectQuery to which the filters should be applied.
39
 */
40
function file_entity_build_filter_query(SelectQueryInterface $query) {
41
  // Build query.
42
  $filter_data = isset($_SESSION['file_entity_overview_filter']) ? $_SESSION['file_entity_overview_filter'] : array();
43
  foreach ($filter_data as $index => $filter) {
44
    list($key, $value) = $filter;
45
    switch ($key) {
46
      case 'uri':
47
        $query->condition('fm.' . $key, $value . '%', 'LIKE');
48
        break;
49

    
50
      case 'type':
51
        $query->condition('fm.' . $key, $value);
52
        break;
53

    
54
    }
55
  }
56
}
57

    
58
/**
59
 * Return form for file administration filters.
60
 */
61
function file_entity_filter_form() {
62
  $session = isset($_SESSION['file_entity_overview_filter']) ? $_SESSION['file_entity_overview_filter'] : array();
63
  $filters = file_filters();
64

    
65
  $i = 0;
66
  $form['filters'] = array(
67
    '#type' => 'fieldset',
68
    '#title' => t('Show only items where'),
69
    '#theme' => 'exposed_filters__file_entity',
70
  );
71
  foreach ($session as $filter) {
72
    list($type, $value) = $filter;
73
    if ($type == 'term') {
74
      // Load term name from DB rather than search and parse options array.
75
      $value = module_invoke('taxonomy', 'term_load', $value);
76
      $value = $value->name;
77
    }
78
    else {
79
      $value = $filters[$type]['options'][$value];
80
    }
81
    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
82
    if ($i++) {
83
      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
84
    }
85
    else {
86
      $form['filters']['current'][] = array('#markup' => t('where %property is %value', $t_args));
87
    }
88
    if (in_array($type, array('type', 'uri'))) {
89
      // Remove the option if it is already being filtered on.
90
      unset($filters[$type]);
91
    }
92
  }
93

    
94
  $form['filters']['status'] = array(
95
    '#type' => 'container',
96
    '#attributes' => array('class' => array('clearfix')),
97
    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
98
  );
99
  $form['filters']['status']['filters'] = array(
100
    '#type' => 'container',
101
    '#attributes' => array('class' => array('filters')),
102
  );
103
  foreach ($filters as $key => $filter) {
104
    $form['filters']['status']['filters'][$key] = array(
105
      '#type' => 'select',
106
      '#options' => $filter['options'],
107
      '#title' => $filter['title'],
108
      '#default_value' => '[any]',
109
    );
110
  }
111

    
112
  $form['filters']['status']['actions'] = array(
113
    '#type' => 'actions',
114
    '#attributes' => array('class' => array('container-inline')),
115
  );
116
  if (count($filters)) {
117
    $form['filters']['status']['actions']['submit'] = array(
118
      '#type' => 'submit',
119
      '#value' => count($session) ? t('Refine') : t('Filter'),
120
    );
121
  }
122
  if (count($session)) {
123
    $form['filters']['status']['actions']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
124
    $form['filters']['status']['actions']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
125
  }
126

    
127
  drupal_add_js('misc/form.js');
128

    
129
  return $form;
130
}
131

    
132
/**
133
 * Process result from file administration filter form.
134
 */
135
function file_entity_filter_form_submit($form, &$form_state) {
136
  $filters = file_filters();
137
  switch ($form_state['values']['op']) {
138
    case t('Filter'):
139
    case t('Refine'):
140
      // Apply every filter that has a choice selected other than 'any'.
141
      foreach ($filters as $filter => $options) {
142
        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
143
          // Flatten the options array to accommodate hierarchical/nested
144
          // options.
145
          $flat_options = form_options_flatten($filters[$filter]['options']);
146
          // Only accept valid selections offered on the dropdown, block bad
147
          // input.
148
          if (isset($flat_options[$form_state['values'][$filter]])) {
149
            $_SESSION['file_entity_overview_filter'][] = array($filter, $form_state['values'][$filter]);
150
          }
151
        }
152
      }
153
      break;
154

    
155
    case t('Undo'):
156
      array_pop($_SESSION['file_entity_overview_filter']);
157
      break;
158

    
159
    case t('Reset'):
160
      $_SESSION['file_entity_overview_filter'] = array();
161
      break;
162

    
163
  }
164
}
165

    
166
/**
167
 * Make mass update of files.
168
 *
169
 * Change all files in the $files array to update them with the field values in
170
 * $updates.
171
 *
172
 * IMPORTANT NOTE: This function is intended to work when called
173
 * from a form submit handler. Calling it outside of the form submission
174
 * process may not work correctly.
175
 *
176
 * @param array $files
177
 *   Array of file fids to update.
178
 * @param array $updates
179
 *   Array of key/value pairs with file field names and the
180
 *   value to update that field to.
181
 */
182
function file_entity_mass_update(array $files, array $updates) {
183
  // We use batch processing to prevent timeout when updating a large number
184
  // of files.
185
  if (count($files) > 10) {
186
    $batch = array(
187
      'operations' => array(
188
        array(
189
          '_file_entity_mass_update_batch_process',
190
          array($files, $updates),
191
        ),
192
      ),
193
      'finished' => '_file_entity_mass_update_batch_finished',
194
      'title' => t('Processing'),
195
      // We use a single multi-pass operation, so the default
196
      // 'Remaining x of y operations' message will be confusing here.
197
      'progress_message' => '',
198
      'error_message' => t('The update has encountered an error.'),
199
      // The operations do not live in the .module file, so we need to
200
      // tell the batch engine which file to load before calling them.
201
      'file' => drupal_get_path('module', 'file_entity') . '/file_entity.admin.inc',
202
    );
203
    batch_set($batch);
204
  }
205
  else {
206
    foreach ($files as $fid) {
207
      _file_entity_mass_update_helper($fid, $updates);
208
    }
209
    drupal_set_message(t('The update has been performed.'));
210
  }
211
}
212

    
213
/**
214
 * File Mass Update - helper function.
215
 */
216
function _file_entity_mass_update_helper($fid, $updates) {
217
  $file = file_load($fid);
218
  // For efficiency manually save the original file before applying any changes.
219
  $file->original = clone $file;
220
  foreach ($updates as $name => $value) {
221
    $file->$name = $value;
222
  }
223
  file_save($file);
224
  return $file;
225
}
226

    
227
/**
228
 * File Mass Update Batch operation.
229
 */
230
function _file_entity_mass_update_batch_process($files, $updates, &$context) {
231
  if (!isset($context['sandbox']['progress'])) {
232
    $context['sandbox']['progress'] = 0;
233
    $context['sandbox']['max'] = count($files);
234
    $context['sandbox']['files'] = $files;
235
  }
236

    
237
  // Process files by groups of 5.
238
  $count = min(5, count($context['sandbox']['files']));
239
  for ($i = 1; $i <= $count; $i++) {
240
    // For each fid, load the file, reset the values, and save it.
241
    $fid = array_shift($context['sandbox']['files']);
242
    $file = _file_entity_mass_update_helper($fid, $updates);
243

    
244
    // Store result for post-processing in the finished callback.
245
    $context['results'][] = l($file->filename, 'file/' . $file->fid);
246

    
247
    // Update our progress information.
248
    $context['sandbox']['progress']++;
249
  }
250

    
251
  // Inform the batch engine that we are not finished,
252
  // and provide an estimation of the completion level we reached.
253
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
254
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
255
  }
256
}
257

    
258
/**
259
 * File Mass Update Batch 'finished' callback.
260
 */
261
function _file_entity_mass_update_batch_finished($success, $results, $operations) {
262
  if ($success) {
263
    drupal_set_message(t('The update has been performed.'));
264
  }
265
  else {
266
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
267
    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
268
    $message .= theme('item_list', array('items' => $results));
269
    drupal_set_message($message);
270
  }
271
}
272

    
273
/**
274
 * Menu callback: file administration.
275
 */
276
function file_entity_admin_file($form, $form_state) {
277
  if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
278
    return file_entity_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['files']));
279
  }
280
  $form['filter'] = file_entity_filter_form();
281
  $form['#submit'][] = 'file_entity_filter_form_submit';
282
  $form['admin'] = file_entity_admin_files();
283

    
284
  return $form;
285
}
286

    
287
/**
288
 * Form builder: Builds the file administration overview.
289
 */
290
function file_entity_admin_files() {
291
  $admin_access = user_access('administer files');
292

    
293
  // Build the 'Update options' form.
294
  $form['options'] = array(
295
    '#type' => 'fieldset',
296
    '#title' => t('Update options'),
297
    '#attributes' => array('class' => array('container-inline')),
298
    '#access' => $admin_access,
299
  );
300
  $options = array();
301
  foreach (module_invoke_all('file_operations') as $operation => $array) {
302
    $options[$operation] = $array['label'];
303
  }
304
  $form['options']['operation'] = array(
305
    '#type' => 'select',
306
    '#title' => t('Operation'),
307
    '#title_display' => 'invisible',
308
    '#options' => $options,
309
    '#default_value' => 'approve',
310
  );
311
  $form['options']['submit'] = array(
312
    '#type' => 'submit',
313
    '#value' => t('Update'),
314
    '#validate' => array('file_entity_admin_files_validate'),
315
    '#submit' => array('file_entity_admin_files_submit'),
316
  );
317

    
318
  // Build the sortable table header.
319
  $header = array(
320
    'title' => array('data' => t('Title'), 'field' => 'fm.filename'),
321
    'type' => array('data' => t('Type'), 'field' => 'fm.type'),
322
    'size' => array('data' => t('Size'), 'field' => 'fm.filesize'),
323
    'author' => t('Author'),
324
    'timestamp' => array(
325
      'data' => t('Updated'),
326
      'field' => 'fm.timestamp',
327
      'sort' => 'desc',
328
    ),
329
    'usage' => array('data' => t('Used in'), 'field' => 'total_count'),
330
    'operations' => array('data' => t('Operations')),
331
  );
332

    
333
  if (variable_get('file_entity_total_count_optimization', FALSE)) {
334
    // If the total_count is being retrieved by subqueries,
335
    // the table is not sortable by this column.
336
    unset($header['usage']['field']);
337
  }
338

    
339
  $query = db_select('file_managed', 'fm')->extend('PagerDefault')->extend('TableSort');
340
  if (!variable_get('file_entity_total_count_optimization', FALSE)) {
341
    $query->leftJoin('file_usage', 'fu', 'fm.fid = fu.fid');
342
    $query->groupBy('fm.fid');
343
    $query->groupBy('fm.uid');
344
    $query->groupBy('fm.timestamp');
345
    $query->addExpression('SUM(fu.count)', 'total_count');
346
  }
347
  file_entity_build_filter_query($query);
348

    
349
  $result = $query
350
    ->fields('fm', array('fid', 'uid'))
351
    ->limit(50)
352
    ->orderByHeader($header)
353
    ->addTag('file_access')
354
    ->execute()
355
    ->fetchAllAssoc('fid');
356

    
357
  if (variable_get('file_entity_total_count_optimization', FALSE)) {
358
    // Get the total_count in separate queries, otherwise the main
359
    // query will take too long.
360
    // This setting can be configured under /admin/config/development/performance.
361
    foreach ($result as &$file_result) {
362
      $count_query = db_select('file_usage', 'fu')
363
        ->fields('fu', array('fid', 'count'))
364
        ->condition('fu.fid', $file_result->fid, '=');
365
      $count_query->addExpression('SUM(fu.count)', 'total_count');
366
      $count_result = $count_query->execute()->fetchAll();
367

    
368
      if (!empty($count_result[0]->total_count)) {
369
        $file_result->total_count = $count_result[0]->total_count;
370
      }
371
    }
372
  }
373

    
374
  $files = file_load_multiple(array_keys($result));
375

    
376
  $uids = array();
377
  foreach ($files as $file) {
378
    $uids[] = $file->uid;
379
  }
380
  $accounts = !empty($uids) ? user_load_multiple(array_unique($uids)) : array();
381

    
382
  // Prepare the list of files.
383
  $destination = drupal_get_destination();
384
  $options = array();
385
  foreach ($files as $file) {
386
    $file_type = file_type_load($file->type);
387
    $account = isset($accounts[$file->uid]) ? $accounts[$file->uid] : NULL;
388
    $total_count = (int) isset($result[$file->fid]->total_count) ? $result[$file->fid]->total_count : 0;
389
    $options[$file->fid] = array(
390
      'title' => array(
391
        'data' => array(
392
          '#type' => 'link',
393
          '#title' => $file->filename,
394
          '#href' => 'file/' . $file->fid,
395
        ),
396
      ),
397
      'type' => $file_type ? check_plain($file_type->label) : FILE_TYPE_NONE,
398
      'size' => format_size($file->filesize),
399
      'author' => theme('username', array('account' => $account)),
400
      'timestamp' => format_date($file->timestamp, 'short'),
401
      'usage' => format_plural($total_count, '1 place', '@count places'),
402
    );
403

    
404
    // Show a warning for files that do not exist.
405
    if (@!is_file($file->uri)) {
406
      $options[$file->fid]['#attributes']['class'][] = 'error';
407
      if (!file_stream_wrapper_get_instance_by_uri($file->uri)) {
408
        $options[$file->fid]['#attributes']['title'] = t('The stream wrapper for @scheme files is missing.', array('@scheme' => file_uri_scheme($file->uri)));
409
      }
410
      else {
411
        $options[$file->fid]['#attributes']['title'] = t('The file does not exist.');
412
      }
413
    }
414

    
415
    // Build a list of all the accessible operations for the current file.
416
    $operations = array();
417
    if (file_entity_access('update', $file)) {
418
      // Convert the usage count to a link.
419
      $options[$file->fid]['usage'] = l($options[$file->fid]['usage'], 'file/' . $file->fid . '/usage');
420
      $operations['edit'] = array(
421
        'title' => t('Edit'),
422
        'href' => 'file/' . $file->fid . '/edit',
423
        'query' => $destination,
424
      );
425
    }
426
    if (file_entity_access('delete', $file)) {
427
      $operations['delete'] = array(
428
        'title' => t('Delete'),
429
        'href' => 'file/' . $file->fid . '/delete',
430
        'query' => $destination,
431
      );
432
    }
433
    $options[$file->fid]['operations'] = array();
434
    if (count($operations) > 1) {
435
      // Render an unordered list of operations links.
436
      $options[$file->fid]['operations'] = array(
437
        'data' => array(
438
          '#theme' => 'links__file_entity_operations',
439
          '#links' => $operations,
440
          '#attributes' => array('class' => array('links', 'inline')),
441
        ),
442
      );
443
    }
444
    elseif (!empty($operations)) {
445
      // Render the first and only operation as a link.
446
      $link = reset($operations);
447
      $options[$file->fid]['operations'] = array(
448
        'data' => array(
449
          '#type' => 'link',
450
          '#title' => $link['title'],
451
          '#href' => $link['href'],
452
          '#options' => array('query' => $link['query']),
453
        ),
454
      );
455
    }
456
  }
457

    
458
  // Only use a tableselect when the current user is able to perform any
459
  // operations.
460
  if ($admin_access) {
461
    $form['files'] = array(
462
      '#type' => 'tableselect',
463
      '#header' => $header,
464
      '#options' => $options,
465
      '#empty' => t('No files available.'),
466
    );
467
  }
468
  // Otherwise, use a simple table.
469
  else {
470
    $form['files'] = array(
471
      '#theme' => 'table',
472
      '#header' => $header,
473
      '#rows' => $options,
474
      '#empty' => t('No files available.'),
475
    );
476
  }
477

    
478
  $form['pager'] = array('#markup' => theme('pager'));
479
  return $form;
480
}
481

    
482
/**
483
 * Validate file_entity_admin_files form submissions.
484
 *
485
 * Check if any files have been selected to perform the chosen
486
 * 'Update option' on.
487
 */
488
function file_entity_admin_files_validate($form, &$form_state) {
489
  // Error if there are no items to select.
490
  if (!is_array($form_state['values']['files']) || !count(array_filter($form_state['values']['files']))) {
491
    form_set_error('', t('No items selected.'));
492
  }
493
}
494

    
495
/**
496
 * Process file_entity_admin_files form submissions.
497
 *
498
 * Execute the chosen 'Update option' on the selected files.
499
 */
500
function file_entity_admin_files_submit($form, &$form_state) {
501
  $operations = module_invoke_all('file_operations');
502
  $operation = $operations[$form_state['values']['operation']];
503
  // Filter out unchecked files.
504
  $files = array_filter($form_state['values']['files']);
505
  if ($function = $operation['callback']) {
506
    // Add in callback arguments if present.
507
    if (isset($operation['callback arguments'])) {
508
      $args = array_merge(array($files), $operation['callback arguments']);
509
    }
510
    else {
511
      $args = array($files);
512
    }
513
    call_user_func_array($function, $args);
514

    
515
    cache_clear_all();
516
  }
517
  else {
518
    // We need to rebuild the form to go to a second step. For example, to
519
    // show the confirmation form for the deletion of files.
520
    $form_state['rebuild'] = TRUE;
521
  }
522
}
523

    
524
/**
525
 * File entity delete confirmation.
526
 */
527
function file_entity_multiple_delete_confirm($form, &$form_state, $files) {
528
  $form['files'] = array(
529
    '#prefix' => '<ul>',
530
    '#suffix' => '</ul>',
531
    '#tree' => TRUE,
532
  );
533
  // array_filter returns only elements with TRUE values.
534
  foreach ($files as $fid => $value) {
535
    $filename = db_query('SELECT filename FROM {file_managed} WHERE fid = :fid', array(':fid' => $fid))->fetchField();
536
    $form['files'][$fid] = array(
537
      '#type' => 'hidden',
538
      '#value' => $fid,
539
      '#prefix' => '<li>',
540
      '#suffix' => check_plain($filename) . "</li>\n",
541
    );
542
  }
543
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
544
  $form['#submit'][] = 'file_entity_multiple_delete_confirm_submit';
545
  $confirm_question = format_plural(count($files),
546
                                  'Are you sure you want to delete this item?',
547
                                  'Are you sure you want to delete these items?');
548
  return confirm_form($form,
549
                    $confirm_question,
550
                    'admin/content/file', t('This action cannot be undone.'),
551
                    t('Delete'), t('Cancel'));
552
}
553

    
554
/**
555
 * Submit handler for delete confirmation.
556
 */
557
function file_entity_multiple_delete_confirm_submit($form, &$form_state) {
558
  if ($form_state['values']['confirm']) {
559
    file_delete_multiple(array_keys($form_state['values']['files']));
560
    $count = count($form_state['values']['files']);
561
    watchdog('file_entity', 'Deleted @count files.', array('@count' => $count));
562
    drupal_set_message(format_plural($count, 'Deleted 1 file.', 'Deleted @count files.'));
563
  }
564
  $form_state['redirect'] = 'admin/content/file';
565
}
566

    
567
/**
568
 * Displays the file type admin overview page.
569
 */
570
function file_entity_list_types_page() {
571
  $file_entity_info = entity_get_info('file');
572
  // Newer versions of Drupal core require the "administer fields" permission
573
  // to access the Field UI.
574
  $field_ui = module_exists('field_ui') && (user_access('administer fields') || !function_exists('field_ui_admin_access'));
575
  $colspan = $field_ui ? 5 : 3;
576
  $header = array(
577
    array('data' => t('Name')),
578
    array('data' => t('Operations'), 'colspan' => $colspan),
579
    array('data' => t('Status')),
580
  );
581
  $rows = array();
582
  $weight = 0;
583
  $types = file_type_load_all(TRUE);
584
  $count = count($types);
585
  foreach ($types as $type) {
586
    $weight++;
587
    $row = array(
588
      array(
589
        'data' => theme('file_entity_file_type_overview',
590
          array(
591
            'label' => $type->label,
592
            'description' => $type->description,
593
          )
594
        ),
595
      ),
596
    );
597
    $path = isset($file_entity_info['bundles'][$type->type]['admin']['real path']) ? $file_entity_info['bundles'][$type->type]['admin']['real path'] : NULL;
598

    
599
    if (empty($type->disabled) && isset($path)) {
600
      $row[] = array('data' => l(t('edit file type'), $path . '/edit'));
601
      if ($field_ui) {
602
        $row[] = array('data' => l(t('manage fields'), $path . '/fields'));
603
        $row[] = array('data' => l(t('manage display'), $path . '/display'));
604
      }
605
      $row[] = array('data' => l(t('manage file display'), $path . '/file-display'));
606
    }
607
    else {
608
      $row += array_fill(1, $colspan - 1, '');
609
    }
610

    
611
    $admin_path = 'admin/structure/file-types/manage/' . $type->type;
612
    switch ($type->ctools_type) {
613
      // Configuration is in code.
614
      case 'Default':
615
      case t('Default'):
616
        if (!empty($type->disabled)) {
617
          $row[] = l(t('enable'), $admin_path . '/enable');
618
        }
619
        else {
620
          $row[] = l(t('disable'), $admin_path . '/disable');
621
        }
622
        break;
623

    
624
      // Configuration is in DB.
625
      case 'Normal':
626
      case t('Normal'):
627
        if (!empty($type->disabled)) {
628
          $status = l(t('enable'), $admin_path . '/enable');
629
        }
630
        else {
631
          $status = l(t('disable'), $admin_path . '/disable');
632
        }
633
        $row[] = $status . ' | ' . l(t('delete'), $admin_path . '/delete');
634
        break;
635

    
636
      // Configuration is in code, but overridden in DB.
637
      case 'Overridden':
638
      case t('Overridden'):
639
        if (!empty($type->disabled)) {
640
          $row[] = l(t('enable'), $admin_path . '/enable');
641
        }
642
        else {
643
          $row[] = l(t('disable'), $admin_path . '/disable') . ' | ' . l(t('revert'), $admin_path . '/revert');
644
        }
645
        break;
646
    }
647

    
648
    if (!empty($type->disabled)) {
649
      $row[] = t('Disabled');
650
      $rows[$weight + $count] = array('data' => $row, 'class' => array('ctools-export-ui-disabled'));
651
    }
652
    else {
653
      $row[] = $type->ctools_type;
654
      $rows[$weight] = array('data' => $row);
655
    }
656
  }
657

    
658
  // Move disabled items to the bottom.
659
  ksort($rows);
660

    
661
  $build['file_type_table'] = array(
662
    '#theme' => 'table',
663
    '#header' => $header,
664
    '#rows' => $rows,
665
    '#empty' => t('No file types available.'),
666
    '#attached' => array(
667
      'css' => array(drupal_get_path('module', 'ctools') . '/css/export-ui-list.css'),
668
    ),
669
  );
670

    
671
  return $build;
672
}
673

    
674
/**
675
 * Form callback; presents file display settings for a given view mode.
676
 */
677
function file_entity_file_display_form($form, &$form_state, $file_type, $view_mode) {
678
  $form['#file_type'] = $file_type->type;
679
  $form['#view_mode'] = $view_mode;
680
  $form['#tree'] = TRUE;
681
  $form['#attached']['js'][] = drupal_get_path('module', 'file_entity') . '/file_entity.admin.js';
682

    
683
  // Retrieve available formatters for this file type and load all configured
684
  // filters for existing text formats.
685
  $formatters = file_info_formatter_types();
686
  foreach ($formatters as $name => $formatter) {
687
    if (!empty($formatter['hidden'])) {
688
      unset($formatters[$name]);
689
    }
690
    if (isset($formatter['mime types'])) {
691
      if (file_entity_match_mimetypes($formatter['mime types'], $file_type->mimetypes)) {
692
        continue;
693
      }
694
      unset($formatters[$name]);
695
    }
696
  }
697
  $current_displays = file_displays_load($file_type->type, $view_mode, TRUE);
698
  foreach ($current_displays as $name => $display) {
699
    $current_displays[$name] = (array) $display;
700
  }
701

    
702
  // Formatter status.
703
  $form['displays']['status'] = array(
704
    '#type' => 'item',
705
    '#title' => t('Enabled displays'),
706
    '#prefix' => '<div id="file-displays-status-wrapper">',
707
    '#suffix' => '</div>',
708
  );
709
  $i = 0;
710
  foreach ($formatters as $name => $formatter) {
711
    $form['displays']['status'][$name] = array(
712
      '#type' => 'checkbox',
713
      '#title' => check_plain($formatter['label']),
714
      '#default_value' => !empty($current_displays[$name]['status']),
715
      '#description' => isset($formatter['description']) ? filter_xss($formatter['description']) : NULL,
716
      '#parents' => array('displays', $name, 'status'),
717
      '#weight' => (isset($formatter['weight']) ? $formatter['weight'] : 0) + ($i / 1000),
718
    );
719
    $i++;
720
  }
721

    
722
  // Formatter order (tabledrag).
723
  $form['displays']['order'] = array(
724
    '#type' => 'item',
725
    '#title' => t('Display precedence order'),
726
    '#theme' => 'file_entity_file_display_order',
727
  );
728
  foreach ($formatters as $name => $formatter) {
729
    $form['displays']['order'][$name]['label'] = array(
730
      '#markup' => check_plain($formatter['label']),
731
    );
732
    $form['displays']['order'][$name]['weight'] = array(
733
      '#type' => 'weight',
734
      '#title' => t('Weight for @title', array('@title' => $formatter['label'])),
735
      '#title_display' => 'invisible',
736
      '#delta' => 50,
737
      '#default_value' => isset($current_displays[$name]['weight']) ? $current_displays[$name]['weight'] : 0,
738
      '#parents' => array('displays', $name, 'weight'),
739
    );
740
    $form['displays']['order'][$name]['#weight'] = $form['displays']['order'][$name]['weight']['#default_value'];
741
  }
742

    
743
  // Formatter settings.
744
  $form['display_settings_title'] = array(
745
    '#type' => 'item',
746
    '#title' => t('Display settings'),
747
  );
748
  $form['display_settings'] = array(
749
    '#type' => 'vertical_tabs',
750
  );
751
  $i = 0;
752
  foreach ($formatters as $name => $formatter) {
753
    if (isset($formatter['settings callback']) && ($function = $formatter['settings callback']) && function_exists($function)) {
754
      $defaults = !empty($formatter['default settings']) ? $formatter['default settings'] : array();
755
      $settings = !empty($current_displays[$name]['settings']) ? $current_displays[$name]['settings'] : array();
756
      $settings += $defaults;
757
      $settings_form = $function($form, $form_state, $settings, $name, $file_type->type, $view_mode);
758
      if (!empty($settings_form)) {
759
        $form['displays']['settings'][$name] = array(
760
          '#type' => 'fieldset',
761
          '#title' => check_plain($formatter['label']),
762
          '#parents' => array('displays', $name, 'settings'),
763
          '#group' => 'display_settings',
764
          '#weight' => (isset($formatter['weight']) ? $formatter['weight'] : 0) + ($i / 1000),
765
        ) + $settings_form;
766
      }
767
    }
768
    $i++;
769
  }
770

    
771
  $form['actions'] = array('#type' => 'actions');
772
  $form['actions']['submit'] = array(
773
    '#type' => 'submit',
774
    '#value' => t('Save configuration'),
775
  );
776

    
777
  return $form;
778
}
779

    
780
/**
781
 * Process file display settings form submissions.
782
 */
783
function file_entity_file_display_form_submit($form, &$form_state) {
784
  $file_type = $form['#file_type'];
785
  $view_mode = $form['#view_mode'];
786
  $displays = isset($form_state['values']['displays']) ? $form_state['values']['displays'] : array();
787
  $displays_original = file_displays_load($file_type, $view_mode, TRUE);
788
  foreach ($displays as $formatter_name => $display) {
789
    $display_original = isset($displays_original[$formatter_name]) ? $displays_original[$formatter_name] : file_display_new($file_type, $view_mode, $formatter_name);
790
    $display += (array) $display_original;
791
    file_display_save((object) $display);
792
  }
793
  drupal_set_message(t('Your settings have been saved.'));
794
}
795

    
796
/**
797
 * Returns HTML for the file type overview page.
798
 *
799
 * Specifically, this returns HTML for a file type label and description.
800
 */
801
function theme_file_entity_file_type_overview($variables) {
802
  return check_plain($variables['label']) . '<div class="description">' . $variables['description'] . '</div>';
803
}
804

    
805
/**
806
 * Returns HTML for a file display's display order table.
807
 */
808
function theme_file_entity_file_display_order($variables) {
809
  $element = $variables['element'];
810

    
811
  $rows = array();
812
  foreach (element_children($element, TRUE) as $name) {
813
    $element[$name]['weight']['#attributes']['class'][] = 'file-display-order-weight';
814
    $rows[] = array(
815
      'data' => array(
816
        drupal_render($element[$name]['label']),
817
        drupal_render($element[$name]['weight']),
818
      ),
819
      'class' => array('draggable'),
820
    );
821
  }
822
  $output = drupal_render_children($element);
823
  $output .= theme('table', array('rows' => $rows, 'attributes' => array('id' => 'file-displays-order')));
824
  drupal_add_tabledrag('file-displays-order', 'order', 'sibling', 'file-display-order-weight', NULL, NULL, TRUE);
825

    
826
  return $output;
827
}
828

    
829
/**
830
 * Form constructor for the file type settings form.
831
 *
832
 * @param object $type
833
 *   The file type.
834
 *
835
 * @see file_entity_file_type_form_validate()
836
 * @see file_entity_file_type_form_submit()
837
 */
838
function file_entity_file_type_form($form, &$form_state, $type = NULL) {
839
  if (!isset($type->type)) {
840
    // This is a new type.
841
    $type = (object) array(
842
      'type' => '',
843
      'label' => '',
844
      'description' => '',
845
      'mimetypes' => array(),
846
    );
847
  }
848
  $form['#file_type'] = $type;
849

    
850
  $form['label'] = array(
851
    '#type' => 'textfield',
852
    '#title' => t('Name'),
853
    '#description' => t('This is the human readable name of the file type.'),
854
    '#required' => TRUE,
855
    '#default_value' => $type->label,
856
  );
857

    
858
  $form['type'] = array(
859
    '#type' => 'machine_name',
860
    '#default_value' => $type->type,
861
    '#maxlength' => 255,
862
    '#disabled' => (bool) $type->type,
863
    '#machine_name' => array(
864
      'exists' => 'file_type_load',
865
      'source' => array('label'),
866
    ),
867
    '#description' => t('A unique machine-readable name for this file type. It must only contain lowercase letters, numbers, and underscores.'),
868
  );
869

    
870
  $form['description'] = array(
871
    '#type' => 'textarea',
872
    '#title' => t('Description'),
873
    '#description' => t('This is the description of the file type.'),
874
    '#default_value' => $type->description,
875
  );
876

    
877
  $form['mimetypes'] = array(
878
    '#type' => 'textarea',
879
    '#title' => t('Mimetypes'),
880
    '#description' => t('Enter one mimetype per line.'),
881
    '#default_value' => implode("\n", $type->mimetypes),
882
  );
883

    
884
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
885
  $mimetypes = file_mimetype_mapping();
886

    
887
  $form['mimetype_mapping'] = array(
888
    '#type' => 'fieldset',
889
    '#title' => t('Mimetype List'),
890
    '#collapsible' => TRUE,
891
    '#collapsed' => TRUE,
892
  );
893
  $form['mimetype_mapping']['mapping'] = array(
894
    '#theme' => 'item_list',
895
    '#items' => $mimetypes['mimetypes'],
896
  );
897

    
898
  $form['actions'] = array('#type' => 'actions');
899

    
900
  $form['actions']['submit'] = array(
901
    '#type' => 'submit',
902
    '#value' => t('Save'),
903
  );
904
  if (!empty($type->type)) {
905
    $form['actions']['delete'] = array(
906
      '#type' => 'submit',
907
      '#value' => t('Delete'),
908
    );
909
  }
910

    
911
  return $form;
912
}
913

    
914
/**
915
 * Form validation handler for file_entity_file_type_form().
916
 *
917
 * @see file_entity_file_type_form_submit()
918
 */
919
function file_entity_file_type_form_validate($form, &$form_state) {
920
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
921
  $mimetype_mapping = file_mimetype_mapping();
922

    
923
  $valid_mimetypes = $mimetype_mapping['mimetypes'];
924
  $submitted_mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
925

    
926
  $invalid_mimetypes = array();
927
  foreach ($submitted_mimetypes as $mimetype) {
928
    if (!file_entity_match_mimetypes($mimetype, $valid_mimetypes)) {
929
      $invalid_mimetypes[] = $mimetype;
930
    }
931
  }
932

    
933
  foreach ($invalid_mimetypes as $mimetype) {
934
    form_set_error('mimetypes', t('The mimetype %mimetype is not a valid mimetype.', array('%mimetype' => $mimetype)));
935
  }
936
}
937

    
938
/**
939
 * Form submission handler for file_entity_file_type_form().
940
 *
941
 * @see file_entity_file_type_form_validate()
942
 */
943
function file_entity_file_type_form_submit($form, &$form_state) {
944
  if (!empty($form['#file_type']->type)) {
945
    $type = file_type_load($form['#file_type']->type);
946
  }
947
  else {
948
    $type = (object) array(
949
      'type' => $form_state['values']['type'],
950
    );
951
  }
952
  if ($form_state['values']['op'] == t('Delete')) {
953
    $form_state['redirect'] = 'admin/structure/file-types/manage/' . $type->type . '/delete';
954
    return;
955
  }
956
  $type->label = $form_state['values']['label'];
957
  $type->description = $form_state['values']['description'];
958
  $type->mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
959

    
960
  file_type_save($type);
961

    
962
  drupal_set_message(t('The file type %type has been updated.', array('%type' => $type->label)));
963
  $form_state['redirect'] = 'admin/structure/file-types';
964
}
965

    
966
/**
967
 * Menu callback; disable a single file type.
968
 */
969
function file_entity_type_enable_confirm($form, &$form_state, $type) {
970
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
971
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
972
  $message = t('Are you sure you want to enable the file type %type?', array('%type' => $type->label));
973
  return confirm_form($form, $message, 'admin/structure/file-types', '', t('Enable'));
974
}
975

    
976
/**
977
 * Process file type disable confirm submissions.
978
 */
979
function file_entity_type_enable_confirm_submit($form, &$form_state) {
980
  file_type_enable($form_state['values']['type']);
981
  $t_args = array('%label' => $form_state['values']['label']);
982
  drupal_set_message(t('The file type %label has been enabled.', $t_args));
983
  watchdog('file_entity', 'Enabled file type %label.', $t_args, WATCHDOG_NOTICE);
984
  $form_state['redirect'] = 'admin/structure/file-types';
985
}
986

    
987
/**
988
 * Menu callback; disable a single file type.
989
 */
990
function file_entity_type_disable_confirm($form, &$form_state, $type) {
991
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
992
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
993

    
994
  $message = t('Are you sure you want to disable the file type %type?', array('%type' => $type->label));
995
  $caption = '';
996

    
997
  $num_files = db_query("SELECT COUNT(*) FROM {file_managed} WHERE type = :type", array(':type' => $type->type))->fetchField();
998
  if ($num_files) {
999
    $caption .= '<p>' . format_plural($num_files, '%type is used by 1 file on
1000
      your site. If you disable this file type, you will not be able to edit
1001
      the %type file and it may not display correctly.', '%type is used by
1002
      @count files on your site. If you remove %type, you will not be able to
1003
      edit the %type file and it may not display correctly.',
1004
    array('%type' => $type->label)) . '</p>';
1005
  }
1006

    
1007
  return confirm_form($form, $message, 'admin/structure/file-types', $caption, t('Disable'));
1008
}
1009

    
1010

    
1011
/**
1012
 * Process file type disable confirm submissions.
1013
 */
1014
function file_entity_type_disable_confirm_submit($form, &$form_state) {
1015
  file_type_disable($form_state['values']['type']);
1016
  $t_args = array('%label' => $form_state['values']['label']);
1017
  drupal_set_message(t('The file type %label has been disabled.', $t_args));
1018
  watchdog('file_entity', 'Disabled file type %label.', $t_args, WATCHDOG_NOTICE);
1019
  $form_state['redirect'] = 'admin/structure/file-types';
1020
}
1021

    
1022
/**
1023
 * Menu callback; revert a single file type.
1024
 */
1025
function file_entity_type_revert_confirm($form, &$form_state, $type) {
1026
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
1027
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
1028
  $message = t('Are you sure you want to revert the file type %type?', array('%type' => $type->label));
1029
  return confirm_form($form, $message, 'admin/structure/file-types', '', t('Revert'));
1030
}
1031

    
1032
/**
1033
 * Process file type delete confirm submissions.
1034
 */
1035
function file_entity_type_revert_confirm_submit($form, &$form_state) {
1036
  // @NOTE deleting the file_type from the DB actually reverts it to code.
1037
  file_type_delete($form_state['values']['type']);
1038
  $t_args = array('%label' => $form_state['values']['label']);
1039
  drupal_set_message(t('The file type %label has been reverted.', $t_args));
1040
  watchdog('file_entity', 'Reverted file type %label.', $t_args, WATCHDOG_NOTICE);
1041
  $form_state['redirect'] = 'admin/structure/file-types';
1042
}
1043

    
1044
/**
1045
 * Menu callback; delete a single file type.
1046
 */
1047
function file_entity_type_delete_confirm($form, &$form_state, $type) {
1048
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
1049
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
1050

    
1051
  $message = t('Are you sure you want to delete the file type %type?', array('%type' => $type->label));
1052
  $caption = '';
1053

    
1054
  $num_files = db_query("SELECT COUNT(*) FROM {file_managed} WHERE type = :type", array(':type' => $type->type))->fetchField();
1055
  if ($num_files) {
1056
    $caption .= '<p>' . format_plural($num_files, '%type is used by 1 file on your site. If you remove this file type, you will not be able to edit the %type file and it may not display correctly.', '%type is used by @count pieces of file on your site. If you remove %type, you will not be able to edit the %type file and it may not display correctly.', array('%type' => $type->label)) . '</p>';
1057
  }
1058

    
1059
  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
1060

    
1061
  return confirm_form($form, $message, 'admin/structure/file-types', $caption, t('Delete'));
1062
}
1063

    
1064
/**
1065
 * Process file type delete confirm submissions.
1066
 */
1067
function file_entity_type_delete_confirm_submit($form, &$form_state) {
1068
  file_type_delete($form_state['values']['type']);
1069

    
1070
  $t_args = array('%label' => $form_state['values']['label']);
1071
  drupal_set_message(t('The file type %label has been deleted.', $t_args));
1072
  watchdog('file_entity', 'Deleted file type %label.', $t_args, WATCHDOG_NOTICE);
1073

    
1074
  $form_state['redirect'] = 'admin/structure/file-types';
1075
}
1076

    
1077
/**
1078
 * Form callback for file_entity settings.
1079
 */
1080
function file_entity_settings_form($form, &$form_state) {
1081
  $form['file_entity_max_filesize'] = array(
1082
    '#type' => 'textfield',
1083
    '#title' => t('Maximum upload size'),
1084
    '#default_value' => variable_get('file_entity_max_filesize', ''),
1085
    '#description' => t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current max limit <strong>%limit</strong>).', array('%limit' => format_size(file_upload_max_size()))),
1086
    '#size' => 10,
1087
    '#element_validate' => array('_file_generic_settings_max_filesize'),
1088
  );
1089

    
1090
  $form['file_entity_default_file_directory'] = array(
1091
    '#type' => 'textfield',
1092
    '#title' => t('Default file directory'),
1093
    '#default_value' => variable_get('file_entity_default_file_directory', ''),
1094
    '#maxlength' => NULL,
1095
  );
1096
  if (module_exists('token')) {
1097
    $form['file_entity_default_file_directory']['#description'] = t('Optional subdirectory within the upload destination where files will be stored if the file is uploaded through the file entity overview page and the directory is not specified otherwise. Do not include preceding or trailing slashes. This field supports tokens.  Suggest using: [current-date:custom:Y]/[current-date:custom:m]/[current-date:custom:d]');
1098
    $form['file_entity_default_file_directory']['tokens'] = array(
1099
      '#theme' => 'token_tree',
1100
      '#dialog' => TRUE,
1101
    );
1102
  }
1103
  else {
1104
    $form['file_entity_default_file_directory']['#description'] = t('Optional subdirectory within the upload destination where files will be stored if the file is uploaded through the file entity overview page and the directory is not specified otherwise. Do not include preceding or trailing slashes.');
1105
  }
1106

    
1107
  $form['file_entity_default_allowed_extensions'] = array(
1108
    '#type' => 'textfield',
1109
    '#title' => t('Default allowed file extensions'),
1110
    '#default_value' => variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp mp3 mov mp4 m4a m4v mpeg avi ogg oga ogv weba webp webm'),
1111
    '#description' => t('Separate extensions with a space and do not include the leading dot.'),
1112
    '#maxlength' => NULL,
1113
  );
1114

    
1115
  $form['file_entity_alt'] = array(
1116
    '#type' => 'textfield',
1117
    '#title' => t('Alt attribute'),
1118
    '#description' => t('The text to use as value for the <em>img</em> tag <em>alt</em> attribute.'),
1119
    '#default_value' => variable_get('file_entity_alt', '[file:field_file_image_alt_text]'),
1120
  );
1121
  $form['file_entity_title'] = array(
1122
    '#type' => 'textfield',
1123
    '#title' => t('Title attribute'),
1124
    '#description' => t('The text to use as value for the <em>img</em> tag <em>title</em> attribute.'),
1125
    '#default_value' => variable_get('file_entity_title', '[file:field_file_image_title_text]'),
1126
  );
1127

    
1128
  // Provide default token values.
1129
  if (module_exists('token')) {
1130
    $form['token_help'] = array(
1131
      '#theme' => 'token_tree',
1132
      '#token_types' => array('file'),
1133
      '#dialog' => TRUE,
1134
    );
1135
    $form['file_entity_alt']['#description'] .= t('This field supports tokens.');
1136
    $form['file_entity_title']['#description'] .= t('This field supports tokens.');
1137
  }
1138
  $form['file_upload_wizard'] = array(
1139
    '#type' => 'fieldset',
1140
    '#title' => t('File upload wizard'),
1141
    '#collapsible' => TRUE,
1142
    '#collapsed' => FALSE,
1143
    '#description' => t('Configure the steps available when uploading a new file.'),
1144
  );
1145
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_file_type'] = array(
1146
    '#type' => 'checkbox',
1147
    '#title' => t('Skip filetype selection.'),
1148
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_file_type', FALSE),
1149
    '#description' => t('The file type selection step is only available if the uploaded file falls into two or more file types. If this step is skipped, files with no available file type or two or more file types will not be assigned a file type.'),
1150
  );
1151
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_scheme'] = array(
1152
    '#type' => 'checkbox',
1153
    '#title' => t('Skip scheme selection.'),
1154
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_scheme', FALSE),
1155
    '#description' => t('The scheme selection step is only available if two or more file destinations, such as public local files served by the webserver and private local files served by Drupal, are available. If this step is skipped, files will automatically be saved using the default download method.'),
1156
  );
1157
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_fields'] = array(
1158
    '#type' => 'checkbox',
1159
    '#title' => t('Skip available fields.'),
1160
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_fields', FALSE),
1161
    '#description' => t('The field selection step is only available if the file type the file belongs to has any available fields. If this step is skipped, any fields on the file will be left blank.'),
1162
  );
1163
  $form['file_replace_options'] = array(
1164
    '#type' => 'fieldset',
1165
    '#title' => t('File replace optons'),
1166
    '#collapsible' => TRUE,
1167
    '#collapsed' => FALSE,
1168
    '#description' => t('Default settings for how to handle file name changes during replace.'),
1169
  );
1170
  $form['file_replace_options']['file_entity_file_replace_options_keep_original_filename'] = array(
1171
    '#type' => 'checkbox',
1172
    '#title' => t('Keep original file name'),
1173
    '#default_value' => variable_get('file_entity_file_replace_options_keep_original_filename', FALSE),
1174
    '#description' => t('Rename the newly uploaded file to the name of the original file. This action cannot be undone.'),
1175
  );
1176

    
1177
  return system_settings_form($form);
1178
}