Projet

Général

Profil

Paste
Télécharger (24,9 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / file_entity / file_entity.file_api.inc @ a8cee257

1
<?php
2

    
3
/**
4
 * @file
5
 * API extensions of Drupal core's file.inc.
6
 */
7

    
8
/**
9
 * The {file_managed}.type value when the file type has not yet been determined.
10
 */
11
define('FILE_TYPE_NONE', 'undefined');
12

    
13
/**
14
 * Returns information about file formatters from hook_file_formatter_info().
15
 *
16
 * @param string $formatter_type
17
 *   (optional) A file formatter type name. If omitted, all file formatter
18
 *   will be returned.
19
 *
20
 * @return string|array
21
 *   Either a file formatter description, as provided by
22
 *   hook_file_formatter_info(), or an array of all existing file formatters,
23
 *   keyed by formatter type name.
24
 */
25
function file_info_formatter_types($formatter_type = NULL) {
26
  $info = &drupal_static(__FUNCTION__);
27
  if (!isset($info)) {
28
    $info = module_invoke_all('file_formatter_info');
29
    drupal_alter('file_formatter_info', $info);
30
    uasort($info, '_file_entity_sort_weight_label');
31
  }
32
  if ($formatter_type) {
33
    if (isset($info[$formatter_type])) {
34
      return $info[$formatter_type];
35
    }
36
  }
37
  else {
38
    return $info;
39
  }
40
}
41

    
42
/**
43
 * Clears caches that are related to file entity.
44
 *
45
 * Clears all cached configuration related to file types, formatters, and
46
 * display settings.
47
 */
48
function file_info_cache_clear() {
49
  // Clear the CTools managed caches.
50
  ctools_include('export');
51
  ctools_export_load_object_reset('file_type');
52
  ctools_export_load_object_reset('file_display');
53

    
54
  // Clear the formatter type cache, managed by file_info_formatter_types().
55
  drupal_static_reset('file_info_formatter_types');
56

    
57
  // Clear file type caches.
58
  drupal_static_reset('file_type_get_names');
59
}
60

    
61
/**
62
 * Construct a drupal_render() style array from an array of loaded files.
63
 *
64
 * @param array $files
65
 *   An array of files as returned by file_load_multiple().
66
 * @param string $view_mode
67
 *   View mode.
68
 * @param int $weight
69
 *   An integer representing the weight of the first file in the list.
70
 * @param string $langcode
71
 *   A string indicating the language field values are to be shown in. If no
72
 *   language is provided the current content language is used.
73
 *
74
 * @return array
75
 *   An array in the format expected by drupal_render().
76
 */
77
function file_view_multiple($files, $view_mode = 'full', $weight = 0, $langcode = NULL) {
78
  $build = array();
79

    
80
  if (empty($files)) {
81
    return $build;
82
  }
83

    
84
  $entities_by_view_mode = entity_view_mode_prepare('file', $files, $view_mode, $langcode);
85
  foreach ($entities_by_view_mode as $entity_view_mode => $entities) {
86
    field_attach_prepare_view('file', $entities, $entity_view_mode, $langcode);
87
    entity_prepare_view('file', $entities, $langcode);
88

    
89
    foreach ($entities as $entity) {
90
      $build['files'][$entity->fid] = file_view($entity, $entity_view_mode, $langcode);
91
    }
92
  }
93

    
94
  foreach ($files as $file) {
95
    $build['files'][$file->fid]['#weight'] = $weight;
96
    $weight++;
97
  }
98
  // Sort here, to preserve the input order of the entities that were passed to
99
  // this function.
100
  uasort($build['files'], 'element_sort');
101
  $build['files']['#sorted'] = TRUE;
102

    
103
  return $build;
104
}
105

    
106
/**
107
 * Generate an array for rendering the given file.
108
 *
109
 * @param object $file
110
 *   A file object.
111
 * @param string $view_mode
112
 *   View mode.
113
 * @param string $langcode
114
 *   (optional) A language code to use for rendering. Defaults to the global
115
 *   content language of the current request.
116
 *
117
 * @return array
118
 *   An array as expected by drupal_render().
119
 */
120
function file_view($file, $view_mode = 'full', $langcode = NULL) {
121
  if (!isset($langcode)) {
122
    $langcode = $GLOBALS['language_content']->language;
123
  }
124

    
125
  // Populate $file->content with a render() array.
126
  file_build_content($file, $view_mode, $langcode);
127

    
128
  $build = $file->content;
129
  // We don't need duplicate rendering info in $file->content.
130
  unset($file->content);
131

    
132
  $build += array(
133
    '#theme' => 'file_entity',
134
    '#file' => $file,
135
    '#view_mode' => $view_mode,
136
    '#language' => $langcode,
137
  );
138

    
139
  // Add contextual links for this file, except when the file is already being
140
  // displayed on its own page. Modules may alter this behavior (for example,
141
  // to restrict contextual links to certain view modes) by implementing
142
  // hook_file_view_alter().
143
  if (!empty($file->fid) && !($view_mode == 'full' && file_entity_is_page($file))) {
144
    $build['#contextual_links']['file'] = array('file', array($file->fid));
145
  }
146

    
147
  // Allow modules to modify the structured file.
148
  $type = 'file';
149
  drupal_alter(array('file_view', 'entity_view'), $build, $type);
150

    
151
  return $build;
152
}
153

    
154
/**
155
 * Builds a structured array representing the file's content.
156
 *
157
 * @param object $file
158
 *   A file object.
159
 * @param string $view_mode
160
 *   View mode, e.g. 'default', 'full', etc.
161
 * @param string $langcode
162
 *   (optional) A language code to use for rendering. Defaults to the global
163
 *   content language of the current request.
164
 */
165
function file_build_content($file, $view_mode = 'full', $langcode = NULL) {
166
  if (!isset($langcode)) {
167
    $langcode = $GLOBALS['language_content']->language;
168
  }
169

    
170
  // Remove previously built content, if exists.
171
  $file->content = array();
172

    
173
  // In case of a multiple view, file_view_multiple() already ran the
174
  // 'prepare_view' step. An internal flag prevents the operation from running
175
  // twice.
176
  // Allow modules to change the view mode.
177
  $view_mode = key(entity_view_mode_prepare('file', array($file->fid => $file), $view_mode, $langcode));
178
  field_attach_prepare_view('file', array($file->fid => $file), $view_mode, $langcode);
179
  entity_prepare_view('file', array($file->fid => $file), $langcode);
180

    
181
  // Build the actual file display.
182
  // @todo Figure out how to clean this crap up.
183
  $file->content['file'] = file_view_file($file, $view_mode, $langcode);
184
  if (isset($file->content['file'])) {
185
    if (isset($file->content['file']['#theme']) && $file->content['file']['#theme'] != 'file_link') {
186
      unset($file->content['file']['#file']);
187
    }
188
    unset($file->content['file']['#view_mode']);
189
    unset($file->content['file']['#language']);
190
  }
191
  else {
192
    unset($file->content['file']);
193
  }
194

    
195
  // Build fields content.
196
  $file->content += field_attach_view('file', $file, $view_mode, $langcode);
197

    
198
  $links = array();
199
  $file->content['links'] = array(
200
    '#theme' => 'links__file',
201
    '#pre_render' => array('drupal_pre_render_links'),
202
    '#attributes' => array('class' => array('links', 'inline')),
203
  );
204
  $file->content['links']['file'] = array(
205
    '#theme' => 'links__file__file',
206
    '#links' => $links,
207
    '#attributes' => array('class' => array('links', 'inline')),
208
  );
209

    
210
  // Allow modules to make their own additions to the file.
211
  module_invoke_all('file_view', $file, $view_mode, $langcode);
212
  module_invoke_all('entity_view', $file, 'file', $view_mode, $langcode);
213
}
214

    
215
/**
216
 * Generate an array for rendering just the file portion of a file entity.
217
 *
218
 * @param object $file
219
 *   A file object.
220
 * @param string|array $displays
221
 *   Can be either:
222
 *   - the name of a view mode;
223
 *   - or an array of custom display settings, as returned by file_displays().
224
 * @param string $langcode
225
 *   (optional) A language code to use for rendering. Defaults to the global
226
 *   content language of the current request.
227
 *
228
 * @return array
229
 *   An array as expected by drupal_render().
230
 */
231
function file_view_file($file, $displays = 'full', $langcode = NULL) {
232
  if (!isset($langcode)) {
233
    $langcode = $GLOBALS['language_content']->language;
234
  }
235

    
236
  // Prepare incoming display specifications.
237
  if (is_string($displays)) {
238
    // Allow modules to change the view mode.
239
    $view_mode = key(entity_view_mode_prepare('file', array($file->fid => $file), $displays, $langcode));
240
    $displays = file_displays($file->type, $view_mode);
241
  }
242
  else {
243
    $view_mode = '_custom_display';
244
  }
245
  drupal_alter('file_displays', $displays, $file, $view_mode);
246
  _file_sort_array_by_weight($displays);
247

    
248
  // Since $file->alt and $file->title were set in file_entity_file_load()
249
  // (which is a language-agnostic hook) they will not be in the correct
250
  // language if the file is being displayed in a language other than the
251
  // default one. Set them again here, using the correct language. This must
252
  // run after hook_file_displays_alter() since the Media module sets
253
  // $file->alt and $file->title again during that hook.
254
  if ($langcode != $GLOBALS['language_content']->language) {
255
    $languages = language_list();
256
    if (isset($languages[$langcode])) {
257
      if (!function_exists('file_entity_set_title_alt_properties')) {
258
        module_load_include('file.inc', 'file_entity');
259
      }
260
      file_entity_set_title_alt_properties(array($file), $languages[$langcode]);
261
    }
262
  }
263

    
264
  // Attempt to display the file with each of the possible displays. Stop after
265
  // the first successful one. See file_displays() for details.
266
  $element = NULL;
267
  foreach ($displays as $formatter_type => $display) {
268
    if (!empty($display['status'])) {
269
      $formatter_info = file_info_formatter_types($formatter_type);
270
      // Under normal circumstances, the UI prevents enabling formatters for
271
      // incompatible MIME types. In case this was somehow circumvented (for
272
      // example, a module updated its formatter definition without updating
273
      // existing display settings), perform an extra check here.
274
      if (isset($formatter_info['mime types'])) {
275
        if (!file_entity_match_mimetypes($formatter_info['mime types'], $file->filemime)) {
276
          continue;
277
        }
278
      }
279
      if (isset($formatter_info['view callback']) && ($function = $formatter_info['view callback']) && function_exists($function)) {
280
        $display['type'] = $formatter_type;
281
        if (!empty($formatter_info['default settings'])) {
282
          if (empty($display['settings'])) {
283
            $display['settings'] = array();
284
          }
285
          $display['settings'] += $formatter_info['default settings'];
286
        }
287
        $element = $function($file, $display, $langcode);
288
        if (isset($element)) {
289
          break;
290
        }
291
      }
292
    }
293
  }
294

    
295
  // As a last resort, fall back to showing a link to the file.
296
  if (!isset($element)) {
297
    $element = array(
298
      '#theme' => 'file_link',
299
      '#file' => $file,
300
    );
301
  }
302

    
303
  // Add defaults and return the element.
304
  $element += array(
305
    '#file' => $file,
306
    '#view_mode' => $view_mode,
307
    '#language' => $langcode,
308
  );
309

    
310
  return $element;
311
}
312

    
313
/**
314
 * @defgroup file_displays File displays API
315
 * @{
316
 * Functions to load and save information about file displays.
317
 */
318

    
319
/**
320
 * Returns an array of displays to use for a file type in a given view mode.
321
 *
322
 * It is common for a site to be configured with broadly defined file types
323
 * (e.g., 'video'), and to have different files of this type require different
324
 * displays (for example, the code required to display a YouTube video is
325
 * different than the code required to display a local QuickTime video).
326
 * Therefore, the site administrator can configure multiple displays for a given
327
 * file type. This function returns all of the displays that the administrator
328
 * enabled for the given file type in the given view mode. file_view_file() then
329
 * invokes each of these, and passes the specific file to display. Each display
330
 * implementation can inspect the file, and either return a render array (if it
331
 * is capable of displaying the file), or return nothing (if it is incapable of
332
 * displaying the file). The first render array returned is the one used.
333
 *
334
 * @param string $file_type
335
 *   The type of file.
336
 * @param string $view_mode
337
 *   The view mode.
338
 *
339
 * @return array
340
 *   An array keyed by the formatter type name. Each item in the array contains
341
 *   the following key/value pairs:
342
 *   - status: Whether this display is enabled. If not TRUE, file_view_file()
343
 *     skips over it.
344
 *   - weight: An integer that determines the order of precedence within the
345
 *     returned array. The lowest weight display capable of displaying the file
346
 *     is used.
347
 *   - settings: An array of key/value pairs specific to the formatter type. See
348
 *     hook_file_formatter_info() for details.
349
 *
350
 * @see hook_file_formatter_info()
351
 * @see file_view_file()
352
 */
353
function file_displays($file_type, $view_mode) {
354
  $cache = &drupal_static(__FUNCTION__, array());
355

    
356
  // If the requested view mode isn't configured to use a custom display for its
357
  // fields, then don't use a custom display for its file either.
358
  if ($view_mode != 'default') {
359
    $view_mode_settings = field_view_mode_settings('file', $file_type);
360
    $view_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default';
361
  }
362

    
363
  if (!isset($cache[$file_type][$view_mode])) {
364
    // Load the display configurations for the file type and view mode. If none
365
    // exist for the view mode, use the default view mode.
366
    $displays = file_displays_load($file_type, $view_mode, TRUE);
367
    if (empty($displays) && $view_mode != 'default') {
368
      $cache[$file_type][$view_mode] = file_displays($file_type, 'default');
369
    }
370
    else {
371
      // Convert the display objects to arrays and remove unnecessary keys.
372
      foreach ($displays as $formatter_name => $display) {
373
        $displays[$formatter_name] = array_intersect_key((array) $display, drupal_map_assoc(array('status', 'weight', 'settings')));
374
      }
375
      $cache[$file_type][$view_mode] = $displays;
376
    }
377
  }
378

    
379
  return $cache[$file_type][$view_mode];
380
}
381

    
382
/**
383
 * Returns an array of {file_display} objects for the file type and view mode.
384
 */
385
function file_displays_load($file_type, $view_mode, $key_by_formatter_name = FALSE) {
386
  ctools_include('export');
387

    
388
  $display_names = array();
389
  $prefix = $file_type . '__' . $view_mode . '__';
390
  foreach (array_keys(file_info_formatter_types()) as $formatter_name) {
391
    $display_names[] = $prefix . $formatter_name;
392
  }
393
  $displays = ctools_export_load_object('file_display', 'names', $display_names);
394

    
395
  if ($key_by_formatter_name) {
396
    $prefix_length = strlen($prefix);
397
    $rekeyed_displays = array();
398
    foreach ($displays as $name => $display) {
399
      $rekeyed_displays[substr($name, $prefix_length)] = $display;
400
    }
401
    $displays = $rekeyed_displays;
402
  }
403

    
404
  return $displays;
405
}
406

    
407
/**
408
 * Saves a {file_display} object to the database.
409
 */
410
function file_display_save($display) {
411
  ctools_include('export');
412
  ctools_export_crud_save('file_display', $display);
413
  file_info_cache_clear();
414
}
415

    
416
/**
417
 * Creates a new {file_display} object.
418
 */
419
function file_display_new($file_type, $view_mode, $formatter_name) {
420
  ctools_include('export');
421
  $display = ctools_export_crud_new('file_display');
422
  file_info_cache_clear();
423
  $display->name = implode('__', array($file_type, $view_mode, $formatter_name));
424
  return $display;
425
}
426

    
427
/**
428
 * @} End of "defgroup file_displays".
429
 */
430

    
431
/**
432
 * @defgroup file_types File types API
433
 * @{
434
 * Functions to load and save information about file types.
435
 */
436

    
437
/**
438
 * Load a file type configuration object.
439
 *
440
 * @param string $name
441
 *   The file type machine name to load.
442
 *
443
 * @return object
444
 *   The file type object, or FALSE if it does not exist.
445
 */
446
function file_type_load($name) {
447
  ctools_include('export');
448
  $type = ctools_export_crud_load('file_type', $name);
449
  return isset($type) ? $type : FALSE;
450
}
451

    
452
/**
453
 * Load multiple file type configuration objects.
454
 *
455
 * @param array $names
456
 *   An array of file type machine names to load.
457
 *
458
 * @return array
459
 *   An array of file type objects, keyed by machine name.
460
 */
461
function file_type_load_multiple(array $names) {
462
  ctools_include('export');
463
  return ctools_export_crud_load_multiple('file_type', $names);
464
}
465

    
466
/**
467
 * Load all file type configuration objects.
468
 *
469
 * This includes all enabled and disabled file types.
470
 *
471
 * @param bool $reset
472
 *   If TRUE, the static cache of all file types will be flushed prior to
473
 *   loading. This can be important on listing pages where file types might
474
 *   have changed on the page load.
475
 *
476
 * @return array
477
 *   An array of file type objects, keyed by machine name.
478
 *
479
 * @see file_type_get_enabled_types()
480
 * @see file_type_get_disabled_types()
481
 */
482
function file_type_load_all($reset = FALSE) {
483
  ctools_include('export');
484
  return ctools_export_crud_load_all('file_type', $reset);
485
}
486

    
487
/**
488
 * Returns an array of enabled file types.
489
 */
490
function file_type_get_enabled_types() {
491
  $types = file_type_load_all();
492
  return array_filter($types, 'file_type_is_enabled');
493
}
494

    
495
/**
496
 * Returns an array of disabled file types.
497
 */
498
function file_type_get_disabled_types() {
499
  $types = file_type_load_all();
500
  return array_filter($types, 'file_type_is_disabled');
501
}
502

    
503
/**
504
 * Returns TRUE if a file type is enabled, FALSE otherwise.
505
 */
506
function file_type_is_enabled($type) {
507
  return empty($type->disabled);
508
}
509

    
510
/**
511
 * Returns TRUE if a file type is disabled, FALSE otherwise.
512
 */
513
function file_type_is_disabled($type) {
514
  return !empty($type->disabled);
515
}
516

    
517
/**
518
 * Returns an array of valid file extensions.
519
 */
520
function file_type_get_valid_extensions($type) {
521
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
522
  $mapping = file_mimetype_mapping();
523

    
524
  $type_extensions = array();
525
  $type_ext_keys = array();
526
  if (!empty($type->mimetypes)) {
527
    foreach ($mapping['mimetypes'] as $ext_key => $mimetype) {
528
      if (file_entity_match_mimetypes($mimetype, $type->mimetypes)) {
529
        $type_ext_keys[] = $ext_key;
530
      }
531
    }
532

    
533
    if ($type_ext_keys) {
534
      $type_extensions = array_intersect($mapping['extensions'], $type_ext_keys);
535
      $type_extensions = array_keys($type_extensions);
536
    }
537
  }
538

    
539
  return $type_extensions;
540
}
541

    
542
/**
543
 * Updates an existing file type or creates a new one.
544
 *
545
 * This function can be called on its own, or via the CTools exportables
546
 * 'save callback' for {file_type} objects.
547
 */
548
function file_type_save($type) {
549
  // Get the old type object, so we now can issue the correct insert/update
550
  // queries.
551
  if (!empty($type->old_type) && $type->old_type != $type->type) {
552
    $rename_bundle = TRUE;
553
    $old_type = file_type_load($type->old_type);
554
  }
555
  else {
556
    $rename_bundle = FALSE;
557
    $old_type = file_type_load($type->type);
558
  }
559

    
560
  // The type and label fields are required, but description is optional.
561
  if (!isset($type->description)) {
562
    $type->description = '';
563
  }
564
  $fields = array(
565
    'type' => $type->type,
566
    'label' => $type->label,
567
    'description' => $type->description,
568
    'mimetypes' => serialize($type->mimetypes),
569
  );
570

    
571
  // Update an existing type object, whether with a modified 'type' property or
572
  // not.
573
  if ($old_type) {
574
    if ($old_type->export_type & EXPORT_IN_DATABASE) {
575
      db_update('file_type')
576
        ->fields($fields)
577
        ->condition('type', $old_type->type)
578
        ->execute();
579
    }
580
    else {
581
      db_insert('file_type')
582
        ->fields($fields)
583
        ->execute();
584
    }
585
    if ($rename_bundle) {
586
      field_attach_rename_bundle('file', $old_type->type, $type->type);
587
    }
588
    module_invoke_all('file_type_update', $type);
589
    $status = SAVED_UPDATED;
590
  }
591
  // Insert a new type object.
592
  else {
593
    db_insert('file_type')
594
      ->fields($fields)
595
      ->execute();
596
    field_attach_create_bundle('file', $type->type);
597
    module_invoke_all('file_type_insert', $type);
598
    $status = SAVED_NEW;
599
  }
600

    
601
  // Clear the necessary caches.
602
  file_info_cache_clear();
603

    
604
  // Ensure the type has the correct export_type in case the $type parameter
605
  // continues to be used by the calling function after this function completes.
606
  if (empty($type->export_type)) {
607
    $type->export_type = 0;
608
  }
609
  $type->export_type |= EXPORT_IN_DATABASE;
610

    
611
  return $status;
612
}
613

    
614
/**
615
 * Deletes a file type from the database.
616
 *
617
 * This function can be called on its own, or via the CTools exportables
618
 * 'delete callback' for {file_type} objects.
619
 *
620
 * @param object|string $type
621
 *   Either a loaded file type object or the machine-name of the type.
622
 */
623
function file_type_delete($type) {
624
  $type = is_string($type) ? file_type_load($type) : $type;
625

    
626
  db_delete('file_type')
627
    ->condition('type', $type->type)
628
    ->execute();
629

    
630
  // Remove this type from CToolS status variable.
631
  $status = variable_get('default_file_type', array());
632
  unset($status[$type->type]);
633
  variable_set('default_file_type', $status);
634

    
635
  file_info_cache_clear();
636

    
637
  // After deleting from the database, check if the type still exists as a
638
  // code-provided default type. If not, consider the type fully deleted and
639
  // invoke the needed hooks.
640
  if (!file_type_load($type->type)) {
641
    field_attach_delete_bundle('file', $type->type);
642
    module_invoke_all('file_type_delete', $type);
643
  }
644
}
645

    
646

    
647
/**
648
 * Enable a file type.
649
 *
650
 * @param string $type
651
 *   Type of the file_type to disable
652
 */
653
function file_type_enable($type) {
654
  ctools_include('export');
655
  ctools_export_crud_enable('file_type', $type);
656
}
657

    
658

    
659
/**
660
 * Disable a file type.
661
 *
662
 * @param string $type
663
 *   Type of the file_type to disable
664
 */
665
function file_type_disable($type) {
666
  ctools_include('export');
667
  ctools_export_crud_disable('file_type', $type);
668
}
669

    
670

    
671
/**
672
 * Determines file type for a given file.
673
 *
674
 * @param object $file
675
 *   File object.
676
 *
677
 * @return string
678
 *   Machine name of file type that should be used for given file.
679
 */
680
function file_get_type($file) {
681
  $types = module_invoke_all('file_type', $file);
682
  drupal_alter('file_type', $types, $file);
683

    
684
  return empty($types) ? NULL : reset($types);
685
}
686

    
687
/**
688
 * @} End of "defgroup file_types".
689
 */
690

    
691
/**
692
 * Sorts an array by weight.
693
 *
694
 * Helper function to sort an array by the value of each item's 'weight' key,
695
 * while preserving relative order of items that have equal weight.
696
 */
697
function _file_sort_array_by_weight(&$a) {
698
  $i = 0;
699
  foreach ($a as $key => $item) {
700
    if (!isset($a[$key]['weight'])) {
701
      $a[$key]['weight'] = 0;
702
    }
703
    $original_weight[$key] = $a[$key]['weight'];
704
    $a[$key]['weight'] += $i / 1000;
705
    $i++;
706
  }
707
  uasort($a, 'drupal_sort_weight');
708
  foreach ($a as $key => $item) {
709
    $a[$key]['weight'] = $original_weight[$key];
710
  }
711
}
712

    
713
/**
714
 * User sort function to sort by weight, then label/name.
715
 */
716
function _file_entity_sort_weight_label($a, $b) {
717
  $a_weight = isset($a['weight']) ? $a['weight'] : 0;
718
  $b_weight = isset($b['weight']) ? $b['weight'] : 0;
719
  if ($a_weight == $b_weight) {
720
    $a_label = isset($a['label']) ? $a['label'] : '';
721
    $b_label = isset($b['label']) ? $b['label'] : '';
722
    return strcasecmp($a_label, $b_label);
723
  }
724
  else {
725
    return $a_weight < $b_weight ? -1 : 1;
726
  }
727
}
728

    
729
/**
730
 * Returns a file object which can be passed to file_save().
731
 *
732
 * @param string $uri
733
 *   A string containing the URI, path, or filename.
734
 * @param bool $use_existing
735
 *   (Optional) If TRUE and there's an existing file in the {file_managed}
736
 *   table with the passed in URI, then that file object is returned.
737
 *   Otherwise, a new file object is returned. Default is TRUE.
738
 *
739
 * @return object|bool
740
 *   A file object, or FALSE on error.
741
 *
742
 * @todo This should probably be named
743
 *   file_load_by_uri($uri, $create_if_not_exists).
744
 * @todo Remove this function when http://drupal.org/node/685818 is fixed.
745
 */
746
function file_uri_to_object($uri, $use_existing = TRUE) {
747
  $file = FALSE;
748
  $uri = file_stream_wrapper_uri_normalize($uri);
749

    
750
  if ($use_existing) {
751
    // We should always attempt to re-use a file if possible.
752
    $files = entity_load('file', FALSE, array('uri' => $uri));
753
    $file = !empty($files) ? reset($files) : FALSE;
754
  }
755

    
756
  if (empty($file)) {
757
    $file = new stdClass();
758
    $file->uid = $GLOBALS['user']->uid;
759
    $file->filename = drupal_basename($uri);
760
    $file->uri = $uri;
761
    $file->filemime = file_get_mimetype($uri);
762
    // This is gagged because some uris will not support it.
763
    $file->filesize = @filesize($uri);
764
    $file->timestamp = REQUEST_TIME;
765
    $file->status = FILE_STATUS_PERMANENT;
766
  }
767

    
768
  return $file;
769
}
770

    
771
/**
772
 * Delete multiple files.
773
 *
774
 * Unlike core's file_delete(), this function does not care about file usage
775
 * or skip on invalid URIs. Just deletes the damn file like it should.
776
 *
777
 * @param array $fids
778
 *   An array of file IDs.
779
 */
780
function file_delete_multiple(array $fids) {
781
  $transaction = db_transaction();
782
  if (!empty($fids) && $files = file_load_multiple($fids)) {
783
    try {
784
      foreach ($files as $fid => $file) {
785
        module_invoke_all('file_delete', $file);
786
        module_invoke_all('entity_delete', $file, 'file');
787
        // Skip calling field_attach_delete as file_entity_file_delete()
788
        // does this.
789
        // field_attach_delete('file', $file);
790
        // Remove this file from the search index if needed.
791
        // This code is implemented in file_entity module rather than in search
792
        // module, because node module is implementing search module's API,
793
        // not the other way around.
794
        if (module_exists('search')) {
795
          search_reindex($fid, 'file');
796
        }
797

    
798
        // Make sure the file is deleted before removing its row from the
799
        // database, so UIs can still find the file in the database.
800
        if (file_valid_uri($file->uri)) {
801
          file_unmanaged_delete($file->uri);
802
        }
803
      }
804

    
805
      db_delete('file_managed')
806
        ->condition('fid', $fids, 'IN')
807
        ->execute();
808
      db_delete('file_usage')
809
        ->condition('fid', $fids, 'IN')
810
        ->execute();
811
    }
812
    catch (Exception $e) {
813
      $transaction->rollback();
814
      watchdog_exception('file', $e);
815
      throw $e;
816
    }
817

    
818
    // Clear the page and block and file_load_multiple caches.
819
    entity_get_controller('file')->resetCache();
820
  }
821
}