filefield_sources.module in FileField Sources 8
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.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Render\Element;
use Drupal\imce\Imce;
use Drupal\file\Entity\File;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\File\FileSystemInterface;
const FILEFIELD_SOURCE_ATTACH_DEFAULT_PATH = 'file_attach';
const FILEFIELD_SOURCE_ATTACH_RELATIVE = 0;
const FILEFIELD_SOURCE_ATTACH_ABSOLUTE = 1;
const FILEFIELD_SOURCE_ATTACH_MODE_MOVE = 'move';
const FILEFIELD_SOURCE_ATTACH_MODE_COPY = 'copy';
const FILEFIELD_SOURCE_REFERENCE_HINT_TEXT = 'example.png [fid:123]';
const FILEFIELD_SOURCE_REMOTE_HINT_TEXT = 'http://example.com/files/file.png';
const FILEFIELD_SOURCE_REFERENCE_MATCH_STARTS_WITH = '0';
const FILEFIELD_SOURCE_REFERENCE_MATCH_CONTAINS = '1';
const FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_NO = '0';
const FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_YES = '1';
/**
* Implements hook_element_info_alter().
*/
function filefield_sources_element_info_alter(&$type) {
if (isset($type['managed_file'])) {
$type['managed_file']['#process'][] = 'filefield_sources_field_process';
$type['managed_file']['#pre_render'][] = '\\Drupal\\filefield_sources\\FilefieldSourcesPreRenderCallback::preRender';
$type['managed_file']['#element_validate'][] = 'filefield_sources_field_validate';
$type['managed_file']['#file_value_callbacks'][] = 'filefield_sources_field_value';
}
}
/**
* Implements hook_theme().
*/
function filefield_sources_theme() {
$theme = [];
$theme['filefield_sources_element'] = [
'render element' => 'element',
];
$theme['filefield_sources_list'] = [
'variables' => [
'id' => NULL,
'sources' => NULL,
],
];
return $theme;
}
/**
* Implements hook_field_widget_third_party_settings_form().
*
* Add file field sources settings form to supported field widget forms.
*
* @see \Drupal\field_ui\FormDisplayOverview
*/
function filefield_sources_field_widget_third_party_settings_form(WidgetInterface $plugin, FieldDefinitionInterface $field_definition, $form_mode, $form, FormStateInterface $form_state) {
$element = [];
if (in_array($plugin
->getPluginId(), \Drupal::moduleHandler()
->invokeAll('filefield_sources_widgets'))) {
$element = filefield_sources_form($plugin, $form_state);
}
return $element;
}
/**
* Implements hook_field_widget_settings_summary_alter().
*
* Add file field sources information to the field widget settings summary.
*
* @see \Drupal\field_ui\FormDisplayOverview
*/
function filefield_sources_field_widget_settings_summary_alter(&$summary, $context) {
$plugin = $context['widget'];
if (in_array($plugin
->getPluginId(), \Drupal::moduleHandler()
->invokeAll('filefield_sources_widgets'))) {
$settings = $plugin
->getThirdPartySetting('filefield_sources', 'filefield_sources');
$enabled_sources = _filefield_sources_enabled($settings);
$summary[] = t('File field sources:') . ' ' . implode(', ', array_keys($enabled_sources));
}
}
/**
* Implements hook_field_widget_form_alter().
*
* Add file field sources widget's settings to element.
*/
function filefield_sources_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
$plugin = $context['widget'];
if (in_array($plugin
->getPluginId(), \Drupal::moduleHandler()
->invokeAll('filefield_sources_widgets'))) {
$element['#filefield_sources_settings'] = $plugin
->getThirdPartySetting('filefield_sources', 'filefield_sources');
// Bundle is missing in element.
$items = $context['items'];
$element['#bundle'] = $items
->getEntity()
->bundle();
}
}
/**
* Implements hook_filefield_sources_widgets().
*
* This returns a list of widgets that are compatible with FileField Sources.
*/
function filefield_sources_filefield_sources_widgets() {
return [
'file_generic',
'image_image',
];
}
/**
* Configuration form for editing FileField Sources settings for a widget.
*/
function filefield_sources_form($plugin, FormStateInterface $form_state) {
$settings = $plugin
->getThirdPartySetting('filefield_sources', 'filefield_sources');
// Backward compatibility: auto-enable 'upload'.
$enabled = _filefield_sources_enabled($settings);
$form['filefield_sources'] = [
'#type' => 'details',
'#title' => t('File sources'),
'#weight' => 20,
];
$sources = filefield_sources_list();
$form['filefield_sources']['sources'] = [
'#type' => 'checkboxes',
'#title' => t('Enabled sources'),
'#options' => $sources,
'#default_value' => $enabled,
'#description' => t('Select the available locations from which this widget may select files.'),
];
$params = [
$plugin,
];
$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, FormStateInterface $form_state, &$complete_form) {
static $js_added;
// Check if we are processing file field sources.
if (!isset($element['#filefield_sources_settings'])) {
return $element;
}
// Do all processing as needed by each source.
$sources = filefield_sources_info();
$settings = $element['#filefield_sources_settings'];
$enabled_sources = _filefield_sources_enabled($settings);
$context = [
'enabled_sources' => &$enabled_sources,
'element' => $element,
'form_state' => $form_state,
];
// Allow other modules to alter the sources.
\Drupal::moduleHandler()
->alter('filefield_sources_sources', $sources, $context);
foreach ($sources as $source_name => $source) {
if (empty($enabled_sources[$source_name])) {
unset($sources[$source_name]);
}
elseif (isset($source['class'])) {
$callback = [
$source['class'],
'process',
];
if (is_callable($callback)) {
$element = call_user_func_array($callback, [
&$element,
$form_state,
&$complete_form,
]);
}
}
}
$element['#filefield_sources'] = $sources;
// Exit out if not adding any sources.
if (empty($sources)) {
return $element;
}
// Hide default 'upload' type?
if (!isset($enabled_sources['upload'])) {
foreach ([
'upload_button',
'upload',
] as $field) {
if (isset($element[$field])) {
$element[$field]['#access'] = FALSE;
}
}
}
// Add class to upload button.
$element['upload_button']['#attributes']['class'][] = 'upload-button';
$element['#attached']['library'][] = 'filefield_sources/drupal.filefield_sources';
// 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);
$element['#attached']['drupalSettings']['fileFieldSources'][$type] = [
'hintText' => $element[$key]['#filefield_sources_hint_text'],
];
$js_added[$key] = TRUE;
}
}
// Adjust the Ajax settings so that on upload and remove of any individual
// file, the entire group of file fields is updated together.
// Clone of Drupal\file\Plugin\Field\FieldWidget\FileWidget::process().
if ($element['#cardinality'] != 1) {
$parents = array_slice($element['#array_parents'], 0, -1);
$new_options = [
'query' => [
'element_parents' => implode('/', $parents),
],
];
$field_element = NestedArray::getValue($complete_form, $parents);
$new_wrapper = $field_element['#id'] . '-ajax-wrapper';
foreach (Element::children($element) as $key) {
foreach (Element::children($element[$key]) as $subkey) {
if (isset($element[$key][$subkey]['#ajax'])) {
$element[$key][$subkey]['#ajax']['options'] = $new_options;
$element[$key][$subkey]['#ajax']['wrapper'] = $new_wrapper;
$element[$key][$subkey]['#limit_validation_errors'] = [
array_slice($element['#array_parents'], 0, -2),
];
}
}
}
unset($element['#prefix'], $element['#suffix']);
}
// Add the list of sources to the element for toggling between sources.
if (empty($element['fids']['#value'])) {
if (count($enabled_sources) > 1) {
$element['filefield_sources_list'] = [
'#theme' => 'filefield_sources_list',
'#id' => $element['#id'],
'#sources' => $sources,
'#weight' => -20,
];
}
}
return $element;
}
/**
* An #element_validate function to run source validations.
*/
function filefield_sources_field_validate(&$element, FormStateInterface $form_state, &$complete_form) {
// Do all processing as needed by each source.
$sources = filefield_sources_info();
foreach ($sources as $source) {
if (!isset($source['class'])) {
continue;
}
$callback = [
$source['class'],
'validate',
];
if (is_callable($callback)) {
call_user_func_array($callback, [
$element,
$form_state,
$complete_form,
]);
}
}
}
/**
* Form submission handler for all FileField Source buttons.
*
* Clone of \Drupal\file\Plugin\Field\FieldWidget\FileWidget::submit(), with
* a few changes:
* - Submit button is one level down compare to 'Upload' source's submit
* button.
* - Replace static in static::getWidgetState and static::setWidgetState by
* WidgetBase.
* - Rebuild the form after all.
*/
function filefield_sources_field_submit(&$form, FormStateInterface $form_state) {
// During the form rebuild, formElement() will create field item widget
// elements using re-indexed deltas, so clear out FormState::$input to
// avoid a mismatch between old and new deltas. The rebuilt elements will
// have #default_value set appropriately for the current state of the field,
// so nothing is lost in doing this.
$button = $form_state
->getTriggeringElement();
$parents = array_slice($button['#parents'], 0, -3);
NestedArray::setValue($form_state
->getUserInput(), $parents, NULL);
// Go one level up in the form, to the widgets container.
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
$field_name = $element['#field_name'];
$parents = $element['#field_parents'];
$submitted_values = NestedArray::getValue($form_state
->getValues(), array_slice($button['#parents'], 0, -3));
foreach ($submitted_values as $delta => $submitted_value) {
if (empty($submitted_value['fids'])) {
unset($submitted_values[$delta]);
}
}
// If there are more files uploaded via the same widget, we have to separate
// them, as we display each file in it's own widget.
$new_values = [];
foreach ($submitted_values as $delta => $submitted_value) {
if (is_array($submitted_value['fids'])) {
foreach ($submitted_value['fids'] as $fid) {
$new_value = $submitted_value;
$new_value['fids'] = [
$fid,
];
$new_values[] = $new_value;
}
}
else {
$new_value = $submitted_value;
}
}
// Re-index deltas after removing empty items.
$submitted_values = array_values($new_values);
// Update form_state values.
NestedArray::setValue($form_state
->getValues(), array_slice($button['#parents'], 0, -3), $submitted_values);
// Update items.
$field_state = WidgetBase::getWidgetState($parents, $field_name, $form_state);
$field_state['items'] = $submitted_values;
WidgetBase::setWidgetState($parents, $field_name, $form_state, $field_state);
// We need to rebuild the form, so that uploaded file can be displayed.
$form_state
->setRebuild();
}
/**
* A #filefield_value_callback to run source value callbacks.
*/
function filefield_sources_field_value(&$element, &$input, FormStateInterface $form_state) {
// Do all processing as needed by each source.
$sources = filefield_sources_info();
foreach ($sources as $source) {
if (isset($source['class'])) {
$callback = [
$source['class'],
'value',
];
if (is_callable($callback)) {
call_user_func_array($callback, [
&$element,
&$input,
$form_state,
]);
}
}
}
}
/**
* Call all FileField Source hooks stored in the available include files.
*/
function filefield_sources_invoke_all($method, &$params) {
$return = [];
foreach (\Drupal::service('filefield_sources')
->getDefinitions() as $definition) {
if (!isset($definition['class'])) {
continue;
}
// Get routes defined by each plugin.
$callback = [
$definition['class'],
$method,
];
if (is_callable($callback)) {
$result = call_user_func_array($callback, $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($include_default = TRUE) {
$info = \Drupal::service('filefield_sources')
->getDefinitions();
if (isset($info['imce']) && !Imce::access()) {
unset($info['imce']);
}
if ($include_default) {
$info['upload'] = [
'name' => t('Upload (default)'),
'label' => t('Upload'),
'description' => t('Upload a file from your computer.'),
'weight' => -10,
];
}
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($include_default);
$list = [];
foreach ($info as $key => $source) {
$list[$key] = $source['name'];
}
return $list;
}
/**
* Save a file into the database after validating it.
*
* This function is identical to the core function file_save_upload() except
* that it accepts an input file path instead of an input file source name.
*
* @see file_save_upload()
*/
function filefield_sources_save_file($filepath, $validators = [], $destination = FALSE, $replace = FileSystemInterface::EXISTS_RENAME) {
$user = \Drupal::currentUser();
// Begin building file object.
$file = File::create([
'uri' => $filepath,
'uid' => $user
->id(),
'status' => FileSystemInterface::EXISTS_RENAME,
]);
$file
->setFilename(trim(basename($filepath), '.'));
$file
->setMimeType(\Drupal::service('file.mime_type.guesser')
->guess($file
->getFilename()));
$file
->setSize(filesize($filepath));
$extensions = '';
if (isset($validators['file_validate_extensions'])) {
if (isset($validators['file_validate_extensions'][0])) {
// Build the list of non-munged extensions if the caller provided them.
$extensions = $validators['file_validate_extensions'][0];
}
else {
// If 'file_validate_extensions' is set and the list is empty then the
// caller wants to allow any extension. In this case we have to remove the
// validator or else it will reject all extensions.
unset($validators['file_validate_extensions']);
}
}
else {
// No validator was provided, so add one using the default list.
// Build a default non-munged safe list for file_munge_filename().
$extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
$validators['file_validate_extensions'] = [];
$validators['file_validate_extensions'][0] = $extensions;
}
if (!empty($extensions)) {
// Munge the filename to protect against possible malicious extension hiding
// within an unknown file type (ie: filename.html.foo).
$file
->setFilename(file_munge_filename($file
->getFilename(), $extensions));
}
// Rename potentially executable files, to help prevent exploits (i.e. will
// rename filename.php.foo and filename.php to filename.php.foo.txt and
// filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'
// evaluates to TRUE.
if (!\Drupal::config('system.file')
->get('allow_insecure_uploads') && preg_match('/\\.(php|pl|py|cgi|asp|js)(\\.|$)/i', $file
->getFilename()) && substr($file
->getFilename(), -4) != '.txt') {
$file
->setMimeType('text/plain');
$file
->setFileUri($file
->getFileUri() . '.txt');
$file
->setFilename($file
->getFilename() . '.txt');
// The .txt extension may not be in the allowed list of extensions. We have
// to add it here or else the file upload will fail.
if (!empty($extensions)) {
$validators['file_validate_extensions'][0] .= ' txt';
\Drupal::messenger()
->addStatus(t('For security reasons, your upload has been renamed to %filename.', [
'%filename' => $file
->getFilename(),
]));
}
}
// If the destination is not provided, use the temporary directory.
if (empty($destination)) {
$destination = 'temporary://';
}
// Assert that the destination contains a valid stream.
$destination_scheme = \Drupal::service('stream_wrapper_manager')
->getScheme($destination);
if (!$destination_scheme || !\Drupal::service('stream_wrapper_manager')
->isValidScheme($destination_scheme)) {
\Drupal::messenger()
->addError(t('The file could not be uploaded, because the destination %destination is invalid.', [
'%destination' => $destination,
]), 'error');
return FALSE;
}
// A URI may already have a trailing slash or look like "public://".
if (substr($destination, -1) != '/') {
$destination .= '/';
}
// Ensure the destination is writable.
\Drupal::service('file_system')
->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY);
// Check if this is actually the same file being "attached" to a file record.
// If so, it acts as a file replace, except no file is actually moved.
$reuse_file = $destination . $file
->getFilename() === $file
->getFileUri();
if ($reuse_file) {
$replace = FileSystemInterface::EXISTS_REPLACE;
}
$file->destination = \Drupal::service('file_system')
->getDestinationFilename($destination . $file
->getFilename(), $replace);
// If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
// there's an existing file so we need to bail.
if ($file->destination === FALSE) {
\Drupal::messenger()
->addError(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', [
'%source' => $file
->getFilename(),
'%directory' => $destination,
]), 'error');
return FALSE;
}
// Add in our check of the the file name length.
$validators['file_validate_name_length'] = [];
// Call the validation functions specified by this function's caller.
$errors = file_validate($file, $validators);
// Check for errors.
if (!empty($errors)) {
$message = t('The specified file %name could not be uploaded.', [
'%name' => $file
->getFilename(),
]);
if (count($errors) > 1) {
$message .= theme('item_list', [
'items' => $errors,
]);
}
else {
$message .= ' ' . array_pop($errors);
}
\Drupal::messenger()
->addError($message, 'error');
return FALSE;
}
// Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary
// directory. This overcomes open_basedir restrictions for future file
// operations.
$file
->setFileUri($file->destination);
if (!$reuse_file && !\Drupal::service('file_system')
->copy($filepath, $file
->getFileUri(), $replace)) {
\Drupal::messenger()
->addError(t('File upload error. Could not move uploaded file.'), 'error');
\Drupal::logger('filefield_sources')
->log(E_NOTICE, 'Upload error. Could not move uploaded file %file to destination %destination.', [
'%file' => $file
->getFilename(),
'%destination' => $file
->getFileUri(),
]);
return FALSE;
}
// Set the permissions on the new file.
\Drupal::service('file_system')
->chmod($file
->getFileUri());
// If we are replacing an existing file re-use its database record.
if ($replace == FileSystemInterface::EXISTS_REPLACE) {
$existing_files = File::loadMultiple([], [
'uri' => $file
->getFileUri(),
]);
if (count($existing_files)) {
$existing = reset($existing_files);
$file
->setOriginalId($existing
->id());
}
}
// If we made it this far it's safe to record this file in the database.
$file
->save();
return $file;
}
/**
* Clean up the file name, munging extensions and transliterating.
*
* @param string $filepath
* A string containing a file name or full path. Only the file name will
* actually be modified.
*
* @return string
* A file path with a cleaned-up file name.
*/
function filefield_sources_clean_filename($filepath, $extensions) {
$filename = basename($filepath);
$language = \Drupal::languageManager()
->getCurrentLanguage()
->getId();
$filename = \Drupal::transliteration()
->transliterate($filename, $language);
// 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().
if (empty($extensions)) {
$extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
}
$filename = file_munge_filename($filename, $extensions);
$directory = \Drupal::service('file_system')
->dirname($filepath);
return ($directory != '.' ? $directory . '/' : '') . $filename;
}
/**
* Theme the display of the source element.
*/
function template_preprocess_filefield_sources_element(&$variables) {
$element = $variables['element'];
$source_id = $element['#source_id'];
$method = isset($element['#method']) ? $element['#method'] : 'element';
$extra_variables = isset($element['#variables']) ? $element['#variables'] : [];
$sources = filefield_sources_info();
if (isset($sources[$source_id]['class'])) {
$callback = [
$sources[$source_id]['class'],
$method,
];
if (is_callable($callback)) {
$variables = array_merge($variables, $extra_variables);
$variables['rendered_element'] = call_user_func_array($callback, [
$variables,
]);
}
}
return '';
}
/**
* Validate a file based on the $element['#upload_validators'] property.
*/
function filefield_sources_element_validate($element, $file, FormStateInterface $form_state) {
$validators = $element['#upload_validators'];
$errors = [];
// Since this frequently is used to reference existing files, check that
// they exist first in addition to the normal validations.
if (!file_exists($file
->getFileUri())) {
$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.', [
'%name' => $file->filename,
]);
if (count($errors) > 1) {
$message .= '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
}
else {
$message .= ' ' . array_pop($errors);
}
$form_state
->setError($element, $message);
return 0;
}
return 1;
}
/**
* Generate help text based on the $element['#upload_validators'] property.
*/
function filefield_sources_element_validation_help($validators) {
$desc = [];
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 + [
'weight' => 0,
'label' => '',
];
$b = (array) $b + [
'weight' => 0,
'label' => '',
];
return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : strnatcasecmp($a['label'], $b['label']));
}
/**
* Helper to return enabled sources for a field.
*
* This provides backward compatibility for 'upload' type.
*
* @see http://drupal.org/node/932994
*/
function _filefield_sources_enabled($settings) {
if (!isset($settings['sources']['upload'])) {
$settings['sources']['upload'] = 'upload';
}
$enabled = array_keys(array_filter($settings['sources']));
asort($enabled);
return array_combine($enabled, $enabled);
}
// @todo Remove once https://www.drupal.org/node/1808132 is finished.
if (!function_exists('module_get_weight')) {
/**
* Gets weight of a particular module.
*
* @param string $module
* The name of the module (without the .module extension).
*
* @return int
* The configured weight of the module.
*
* @throws InvalidArgumentException
* Thrown in case the given module is not installed in the system.
*/
function module_get_weight($module) {
$weight = \Drupal::config('core.extension')
->get("module.{$module}");
if ($weight !== NULL) {
return (int) $weight;
}
$weight = \Drupal::config('core.extension')
->get("disabled.module.{$module}");
if ($weight !== NULL) {
return (int) $weight;
}
throw new InvalidArgumentException(new FormattableMarkup('The module %module is not installed.', [
'%module' => $module,
]));
}
}
/**
* Check for CURL extension enabled.
*/
function filefield_sources_curl_enabled() {
return function_exists('curl_version');
}
Functions
Name | Description |
---|---|
filefield_sources_clean_filename | Clean up the file name, munging extensions and transliterating. |
filefield_sources_curl_enabled | Check for CURL extension enabled. |
filefield_sources_element_info_alter | Implements hook_element_info_alter(). |
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_process | A #process callback to extend the filefield_widget element type. |
filefield_sources_field_submit | Form submission handler for all FileField Source buttons. |
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_field_widget_form_alter | Implements hook_field_widget_form_alter(). |
filefield_sources_field_widget_settings_summary_alter | Implements hook_field_widget_settings_summary_alter(). |
filefield_sources_field_widget_third_party_settings_form | Implements hook_field_widget_third_party_settings_form(). |
filefield_sources_filefield_sources_widgets | Implements hook_filefield_sources_widgets(). |
filefield_sources_form | Configuration form for editing FileField Sources settings for a widget. |
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_save_file | Save a file into the database after validating it. |
filefield_sources_theme | Implements hook_theme(). |
template_preprocess_filefield_sources_element | Theme the display of the source element. |
_filefield_sources_enabled | Helper to return enabled sources for a field. |
_filefield_sources_sort | Custom sort function for ordering sources. |