filefield_sources.module in FileField Sources 6
Same filename and directory in other branches
Extend FileField to allow files from multiple sources.
File
filefield_sources.moduleView source
<?php
/**
* @file
* Extend FileField to allow files from multiple sources.
*/
/**
* Implements hook_menu().
*/
function filefield_sources_menu() {
$params = array();
return filefield_sources_invoke_all('menu', $params);
}
/**
* Implements hook_elements().
*/
function filefield_sources_elements() {
$elements = array();
foreach (module_invoke_all('filefield_sources_widgets') as $widget) {
$elements[$widget]['#process'] = array(
'filefield_sources_field_process',
);
$elements[$widget]['#pre_render'] = array(
'filefield_sources_field_pre_render',
);
$elements[$widget]['#element_validate'] = array(
'filefield_sources_field_validate',
);
$elements[$widget]['#filefield_value_callback'] = array(
'filefield_sources_field_value',
);
}
return $elements;
}
/**
* Implements hook_theme().
*/
function filefield_sources_theme() {
$params = array();
$theme = filefield_sources_invoke_all('theme', $params);
$theme['filefield_sources_list'] = array(
'arguments' => array(
'sources' => NULL,
),
);
return $theme;
}
/**
* Implements hook_filefield_sources_widgets().
*
* This returns a list of widgets that are compatible with FileField Sources.
*/
function filefield_sources_filefield_sources_widgets() {
return array(
'filefield_widget',
'imagefield_widget',
);
}
/**
* Implements hook_widget_settings_alter().
*/
function filefield_sources_widget_settings_alter(&$settings, $op, $widget) {
// Only support modules that implement hook_insert_widgets().
$widget_type = isset($widget['widget_type']) ? $widget['widget_type'] : $widget['type'];
if (!in_array($widget_type, module_invoke_all('filefield_sources_widgets'))) {
return;
}
if ($op == 'form') {
$settings = array_merge($settings, filefield_sources_form($widget));
}
if ($op == 'save') {
$settings = array_merge($settings, filefield_sources_widget_settings($widget));
}
}
/**
* A list of settings needed by FileField Sources module on widgets.
*/
function filefield_sources_widget_settings($widget) {
$settings = array(
'filefield_sources',
);
$params = array(
'save',
$widget,
);
$settings = array_merge($settings, filefield_sources_invoke_all('settings', $params));
return $settings;
}
/**
* Configuration form for editing FileField Sources settings for a widget.
*/
function filefield_sources_form($widget) {
$settings = $widget;
$form['filefield_sources'] = array(
'#type' => 'fieldset',
'#title' => t('File sources'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 15,
);
$sources = filefield_sources_list(FALSE);
$sources = isset($settings['filefield_sources']) ? array_intersect_key(array_merge($settings['filefield_sources'], $sources), $sources) : $sources;
$form['filefield_sources']['filefield_sources'] = array(
'#type' => 'checkboxes',
'#title' => t('Enabled sources'),
'#options' => $sources,
'#default_value' => isset($settings['filefield_sources']) ? $settings['filefield_sources'] : array(),
'#description' => t('Select the available locations from which this widget may select files.'),
);
$params = array(
'form',
$settings,
);
$form['filefield_sources'] = array_merge($form['filefield_sources'], filefield_sources_invoke_all('settings', $params));
return $form;
}
/**
* A #process callback to extend the filefield_widget element type.
*
* Add the central JavaScript and CSS files that allow switching between
* different sources. Third-party modules can also add to the list of sources
* by implementing hook_filefield_sources_info().
*/
function filefield_sources_field_process($element, $edit, &$form_state, $form) {
static $js_added;
// If not a recognized field instance, do not process.
if (!isset($element['#field_name']) || !($field = content_fields($element['#field_name'], $element['#type_name']))) {
return $element;
}
// Do all processing as needed by each source.
$sources = filefield_sources_info();
$enabled_sources = isset($field['widget']['filefield_sources']) ? $field['widget']['filefield_sources'] : array();
foreach ($sources as $source_name => $source) {
if (empty($enabled_sources[$source_name])) {
unset($sources[$source_name]);
}
elseif (isset($source['process'])) {
$function = $source['process'];
$element = $function($element, $edit, $form_state, $form);
}
}
// Exit out if not adding any sources.
if (empty($sources)) {
return $element;
}
// Add basic JS and CSS.
$path = drupal_get_path('module', 'filefield_sources');
drupal_add_css($path . '/filefield_sources.css');
drupal_add_js($path . '/filefield_sources.js');
// Check the element for hint text that might need to be added.
foreach (element_children($element) as $key) {
if (isset($element[$key]['#filefield_sources_hint_text']) && !isset($js_added[$key])) {
$type = str_replace('filefield_', '', $key);
drupal_add_js(array(
'fileFieldSources' => array(
$type => array(
'hintText' => $element[$key]['#filefield_sources_hint_text'],
),
),
), 'setting');
$js_added[$key] = TRUE;
}
}
// Add the list of sources to the element for toggling between sources.
if (empty($element['fid']['#value'])) {
$element['filefield_sources_list'] = array(
'#type' => 'markup',
'#value' => theme('filefield_sources_list', $element, $sources),
'#weight' => -20,
);
}
return $element;
}
/**
* A #pre_render function to hide sources if a file is currently uploaded.
*/
function filefield_sources_field_pre_render($element) {
// If we already have a file, we don't want to show the upload controls.
if (!empty($element['fid']['#value'])) {
foreach (element_children($element) as $key) {
if (!empty($element[$key]['#filefield_source'])) {
$element[$key]['#access'] = FALSE;
}
}
}
return $element;
}
/**
* An #element_validate function to run source validations.
*/
function filefield_sources_field_validate($element, &$form_state, $form) {
// Do all processing as needed by each source.
$sources = filefield_sources_info();
foreach ($sources as $source) {
if (isset($source['validate'])) {
$function = $source['validate'];
$function($element, $form_state, $form);
}
}
}
/**
* A #filefield_value_callback to run source value callbacks.
*/
function filefield_sources_field_value($element, &$item) {
// Do all processing as needed by each source.
$sources = filefield_sources_info();
foreach ($sources as $source) {
if (isset($source['value'])) {
$function = $source['value'];
$function($element, $item);
}
}
}
/**
* Call all FileField Source hooks stored in the available include files.
*/
function filefield_sources_invoke_all($method, &$params) {
$return = array();
foreach (filefield_sources_includes() as $source) {
$function = 'filefield_source_' . $source . '_' . $method;
if (function_exists($function)) {
$result = call_user_func_array($function, $params);
if (isset($result) && is_array($result)) {
$return = array_merge_recursive($return, $result);
}
elseif (isset($result)) {
$return[] = $result;
}
}
}
return $return;
}
/**
* Load hook_filefield_sources_info() data from all modules.
*/
function filefield_sources_info() {
$info = module_invoke_all('filefield_sources_info');
drupal_alter('filefield_sources_info', $info);
uasort($info, '_filefield_sources_sort');
return $info;
}
/**
* Create a list of FileField Sources by name, suitable for a select list.
*/
function filefield_sources_list($include_default = TRUE) {
$info = filefield_sources_info();
$list = array();
if ($include_default) {
$list['upload'] = t('Upload');
}
foreach ($info as $key => $source) {
$list[$key] = $source['name'];
}
return $list;
}
/**
* Implements hook_filefield_sources_info().
*/
function filefield_sources_filefield_sources_info() {
$params = array();
return filefield_sources_invoke_all('info', $params);
}
/**
* Load all the potential sources.
*/
function filefield_sources_includes($include = TRUE, $enabled_only = TRUE) {
if ($enabled_only) {
$enabled_includes = variable_get('filefield_sources', filefield_sources_includes(FALSE, FALSE));
}
$includes = array();
$directory = drupal_get_path('module', 'filefield_sources') . '/sources';
foreach (file_scan_directory($directory, '.inc$') as $file) {
if (!$enabled_only || in_array($file->name, $enabled_includes)) {
$includes[] = $file->name;
if ($include) {
include_once $file->filename;
}
}
}
return $includes;
}
/**
* Check the current user's access to a file through hook_file_download().
*
* @param $uri
* A file URI as loaded from the database.
* @return
* Boolean TRUE if the user has access, FALSE otherwise.
*
* @see file_download()
* @see hook_file_download().
*/
function filefield_sources_file_access($filepath) {
$headers = array();
foreach (module_implements('file_download') as $module) {
$function = $module . '_file_download';
$result = $function($filepath);
if ($result == -1) {
// Throw away the headers received so far.
$headers = array();
break;
}
if (isset($result) && is_array($result)) {
$headers = array_merge($headers, $result);
}
}
return !empty($headers);
}
/**
* Clean up the file name, munging extensions and transliterating.
*
* @param $filepath
* A string containing a file name or full path. Only the file name will
* actually be modified.
* @return
* A file path with a cleaned-up file name.
*/
function filefield_sources_clean_filename($filepath) {
global $user;
$filename = basename($filepath);
if (module_exists('transliteration')) {
module_load_include('inc', 'transliteration');
$langcode = NULL;
if (!empty($_POST['language'])) {
$languages = language_list();
$langcode = isset($languages[$_POST['language']]) ? $_POST['language'] : NULL;
}
$filename = transliteration_clean_filename($filename, $langcode);
}
// Because this transfer mechanism does not use file_save_upload(), we need
// to manually munge the filename to prevent dangerous extensions.
// See file_save_upload().
$extensions = '';
foreach ($user->roles as $rid => $name) {
$extensions .= ' ' . variable_get("upload_extensions_{$rid}", variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
}
$filename = file_munge_filename($filename, $extensions);
$directory = dirname($filepath);
return ($directory ? $directory . '/' : $directory) . $filename;
}
/**
* Theme the display of the sources list.
*/
function theme_filefield_sources_list($element, $sources) {
$links = array();
// Add the default "Upload" since it's not in our list.
$default['upload'] = array(
'label' => t('Upload'),
'description' => t('Upload a file from your computer.'),
);
$sources = array_merge($default, $sources);
foreach ($sources as $name => $source) {
$links[] = '<a href="#" onclick="return false;" title="' . $source['description'] . '" id="' . $element['#id'] . '-' . $name . '-source" class="filefield-source filefield-source-' . $name . '">' . $source['label'] . '</a>';
}
return '<div class="filefield-sources-list">' . implode(' | ', $links) . '</div>';
}
/**
* Validate a file based on the $element['#upload_validators'] property.
*/
function filefield_sources_element_validate($element, $file) {
$validators = $element['#upload_validators'];
$errors = array();
// Since this frequently is used to reference existing files, check that
// they exist first in addition to the normal validations.
if (!file_exists($file->filepath)) {
$errors[] = t('The file does not exist.');
}
else {
foreach ($validators as $function => $args) {
// Add the $file variable to the list of arguments and pass it by
// reference (required for PHP 5.3 and higher).
array_unshift($args, NULL);
$args[0] =& $file;
$errors = array_merge($errors, call_user_func_array($function, $args));
}
}
// Check for validation errors.
if (!empty($errors)) {
$message = t('The selected file %name could not be referenced.', array(
'%name' => $file->filename,
));
if (count($errors) > 1) {
$message .= '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
}
else {
$message .= ' ' . array_pop($errors);
}
form_error($element, $message);
return 0;
}
return 1;
}
/**
* Generate help text based on the $element['#upload_validators'] property.
*/
function filefield_sources_element_validation_help($validators) {
$desc = array();
foreach ($validators as $callback => $arguments) {
$help_func = $callback . '_help';
if (function_exists($help_func)) {
$desc[] = call_user_func_array($help_func, $arguments);
}
}
return empty($desc) ? '' : implode('<br />', $desc);
}
/**
* Custom sort function for ordering sources.
*/
function _filefield_sources_sort($a, $b) {
$a = (array) $a + array(
'weight' => 0,
'label' => '',
);
$b = (array) $b + array(
'weight' => 0,
'label' => '',
);
return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : strnatcasecmp($a['label'], $b['label']));
}
Functions
Name | Description |
---|---|
filefield_sources_clean_filename | Clean up the file name, munging extensions and transliterating. |
filefield_sources_elements | Implements hook_elements(). |
filefield_sources_element_validate | Validate a file based on the $element['#upload_validators'] property. |
filefield_sources_element_validation_help | Generate help text based on the $element['#upload_validators'] property. |
filefield_sources_field_pre_render | A #pre_render function to hide sources if a file is currently uploaded. |
filefield_sources_field_process | A #process callback to extend the filefield_widget element type. |
filefield_sources_field_validate | An #element_validate function to run source validations. |
filefield_sources_field_value | A #filefield_value_callback to run source value callbacks. |
filefield_sources_filefield_sources_info | Implements hook_filefield_sources_info(). |
filefield_sources_filefield_sources_widgets | Implements hook_filefield_sources_widgets(). |
filefield_sources_file_access | Check the current user's access to a file through hook_file_download(). |
filefield_sources_form | Configuration form for editing FileField Sources settings for a widget. |
filefield_sources_includes | Load all the potential sources. |
filefield_sources_info | Load hook_filefield_sources_info() data from all modules. |
filefield_sources_invoke_all | Call all FileField Source hooks stored in the available include files. |
filefield_sources_list | Create a list of FileField Sources by name, suitable for a select list. |
filefield_sources_menu | Implements hook_menu(). |
filefield_sources_theme | Implements hook_theme(). |
filefield_sources_widget_settings | A list of settings needed by FileField Sources module on widgets. |
filefield_sources_widget_settings_alter | Implements hook_widget_settings_alter(). |
theme_filefield_sources_list | Theme the display of the sources list. |
_filefield_sources_sort | Custom sort function for ordering sources. |