Newer
Older
Dave Reid
committed
<?php
/**
* @file
* Extends Drupal file entities to be fieldable and viewable.
*/
Paris Liakos
committed
/**
* Modules should return this value from hook_file_entity_access() to allow
* access to a file.
*/
define('FILE_ENTITY_ACCESS_ALLOW', 'allow');
/**
* Modules should return this value from hook_file_entity_access() to deny
* access to a file.
*/
define('FILE_ENTITY_ACCESS_DENY', 'deny');
/**
* Modules should return this value from hook_file_entity_access() to not affect
* file access.
*/
define('FILE_ENTITY_ACCESS_IGNORE', NULL);
Dave Reid
committed
/**
* As part of extending Drupal core's file entity API, this module adds some
* functions to the 'file' namespace. For organization, those are kept in the
* 'file_entity.file_api.inc' file.
*/
require_once dirname(__FILE__) . '/file_entity.file_api.inc';
Dave Reid
committed
// @todo Remove when http://drupal.org/node/977052 is fixed.
require_once dirname(__FILE__) . '/file_entity.field.inc';
Dave Reid
committed
/**
* Implements hook_hook_info().
*/
function file_entity_hook_info() {
$hooks = array(
'file_operation_info',
'file_operation_info_alter',
'file_type_info',
'file_type_info_alter',
'file_formatter_info',
'file_formatter_info_alter',
'file_view',
'file_view_alter',
'file_displays_alter',
Paris Liakos
committed
'file_type',
'file_type_alter',
Dave Reid
committed
);
return array_fill_keys($hooks, array('group' => 'file'));
}
/**
* Implements hook_hook_info_alter().
*
* Add support for existing core hooks to be located in modulename.file.inc.
*/
function file_entity_hook_info_alter(&$info) {
$hooks = array(
// File API hooks
'file_copy',
'file_move',
'file_validate',
// File access
'file_download',
'file_download_access',
'file_download_access_alter',
// File entity hooks
'file_load',
'file_presave',
'file_insert',
'file_update',
'file_delete',
// Miscellanious hooks
'file_mimetype_mapping_alter',
'file_url_alter',
);
$info += array_fill_keys($hooks, array('group' => 'file'));
}
Dave Reid
committed
/**
* Implements hook_help().
*/
function file_entity_help($path, $arg) {
switch ($path) {
Thomas Svenson
committed
case 'admin/structure/file-types':
Dave Reid
committed
$output = '<p>' . t('When a file is uploaded to this website, it is assigned one of the following types, based on what kind of file it is.') . '</p>';
return $output;
case 'admin/structure/file-types/manage/%/display/preview':
case 'admin/structure/file-types/manage/%/file-display/preview':
drupal_set_message(t('Some modules rely on the Preview view mode to function correctly. Changing these settings may break parts of your site.'), 'warning');
break;
Dave Reid
committed
}
}
/**
* Implements hook_menu().
*/
function file_entity_menu() {
Robin Barre
committed
// File Configuration
Dave Reid
committed
// @todo Move this back to admin/config/media/file-types in Drupal 8 if
// MENU_MAX_DEPTH is increased to a value higher than 9.
Thomas Svenson
committed
$items['admin/structure/file-types'] = array(
Dave Reid
committed
'title' => 'File types',
Jacob Singh
committed
'description' => 'Manage settings for the type of files used on your site.',
Dave Reid
committed
'page callback' => 'file_entity_list_types_page',
Paris Liakos
committed
'access arguments' => array('administer file types'),
Dave Reid
committed
'file' => 'file_entity.admin.inc',
);
Paris Liakos
committed
$items['admin/structure/file-types/manage/%file_type'] = array(
Dave Reid
committed
'title' => 'Manage file types',
Jacob Singh
committed
'description' => 'Manage settings for the type of files used on your site.',
);
$items['admin/content/file'] = array(
'title' => 'Files',
Dave Reid
committed
'description' => 'Manage files used on your site.',
Jacob Singh
committed
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_admin_file'),
Jacob Singh
committed
'access arguments' => array('administer files'),
'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
'file' => 'file_entity.admin.inc',
);
$items['admin/content/file/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
Dave Reid
committed
);
Robin Barre
committed
// general view, edit, delete for files
Dave Reid
committed
$items['file/add'] = array(
'title' => 'Add file',
'page callback' => 'drupal_get_form',
Dylan Tack
committed
'page arguments' => array('file_entity_add_upload', array()),
Paris Liakos
committed
'access callback' => 'file_entity_access',
'access arguments' => array('create'),
Dave Reid
committed
'file' => 'file_entity.pages.inc',
);
if (module_exists('plupload') && module_exists('multiform')) {
$items['file/add']['page arguments'] = array('file_entity_add_upload_multiple');
}
$items['file/add/upload'] = array(
'title' => 'Upload',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
Robin Barre
committed
$items['file/%file'] = array(
'title callback' => 'entity_label',
'title arguments' => array('file', 1),
// The page callback also invokes drupal_set_title() in case
// the menu router's title is overridden by a menu link.
Robin Barre
committed
'page callback' => 'file_entity_view_page',
'page arguments' => array(1),
'access callback' => 'file_entity_access',
Paris Liakos
committed
'access arguments' => array('view', 1),
Robin Barre
committed
'file' => 'file_entity.pages.inc',
);
$items['file/%file/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
Paris Liakos
committed
$items['file/%file/usage'] = array(
'title' => 'Usage',
'page callback' => 'file_entity_usage_page',
'page arguments' => array(1),
'access callback' => 'file_entity_access',
'access arguments' => array('update', 1),
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE,
'file' => 'file_entity.pages.inc',
);
Devin Carlson
committed
$items['file/%file/download'] = array(
'title' => 'Download',
'page callback' => 'file_entity_download_page',
'page arguments' => array(1),
'access callback' => 'file_entity_access',
'access arguments' => array('download', 1),
'file' => 'file_entity.pages.inc',
'type' => MENU_CALLBACK,
);
Robin Barre
committed
$items['file/%file/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_edit', 1),
Robin Barre
committed
'access callback' => 'file_entity_access',
Paris Liakos
committed
'access arguments' => array('update', 1),
Robin Barre
committed
'weight' => 0,
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'file_entity.pages.inc',
);
$items['file/%file/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_delete_form', 1),
Robin Barre
committed
'access callback' => 'file_entity_access',
Paris Liakos
committed
'access arguments' => array('delete', 1),
Robin Barre
committed
'weight' => 1,
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'file_entity.pages.inc',
);
Dave Reid
committed
// Attach a "Manage file display" tab to each file type in the same way that
// Field UI attaches "Manage fields" and "Manage display" tabs. Note that
// Field UI does not have to be enabled; we're just using the same IA pattern
// here for attaching the "Manage file display" page.
$entity_info = entity_get_info('file');
foreach ($entity_info['bundles'] as $file_type => $bundle_info) {
if (isset($bundle_info['admin'])) {
// Get the base path and access.
$path = $bundle_info['admin']['path'];
$access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
$access += array(
'access callback' => 'user_access',
Paris Liakos
committed
'access arguments' => array('administer file types'),
Dave Reid
committed
);
// The file type must be passed to the page callbacks. It might be
// configured as a wildcard (multiple file types sharing the same menu
// router path).
$file_type_argument = isset($bundle_info['admin']['bundle argument']) ? $bundle_info['admin']['bundle argument'] : $file_type;
Paris Liakos
committed
$items[$path] = array(
'title' => 'Edit file type',
Paris Liakos
committed
'title callback' => 'file_entity_type_get_name',
Paris Liakos
committed
'title arguments' => array(4),
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_file_type_form', $file_type_argument),
'file' => 'file_entity.admin.inc',
) + $access;
// Add the 'File type settings' tab.
$items["$path/edit"] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
Dave Reid
committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
// Add the 'Manage file display' tab.
$items["$path/file-display"] = array(
'title' => 'Manage file display',
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_file_display_form', $file_type_argument, 'default'),
'type' => MENU_LOCAL_TASK,
'weight' => 3,
'file' => 'file_entity.admin.inc',
) + $access;
// Add a secondary tab for each view mode.
$weight = 0;
$view_modes = array('default' => array('label' => t('Default'))) + $entity_info['view modes'];
foreach ($view_modes as $view_mode => $view_mode_info) {
$items["$path/file-display/$view_mode"] = array(
'title' => $view_mode_info['label'],
'page arguments' => array('file_entity_file_display_form', $file_type_argument, $view_mode),
'type' => ($view_mode == 'default' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK),
'weight' => ($view_mode == 'default' ? -10 : $weight++),
'file' => 'file_entity.admin.inc',
// View modes for which the 'custom settings' flag isn't TRUE are
// disabled via this access callback. This needs to extend, rather
// than override normal $access rules.
'access callback' => '_file_entity_view_mode_menu_access',
'access arguments' => array_merge(array($file_type_argument, $view_mode, $access['access callback']), $access['access arguments']),
);
}
}
}
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
// Optional devel module integration
if (module_exists('devel')) {
$items['file/%file/devel'] = array(
'title' => 'Devel',
'page callback' => 'devel_load_object',
'page arguments' => array('file', 1),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'devel.pages.inc',
'file path' => drupal_get_path('module', 'devel'),
'weight' => 100,
);
$items['file/%file/devel/load'] = array(
'title' => 'Load',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['file/%file/devel/render'] = array(
'title' => 'Render',
'page callback' => 'devel_render_object',
'page arguments' => array('file', 1),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
'file path' => drupal_get_path('module', 'devel'),
'type' => MENU_LOCAL_TASK,
'weight' => 100,
);
if (module_exists('token')) {
$items['file/%file/devel/token'] = array(
'title' => 'Tokens',
'page callback' => 'token_devel_token_object',
'page arguments' => array('file', 1),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'token.pages.inc',
'file path' => drupal_get_path('module', 'token'),
'weight' => 5,
);
}
Dave Reid
committed
return $items;
}
Dave Reid
committed
/**
* Implements hook_menu_local_tasks_alter().
*/
function file_entity_menu_local_tasks_alter(&$data, $router_item, $root_path) {
// Add action link to 'file/add' on 'admin/content/file' page.
if ($root_path == 'admin/content/file') {
$item = menu_get_item('file/add');
if (!empty($item['access'])) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
'#weight' => $item['weight'],
);
}
}
}
Robin Barre
committed
/**
* Implement hook_permission().
*/
function file_entity_permission() {
Paris Liakos
committed
$permissions = array(
'bypass file access' => array(
'title' => t('Bypass file access control'),
'description' => t('View, edit and delete all files regardless of permission restrictions.'),
'restrict access' => TRUE,
),
'administer file types' => array(
'title' => t('Administer file types'),
'restrict access' => TRUE,
),
'administer files' => array(
'title' => t('Administer files'),
'restrict access' => TRUE,
Paris Liakos
committed
),
'create files' => array(
'title' => t('Add and upload new files'),
Robin Barre
committed
),
Paris Liakos
committed
'view own private files' => array(
'title' => t('View own private files'),
Paris Liakos
committed
),
'view own files' => array(
'title' => t('View own files'),
Devin Carlson
committed
),
Devin Carlson
committed
'view private files' => array(
'title' => t('View private files'),
'restrict access' => TRUE,
Devin Carlson
committed
),
'view files' => array(
'title' => t('View files'),
Devin Carlson
committed
),
Paris Liakos
committed
'edit own files' => array(
'title' => t('Edit own files'),
),
'edit any files' => array(
'title' => t('Edit any files'),
),
'delete own files' => array(
'title' => t('Delete own files'),
),
Paris Liakos
committed
'delete any files' => array(
'title' => t('Delete any files'),
Robin Barre
committed
),
'download own files' => array(
'title' => t('Download own files'),
),
'download any files' => array(
'title' => t('Download any files'),
),
Robin Barre
committed
);
Paris Liakos
committed
// Add description for the 'View file details' and 'View own private file
// details' permissions to show which stream wrappers they apply to.
$wrappers = array();
foreach (file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE) as $key => $wrapper) {
if (empty($wrapper['private'])) {
$wrappers['public'][$key] = $wrapper['name'];
}
else {
$wrappers['private'][$key] = $wrapper['name'];
}
}
$wrappers += array('public' => array(t('None')), 'private' => array(t('None')));
$permissions['view files']['description'] = t('Includes the following stream wrappers: %wrappers.', array('%wrappers' => implode(', ', $wrappers['public'])));
$permissions['view own private files']['description'] = t('Includes the following stream wrappers: %wrappers.', array('%wrappers' => implode(', ', $wrappers['private'])));
Paris Liakos
committed
return $permissions;
Robin Barre
committed
}
Paris Liakos
committed
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/**
* Gather the rankings from the the hook_ranking implementations.
*
* @param $query
* A query object that has been extended with the Search DB Extender.
*/
function _file_entity_rankings(SelectQueryExtender $query) {
if ($ranking = module_invoke_all('file_ranking')) {
$tables = &$query->getTables();
foreach ($ranking as $rank => $values) {
if ($file_rank = variable_get('file_entity_rank_' . $rank, 0)) {
// If the table defined in the ranking isn't already joined, then add it.
if (isset($values['join']) && !isset($tables[$values['join']['alias']])) {
$query->addJoin($values['join']['type'], $values['join']['table'], $values['join']['alias'], $values['join']['on']);
}
$arguments = isset($values['arguments']) ? $values['arguments'] : array();
$query->addScore($values['score'], $arguments, $file_rank);
}
}
}
}
/**
* Implements hook_search_info().
*/
function file_entity_search_info() {
return array(
'title' => 'Files',
'path' => 'file',
);
}
/**
* Implements hook_search_access().
*/
function file_entity_search_access() {
Devin Carlson
committed
return user_access('view own private files') || user_access('view own files') || user_access('view private files') || user_access('view files');
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
}
/**
* Implements hook_search_reset().
*/
function file_entity_search_reset() {
db_update('search_dataset')
->fields(array('reindex' => REQUEST_TIME))
->condition('type', 'file')
->execute();
}
/**
* Implements hook_search_status().
*/
function file_entity_search_status() {
$total = db_query('SELECT COUNT(*) FROM {file_managed}')->fetchField();
$remaining = db_query("SELECT COUNT(*) FROM {file_managed} fm LEFT JOIN {search_dataset} d ON d.type = 'file' AND d.sid = fm.fid WHERE d.sid IS NULL OR d.reindex <> 0")->fetchField();
return array('remaining' => $remaining, 'total' => $total);
}
/**
* Implements hook_search_admin().
*/
function file_entity_search_admin() {
// Output form for defining rank factor weights.
$form['file_ranking'] = array(
'#type' => 'fieldset',
'#title' => t('File ranking'),
);
$form['file_ranking']['#theme'] = 'file_entity_search_admin';
$form['file_ranking']['info'] = array(
'#value' => '<em>' . t('The following numbers control which properties the file search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
);
// Note: reversed to reflect that higher number = higher ranking.
$options = drupal_map_assoc(range(0, 10));
foreach (module_invoke_all('file_ranking') as $var => $values) {
$form['file_ranking']['factors']['file_entity_rank_' . $var] = array(
'#title' => $values['title'],
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get('file_entity_rank_' . $var, 0),
);
}
return $form;
}
/**
* Implements hook_search_execute().
*/
function file_entity_search_execute($keys = NULL, $conditions = NULL) {
global $user;
// Build matching conditions
$query = db_select('search_index', 'i', array('target' => 'slave'))->extend('SearchQuery')->extend('PagerDefault');
$query->join('file_managed', 'fm', 'fm.fid = i.sid');
$query->searchExpression($keys, 'file');
if (user_access('bypass file access')) {
// Administrators don't need to be restricted to only permanent files.
$query->condition('fm.status', FILE_STATUS_PERMANENT);
}
elseif (user_access('view files')) {
// For non-private files, users can view if they have the 'view files'
// permission.
$query->condition('fm.status', FILE_STATUS_PERMANENT);
}
Devin Carlson
committed
elseif (user_access('view private files') && user_is_logged_in()) {
// For private files, users can view private files if the
// user is not anonymous, and has the 'view private files' permission.
$query->condition('fm.uri', db_like('private://') . '%', 'LIKE');
$query->condition('fm.status', FILE_STATUS_PERMANENT);
}
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
elseif (user_access('view own files')) {
// For non-private files, allow to see if user owns the file.
$query->condition('fm.uid', $user->uid, '=');
$query->condition('fm.status', FILE_STATUS_PERMANENT);
}
elseif (user_access('view own private files') && user_is_logged_in()) {
// For private files, users can view their own private files if the
// user is not anonymous, and has the 'view own private files' permission.
$query->condition('fm.uri', db_like('private://') . '%', 'LIKE');
$query->condition('fm.uid', $user->uid, '=');
$query->condition('fm.status', FILE_STATUS_PERMANENT);
}
// Insert special keywords.
$query->setOption('type', 'fm.type');
if ($query->setOption('term', 'ti.tid')) {
$query->join('taxonomy_index', 'ti', 'fm.fid = ti.fid');
}
// Only continue if the first pass query matches.
if (!$query->executeFirstPass()) {
return array();
}
// Add the ranking expressions.
_file_entity_rankings($query);
// Load results.
$find = $query
->limit(10)
->execute();
$results = array();
foreach ($find as $item) {
// Render the file.
$file = file_load($item->sid);
$build = file_view($file, 'search_result');
unset($build['#theme']);
$file->rendered = drupal_render($build);
$extra = module_invoke_all('file_entity_search_result', $file);
$types = file_entity_type_get_names();
$uri = entity_uri('file', $file);
$results[] = array(
'link' => url($uri['path'], array_merge($uri['options'], array('absolute' => TRUE))),
'type' => check_plain($types[$file->type]),
'title' => $file->filename,
'user' => theme('username', array('account' => user_load($file->uid))),
'date' => $file->timestamp,
'file' => $file,
'extra' => $extra,
'score' => $item->calculated_score,
'snippet' => search_excerpt($keys, $file->rendered),
'language' => function_exists('entity_language') ? entity_language('file', $file) : NULL,
);
}
return $results;
}
/**
* Implements hook_file_ranking().
*/
function file_entity_file_ranking() {
// Create the ranking array and add the basic ranking options.
$ranking = array(
'relevance' => array(
'title' => t('Keyword relevance'),
// Average relevance values hover around 0.15
'score' => 'i.relevance',
),
);
// Add relevance based on creation date.
if ($file_cron_last = variable_get('file_entity_cron_last', 0)) {
$ranking['timestamp'] = array(
'title' => t('Recently posted'),
// Exponential decay with half-life of 6 months, starting at last indexed file
'score' => 'POW(2.0, (fm.timestamp - :file_cron_last) * 6.43e-8)',
'arguments' => array(':file_cron_last' => $file_cron_last),
);
}
return $ranking;
}
/**
* Returns HTML for the file ranking part of the search settings admin page.
*
* @param $variables
* An associative array containing:
* - form: A render element representing the form.
*
* @ingroup themeable
*/
function theme_file_entity_search_admin($variables) {
$form = $variables['form'];
$output = drupal_render($form['info']);
$header = array(t('Factor'), t('Weight'));
foreach (element_children($form['factors']) as $key) {
$row = array();
$row[] = $form['factors'][$key]['#title'];
$form['factors'][$key]['#title_display'] = 'invisible';
$row[] = drupal_render($form['factors'][$key]);
$rows[] = $row;
}
$output .= theme('table', array('header' => $header, 'rows' => $rows));
$output .= drupal_render_children($form);
return $output;
}
/**
* Implements hook_update_index().
*/
function file_entity_update_index() {
$limit = (int)variable_get('search_cron_limit', 100);
$result = db_query_range("SELECT fm.fid FROM {file_managed} fm LEFT JOIN {search_dataset} d ON d.type = 'file' AND d.sid = fm.fid WHERE d.sid IS NULL OR d.reindex <> 0 ORDER BY d.reindex ASC, fm.fid ASC", 0, $limit, array(), array('target' => 'slave'));
foreach ($result as $file) {
_file_entity_index_file($file);
}
}
/**
* Index a single file.
*
* @param $file
* The file to index.
*/
function _file_entity_index_file($file) {
$file = file_load($file->fid);
// Save the creation time of the most recent indexed file, for the search
// results half-life calculation.
variable_set('file_entity_cron_last', $file->timestamp);
// Render the file.
$build = file_view($file, 'search_index');
unset($build['#theme']);
$file->rendered = drupal_render($build);
$text = '<h1>' . check_plain($file->filename) . '</h1>' . $file->rendered;
// Fetch extra data normally not visible
$extra = module_invoke_all('file_entity_update_index', $file);
foreach ($extra as $t) {
$text .= $t;
}
// Update index
search_index($file->fid, 'file', $text);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function file_entity_form_search_form_alter(&$form, $form_state) {
if (isset($form['module']) && $form['module']['#value'] == 'file_entity' && user_access('use advanced search')) {
// Keyword boxes:
$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced search'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array('class' => array('search-advanced')),
);
$form['advanced']['keywords'] = array(
'#prefix' => '<div class="criterion">',
'#suffix' => '</div>',
);
$form['advanced']['keywords']['or'] = array(
'#type' => 'textfield',
'#title' => t('Containing any of the words'),
'#size' => 30,
'#maxlength' => 255,
);
$form['advanced']['keywords']['phrase'] = array(
'#type' => 'textfield',
'#title' => t('Containing the phrase'),
'#size' => 30,
'#maxlength' => 255,
);
$form['advanced']['keywords']['negative'] = array(
'#type' => 'textfield',
'#title' => t('Containing none of the words'),
'#size' => 30,
'#maxlength' => 255,
);
// File types:
$types = array_map('check_plain', file_entity_type_get_names());
$form['advanced']['type'] = array(
'#type' => 'checkboxes',
'#title' => t('Only of the type(s)'),
'#prefix' => '<div class="criterion">',
'#suffix' => '</div>',
'#options' => $types,
);
$form['advanced']['submit'] = array(
'#type' => 'submit',
'#value' => t('Advanced search'),
'#prefix' => '<div class="action">',
'#suffix' => '</div>',
'#weight' => 100,
);
$form['#validate'][] = 'file_entity_search_validate';
}
}
/**
* Form API callback for the search form. Registered in file_entity_form_alter().
*/
function file_entity_search_validate($form, &$form_state) {
// Initialize using any existing basic search keywords.
$keys = $form_state['values']['processed_keys'];
// Insert extra restrictions into the search keywords string.
if (isset($form_state['values']['type']) && is_array($form_state['values']['type'])) {
// Retrieve selected types - Form API sets the value of unselected
// checkboxes to 0.
$form_state['values']['type'] = array_filter($form_state['values']['type']);
if (count($form_state['values']['type'])) {
$keys = search_expression_insert($keys, 'type', implode(',', array_keys($form_state['values']['type'])));
}
}
if (isset($form_state['values']['term']) && is_array($form_state['values']['term']) && count($form_state['values']['term'])) {
$keys = search_expression_insert($keys, 'term', implode(',', $form_state['values']['term']));
}
if ($form_state['values']['or'] != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_state['values']['or'], $matches)) {
$keys .= ' ' . implode(' OR ', $matches[1]);
}
}
if ($form_state['values']['negative'] != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_state['values']['negative'], $matches)) {
$keys .= ' -' . implode(' -', $matches[1]);
}
}
if ($form_state['values']['phrase'] != '') {
$keys .= ' "' . str_replace('"', ' ', $form_state['values']['phrase']) . '"';
}
if (!empty($keys)) {
form_set_value($form['basic']['processed_keys'], trim($keys), $form_state);
}
}
Robin Barre
committed
/**
* Implements hook_admin_paths().
*/
function file_entity_admin_paths() {
$paths = array(
Kristof De Jaeger
committed
'file/add' => TRUE,
'file/add/*' => TRUE,
Robin Barre
committed
'file/*/edit' => TRUE,
Paris Liakos
committed
'file/*/usage' => TRUE,
Robin Barre
committed
'file/*/delete' => TRUE,
);
return $paths;
}
Dave Reid
committed
/**
* Implements hook_theme().
*/
function file_entity_theme() {
return array(
Dave Reid
committed
'file_entity' => array(
'render element' => 'elements',
Robin Barre
committed
'template' => 'file_entity',
Dave Reid
committed
),
'file_entity_search_admin' => array(
'render element' => 'form',
),
Dave Reid
committed
'file_entity_file_type_overview' => array(
'variables' => array('label' => NULL, 'description' => NULL),
'file' => 'file_entity.admin.inc',
),
'file_entity_file_display_order' => array(
'render element' => 'element',
'file' => 'file_entity.admin.inc',
),
Jacob Singh
committed
'file_entity_file_link' => array(
'variables' => array('file' => NULL, 'icon_directory' => NULL),
'file' => 'file_entity.theme.inc',
Paris Liakos
committed
),
Dave Reid
committed
);
}
/**
* Implements hook_entity_info_alter().
*
Paris Liakos
committed
* Extends the core file entity to be fieldable. The file type is used as the
* bundle key. File types are implemented as CTools exportables, so modules can
* define default file types via hook_file_default_types(), and the
* administrator can override the default types or add custom ones via
* admin/structure/file-types.
Dave Reid
committed
*/
function file_entity_entity_info_alter(&$entity_info) {
$entity_info['file']['fieldable'] = TRUE;
$entity_info['file']['entity keys']['bundle'] = 'type';
Paris Liakos
committed
$entity_info['file']['bundle keys']['bundle'] = 'type';
Dave Reid
committed
$entity_info['file']['bundles'] = array();
$entity_info['file']['uri callback'] = 'file_entity_uri';
$entity_info['file']['view modes']['teaser'] = array(
'label' => t('Teaser'),
'custom settings' => TRUE,
);
$entity_info['file']['view modes']['full'] = array(
'label' => t('Full content'),
'custom settings' => FALSE,
);
$entity_info['file']['view modes']['preview'] = array(
'label' => t('Preview'),
'custom settings' => TRUE,
);
// Search integration is provided by file_entity.module, so search-related
// view modes for files are defined here and not in search.module.
if (module_exists('search')) {
$entity_info['file']['view modes']['search_index'] = array(
'label' => t('Search index'),
'custom settings' => FALSE,
);
$entity_info['file']['view modes']['search_result'] = array(
'label' => t('Search result'),
'custom settings' => FALSE,
);
}
Paris Liakos
committed
foreach (file_type_get_enabled_types() as $type) {
$entity_info['file']['bundles'][$type->type] = array(
'label' => $type->label,
Dave Reid
committed
'admin' => array(
Paris Liakos
committed
'path' => 'admin/structure/file-types/manage/%file_type',
'real path' => 'admin/structure/file-types/manage/' . $type->type,
Thomas Svenson
committed
'bundle argument' => 4,
Dave Reid
committed
),
);
}
// Enable Metatag support.
$entity_info['file']['metatags'] = TRUE;
// Ensure some of the Entity API callbacks are supported.
$entity_info['file']['creation callback'] = 'entity_metadata_create_object';
$entity_info['file']['view callback'] = 'file_view_multiple';
$entity_info['file']['edit callback'] = 'file_entity_metadata_form_file';
$entity_info['file']['access callback'] = 'file_entity_access';
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
// Add integration with the Title module for file name replacement support.
$entity_info['file']['field replacement'] = array(
'filename' => array(
'field' => array(
'type' => 'text',
'cardinality' => 1,
'translatable' => TRUE,
),
'instance' => array(
'label' => t('File name'),
'description' => t('A field replacing file name.'),
'required' => TRUE,
'settings' => array(
'text_processing' => 0,
),
'widget' => array(
'weight' => -5,
),
'display' => array(
'default' => array(
'type' => 'hidden',
),
),
),
'preprocess_key' => 'filename',
),
);
}
/**
* Implements hook_entity_property_info().
*/
function file_entity_entity_property_info() {
$info['file']['properties']['type'] = array(
'label' => t('File type'),
'type' => 'token',
'description' => t('The type of the file.'),
'setter callback' => 'entity_property_verbatim_set',
'setter permission' => 'administer files',
Paris Liakos
committed
'options list' => 'file_entity_type_get_names',
'required' => TRUE,
'schema field' => 'type',
);
return $info;
Dave Reid
committed
}
/**
* Implements hook_field_display_ENTITY_TYPE_alter().
*/
function file_entity_field_display_file_alter(&$display, $context) {
// Hide field labels in search index.
if ($context['view_mode'] == 'search_index') {
$display['label'] = 'hidden';
}
}
/**
* URI callback for file entities.
*/
function file_entity_uri($file) {
$uri['path'] = 'file/' . $file->fid;
return $uri;
}
/**
* Entity API callback to get the form of a file entity.
*/
function file_entity_metadata_form_file($file) {
// Pre-populate the form-state with the right form include.
$form_state['build_info']['args'] = array($file);
form_load_include($form_state, 'inc', 'file_entity', 'file_entity.pages');
return drupal_build_form('file_entity_edit', $form_state);
}
Dave Reid
committed
/**
* Implements hook_field_extra_fields().
*
* Adds 'file' as an extra field, so that its display and form component can be
* weighted relative to the fields that are added to file entity bundles.
*/
function file_entity_field_extra_fields() {
Paris Liakos
committed
if ($file_type_names = file_entity_type_get_names()) {
Lathan Britz
committed
foreach ($file_type_names as $type => $name) {
$info['file'][$type]['form']['filename'] = array(
'label' => t('File name'),
'description' => t('File name'),
'weight' => -10,
);
$info['file'][$type]['form']['preview'] = array(
'label' => t('File'),
'description' => t('File preview'),
'weight' => -5,
);
$info['file'][$type]['display']['file'] = array(
'label' => t('File'),
'description' => t('File display'),
'weight' => 0,
);
}
Dave Reid
committed
}
Dave Reid
committed
}
/**
* Implements hook_file_formatter_info().
*/
function file_entity_file_formatter_info() {
$formatters = array();
// Allow file field formatters to be reused for displaying the file entity's
// file pseudo-field.
Dave Reid
committed
foreach (field_info_formatter_types() as $field_formatter_type => $field_formatter_info) {
$is_file_formatter = in_array('file', $field_formatter_info['field types']);
$is_image_formatter = in_array('image', $field_formatter_info['field types']);
if ($is_file_formatter || $is_image_formatter) {
Dave Reid
committed
$formatters['file_field_' . $field_formatter_type] = array(
'label' => $field_formatter_info['label'],
'view callback' => 'file_entity_file_formatter_file_field_view',
);
if (!$is_file_formatter) {
$formatters['file_field_' . $field_formatter_type]['file types'] = array('image');
}
Dave Reid
committed
if (!empty($field_formatter_info['settings'])) {
$formatters['file_field_' . $field_formatter_type] += array(
'default settings' => $field_formatter_info['settings'],
'settings callback' => 'file_entity_file_formatter_file_field_settings',