first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
<?php
/**
* @file
* Administrative interface for file type configuration.
*/
/**
* Displays the file type admin overview page.
*/
function file_entity_list_types_page() {
$types = file_info_file_types();
$entity_info = entity_get_info('file');
$field_ui = module_exists('field_ui');
$header = array(
array('data' => t('Name')),
array('data' => t('Operations'), 'colspan' => $field_ui ? '3' : '1'),
);
$rows = array();
foreach ($types as $type => $info) {
$row = array(array('data' => theme('file_entity_file_type_overview', $info)));
$path = isset($entity_info['bundles'][$type]['admin']['real path']) ? $entity_info['bundles'][$type]['admin']['real path'] : NULL;
if ($field_ui) {
$row[] = array('data' => isset($path) ? l(t('manage fields'), $path . '/fields') : '');
$row[] = array('data' => isset($path) ? l(t('manage display'), $path . '/display') : '');
}
$row[] = array('data' => isset($path) ? l(t('manage file display'), $path . '/file-display') : '');
$rows[] = $row;
}
$build['file_type_table'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => t('No file types available.'),
);
return $build;
}
/**
* Form callback; presents file display settings for a given view mode.
*/
function file_entity_file_display_form($form, &$form_state, $bundle, $view_mode) {
$file_type = field_extract_bundle('file', $bundle);
$form['#file_type'] = $file_type;
$form['#view_mode'] = $view_mode;
$form['#tree'] = TRUE;
$form['#attached']['js'][] = drupal_get_path('module', 'file_entity') . '/file_entity.admin.js';
// Retrieve available formatters for this file type and load all configured
// filters for existing text formats.
$formatters = file_info_formatter_types();
foreach ($formatters as $name => $formatter) {
if (isset($formatter['file types']) && !in_array($file_type, $formatter['file types'])) {
unset ($formatters[$name]);
}
}
$current_displays = file_displays_load($file_type, $view_mode, TRUE);
foreach ($current_displays as $name => $display) {
$current_displays[$name] = (array) $display;
}
// Formatter status.
$form['displays']['status'] = array(
'#type' => 'item',
'#title' => t('Enabled displays'),
'#prefix' => '<div id="file-displays-status-wrapper">',
'#suffix' => '</div>',
);
$i=0;
foreach ($formatters as $name => $formatter) {
$form['displays']['status'][$name] = array(
'#type' => 'checkbox',
'#title' => $formatter['label'],
'#default_value' => !empty($current_displays[$name]['status']),
'#description' => isset($formatter['description']) ? $formatter['description'] : NULL,
'#parents' => array('displays', $name, 'status'),
'#weight' => $formatter['weight'] + $i/1000,
);
$i++;
}
// Formatter order (tabledrag).
$form['displays']['order'] = array(
'#type' => 'item',
'#title' => t('Display precedence order'),
'#theme' => 'file_entity_file_display_order',
);
foreach ($formatters as $name => $formatter) {
$form['displays']['order'][$name]['label'] = array(
'#markup' => check_plain($formatter['label']),
);
$form['displays']['order'][$name]['weight'] = array(
'#type' => 'weight',
'#title' => t('Weight for @title', array('@title' => $formatter['label'])),
'#title_display' => 'invisible',
'#delta' => 50,
'#default_value' => isset($current_displays[$name]['weight']) ? $current_displays[$name]['weight'] : 0,
'#parents' => array('displays', $name, 'weight'),
);
$form['displays']['order'][$name]['#weight'] = $form['displays']['order'][$name]['weight']['#default_value'];
}
// Formatter settings.
$form['display_settings_title'] = array(
'#type' => 'item',
'#title' => t('Display settings'),
);
$form['display_settings'] = array(
'#type' => 'vertical_tabs',
);
$i=0;
foreach ($formatters as $name => $formatter) {
if (isset($formatter['settings callback']) && ($function = $formatter['settings callback']) && function_exists($function)) {
$defaults = !empty($formatter['default settings']) ? $formatter['default settings'] : array();
$settings = !empty($current_displays[$name]['settings']) ? $current_displays[$name]['settings'] : array();
$settings += $defaults;
$settings_form = $function($form, $form_state, $settings, $name, $file_type, $view_mode);
if (!empty($settings_form)) {
$form['displays']['settings'][$name] = array(
'#type' => 'fieldset',
'#title' => $formatter['label'],
'#parents' => array('displays', $name, 'settings'),
'#group' => 'display_settings',
'#weight' => $formatter['weight'] + $i/1000,
) + $settings_form;
}
}
$i++;
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
return $form;
}
/**
* Process file display settings form submissions.
*/
function file_entity_file_display_form_submit($form, &$form_state) {
$file_type = $form['#file_type'];
$view_mode = $form['#view_mode'];
$displays = isset($form_state['values']['displays']) ? $form_state['values']['displays'] : array();
$displays_original = file_displays_load($file_type, $view_mode, TRUE);
foreach ($displays as $formatter_name => $display) {
$display_original = isset($displays_original[$formatter_name]) ? $displays_original[$formatter_name] : file_display_new($file_type, $view_mode, $formatter_name);
$display += (array) $display_original;
file_display_save((object) $display);
}
drupal_set_message(t('Your settings have been saved.'));
}
/**
* Returns HTML for a file type label and description for the file type admin overview page.
*/
function theme_file_entity_file_type_overview($variables) {
return check_plain($variables['label']) . '<div class="description">' . $variables['description'] . '</div>';
}
/**
* Returns HTML for a file display's display order table.
*/
function theme_file_entity_file_display_order($variables) {
$element = $variables['element'];
$rows = array();
foreach (element_children($element, TRUE) as $name) {
$element[$name]['weight']['#attributes']['class'][] = 'file-display-order-weight';
$rows[] = array(
'data' => array(
drupal_render($element[$name]['label']),
drupal_render($element[$name]['weight']),
),
'class' => array('draggable'),
);
}
$output = drupal_render_children($element);
$output .= theme('table', array('rows' => $rows, 'attributes' => array('id' => 'file-displays-order')));
drupal_add_tabledrag('file-displays-order', 'order', 'sibling', 'file-display-order-weight', NULL, NULL, TRUE);
return $output;
}

View File

@@ -0,0 +1,45 @@
(function ($) {
Drupal.behaviors.fileDisplayStatus = {
attach: function (context, settings) {
$('#file-displays-status-wrapper input.form-checkbox', context).once('display-status', function () {
var $checkbox = $(this);
// Retrieve the tabledrag row belonging to this display.
var $row = $('#' + $checkbox.attr('id').replace(/-status$/, '-weight'), context).closest('tr');
// Retrieve the vertical tab belonging to this display.
var tab = $('#' + $checkbox.attr('id').replace(/-status$/, '-settings'), context).data('verticalTab');
// Bind click handler to this checkbox to conditionally show and hide the
// display's tableDrag row and vertical tab pane.
$checkbox.bind('click.displayStatusUpdate', function () {
if ($checkbox.is(':checked')) {
$row.show();
if (tab) {
tab.tabShow().updateSummary();
}
}
else {
$row.hide();
if (tab) {
tab.tabHide().updateSummary();
}
}
// Restripe table after toggling visibility of table row.
Drupal.tableDrag['file-displays-order'].restripeTable();
});
// Attach summary for configurable displays (only for screen-readers).
if (tab) {
tab.fieldset.drupalSetSummary(function (tabContext) {
return $checkbox.is(':checked') ? Drupal.t('Enabled') : Drupal.t('Disabled');
});
}
// Trigger our bound click handler to update elements to initial state.
$checkbox.triggerHandler('click.displayStatusUpdate');
});
}
};
})(jQuery);

View File

@@ -0,0 +1,140 @@
<?php
/**
* @file
* Hooks provided by the File Entity module.
*/
/**
* Define file types.
*
* @return
* An array whose keys are file type names and whose values are arrays
* describing the file type, with the following key/value pairs:
* - label: The human-readable name of the file type.
* - claim callback: The name of the function that returns if a given file is
* of this type. See hook_file_type_TYPE_claim() for details.
* - default view callback: (optional) The name of the function that returns a
* drupal_render() array for displaying the file. Used when there are no
* administrator configured file formatters, or none of the configured ones
* return a display. See hook_file_type_TYPE_default_view() for details.
* - description: (optional) A short description of the file type.
* - weight: (optional) A number defining the order in which the 'claim
* callback' function for this type is called relative to the claim
* callbacks of other defined types, when the type of a file needs to be
* determined. The type with the lowest weighted claim callback to return
* TRUE is assigned to the file. Also, on administrative pages listing file
* types, the types are ordered by weight.
* - admin: (optional) An array of information, to be added to the
* ['bundles'][TYPE]['admin'] entry for the 'file' entity type, thereby
* controlling the path at which Field UI pages are attached for this file
* type, and which users may access them. Defaults to attaching the Field UI
* pages to the admin/config/media/file-types/manage/TYPE path and requiring
* 'administer site configuration' permission. See hook_entity_info() for
* details about this array. This value can also be set to NULL to suppress
* Field UI pages from attaching at all for this file type.
*
* @see hook_file_type_info_alter()
*/
function hook_file_type_info() {
return array(
'image' => array(
'label' => t('Image'),
),
);
}
/**
* Perform alterations on file types.
*
* @param $info
* Array of information on file types exposed by hook_file_type_info()
* implementations.
*/
function hook_file_type_info_alter(&$info) {
// @todo Add example.
}
/**
* @todo Add documentation.
*
* Note: This is not really a hook. The function name is manually specified via
* 'claim callback' in hook_file_type_info(), with this recommended
* callback name pattern.
*/
function hook_file_type_TYPE_claim($file, $type) {
}
/**
* @todo Add documentation.
*
* Note: This is not really a hook. The function name is manually specified via
* 'default view callback' in hook_file_type_info(), with this recommended
* callback name pattern.
*/
function hook_file_type_TYPE_default_view($file, $view_mode, $langcode) {
}
/**
* Define file formatters.
*
* @return
* An array whose keys are file formatter names and whose values are arrays
* describing the formatter.
*
* @todo Document key/value pairs that comprise a formatter.
*
* @see hook_file_formatter_info_alter()
*/
function hook_file_formatter_info() {
// @todo Add example.
}
/**
* Perform alterations on file formatters.
*
* @param $info
* Array of information on file formatters exposed by
* hook_file_formatter_info() implementations.
*/
function hook_file_formatter_info_alter(&$info) {
// @todo Add example.
}
/**
* @todo Add documentation.
*
* Note: This is not really a hook. The function name is manually specified via
* 'view callback' in hook_file_formatter_info(), with this recommended callback
* name pattern.
*/
function hook_file_formatter_FORMATTER_view($file, $display, $langcode) {
}
/**
* @todo Add documentation.
*
* Note: This is not really a hook. The function name is manually specified via
* 'settings callback' in hook_file_formatter_info(), with this recommended
* callback name pattern.
*/
function hook_file_formatter_FORMATTER_settings($form, &$form_state, $settings) {
}
/**
* @todo Add documentation.
*/
function hook_file_displays_alter($displays, $file, $view_mode) {
}
/**
* @todo Add documentation.
*/
function hook_file_view($file, $view_mode, $langcode) {
}
/**
* @todo Add documentation.
*/
function hook_file_view_alter($build, $type) {
}

View File

@@ -0,0 +1,391 @@
<?php
/**
* @file
* API extensions of Drupal core's file.inc.
*/
/**
* The {file_managed}.type value when the file type has not yet been determined.
*/
define('FILE_TYPE_NONE', 'undefined');
/**
* Returns information about file types from hook_file_type_info().
*
* @param $file_type
* (optional) A file type name. If ommitted, all file types will be returned.
*
* @return
* Either a file type description, as provided by hook_file_type_info(), or an
* array of all existing file types, keyed by file type name.
*/
function file_info_file_types($file_type = NULL) {
$info = &drupal_static(__FUNCTION__);
if (!isset($info)) {
$info = module_invoke_all('file_type_info');
drupal_alter('file_type_info', $info);
_file_sort_array_by_weight($info);
}
if (isset($file_type)) {
if (isset($info[$file_type])) {
return $info[$file_type];
}
}
else {
return $info;
}
}
/**
* Returns an object with file type information, so that %file_type can be used in hook_menu() paths.
*
* In addition to the information returned by file_info_file_types(), the 'type'
* property is set for use by field_extract_bundle().
*/
function file_type_load($type) {
$info = file_info_file_types($type);
if (isset($info)) {
$info = (object) $info;
$info->type = $type;
return $info;
}
else {
return FALSE;
}
}
/**
* Determines the file type of a passed in file object.
*/
function file_get_type($file) {
foreach (file_info_file_types() as $type => $info) {
if (isset($info['claim callback']) && ($function = $info['claim callback']) && function_exists($function) && $function($file, $type)) {
return $type;
}
}
}
/**
* Returns information about file formatters from hook_file_formatter_info().
*
* @param $formatter_type
* (optional) A file formatter type name. If ommitted, all file formatter
* will be returned.
*
* @return
* Either a file formatter description, as provided by
* hook_file_formatter_info(), or an array of all existing file formatters,
* keyed by formatter type name.
*/
function file_info_formatter_types($formatter_type = NULL) {
$info = &drupal_static(__FUNCTION__);
if (!isset($info)) {
$info = module_invoke_all('file_formatter_info');
drupal_alter('file_formatter_info', $info);
_file_sort_array_by_weight($info);
}
if ($formatter_type) {
if (isset($info[$formatter_type])) {
return $info[$formatter_type];
}
}
else {
return $info;
}
}
/**
* Clears the file info cache.
*/
function file_info_cache_clear() {
drupal_static_reset('file_info_file_types');
drupal_static_reset('file_info_formatter_types');
}
/**
* Construct a drupal_render() style array from an array of loaded files.
*
* @param $files
* An array of files as returned by file_load_multiple().
* @param $view_mode
* View mode.
* @param $weight
* An integer representing the weight of the first file in the list.
* @param $langcode
* A string indicating the language field values are to be shown in. If no
* language is provided the current content language is used.
*
* @return
* An array in the format expected by drupal_render().
*/
function file_view_multiple($files, $view_mode = 'default', $weight = 0, $langcode = NULL) {
if (empty($files)) {
return array();
}
field_attach_prepare_view('file', $files, $view_mode);
entity_prepare_view('file', $files);
$build = array();
foreach ($files as $file) {
$build[$file->fid] = file_view($file, $view_mode, $langcode);
$build[$file->fid]['#weight'] = $weight;
$weight++;
}
$build['#sorted'] = TRUE;
return $build;
}
/**
* Generate an array for rendering the given file.
*
* @param $file
* A file object.
* @param $view_mode
* View mode.
* @param $langcode
* (optional) A language code to use for rendering. Defaults to the global
* content language of the current request.
*
* @return
* An array as expected by drupal_render().
*/
function file_view($file, $view_mode = 'default', $langcode = NULL) {
if (!isset($langcode)) {
$langcode = $GLOBALS['language_content']->language;
}
// Prepare the file object for viewing, in case file_view() was called by
// something other than file_view_multiple(). These functions exit quickly if
// they've already run, so it's okay to call them even if they've already been
// called by file_view_multiple().
field_attach_prepare_view('file', array($file->fid => $file), $view_mode);
entity_prepare_view('file', array($file->fid => $file));
// Create the render array with the file itself and with fields.
$build = array(
'#file' => $file,
'#view_mode' => $view_mode,
'#language' => $langcode,
);
$build += field_attach_view('file', $file, $view_mode, $langcode);
$build['file'] = file_view_file($file, $view_mode, $langcode);
// Allow modules to add and alter.
module_invoke_all('file_view', $file, $view_mode, $langcode);
module_invoke_all('entity_view', $file, 'file', $view_mode, $langcode);
$type = 'file';
drupal_alter(array('file_view', 'entity_view'), $build, $type);
return $build;
}
/**
* Generate an array for rendering just the file portion of a file entity.
*
* @param $file
* A file object.
* @param $displays
* Can be either:
* - the name of a view mode;
* - or an array of custom display settings, as returned by file_displays().
* @param $langcode
* (optional) A language code to use for rendering. Defaults to the global
* content language of the current request.
*
* @return
* An array as expected by drupal_render().
*/
function file_view_file($file, $displays = 'default', $langcode = NULL) {
if (!isset($langcode)) {
$langcode = $GLOBALS['language_content']->language;
}
// Prepare incoming display specifications.
if (is_string($displays)) {
$view_mode = $displays;
$displays = file_displays($file->type, $view_mode);
}
else {
$view_mode = '_custom_display';
}
drupal_alter('file_displays', $displays, $file, $view_mode);
_file_sort_array_by_weight($displays);
// Attempt to display the file with each of the possible displays. Stop after
// the first successful one. See file_displays() for details.
$element = NULL;
foreach ($displays as $formatter_type => $display) {
if (!empty($display['status'])) {
$formatter_info = file_info_formatter_types($formatter_type);
// Under normal circumstances, the UI prevents enabling formatters for
// incompatible file types. In case this was somehow circumvented (for
// example, a module updated its formatter definition without updating
// existing display settings), perform an extra check here.
if (isset($formatter_info['file types']) && !in_array($file->type, $formatter_info['file types'])) {
continue;
}
if (isset($formatter_info['view callback']) && ($function = $formatter_info['view callback']) && function_exists($function)) {
$display['type'] = $formatter_type;
if (!empty($formatter_info['default settings'])) {
if (empty($display['settings'])) {
$display['settings'] = array();
}
$display['settings'] += $formatter_info['default settings'];
}
$element = $function($file, $display, $langcode);
if (isset($element)) {
break;
}
}
}
}
// If none of the configured formatters were able to display the file, attempt
// to display the file using the file type's default view callback.
if (!isset($element)) {
$file_type_info = file_info_file_types($file->type);
if (isset($file_type_info['default view callback']) && ($function = $file_type_info['default view callback']) && function_exists($function)) {
$element = $function($file, $view_mode, $langcode);
}
}
// If a render element was returned by a formatter or the file type's default
// view callback, add some defaults to it and return it.
if (isset($element)) {
$element += array(
'#file' => $file,
'#view_mode' => $view_mode,
'#language' => $langcode,
);
return $element;
}
}
/**
* Returns an array of possible displays to use for a file type in a given view mode.
*
* It is common for a site to be configured with broadly defined file types
* (e.g., 'video'), and to have different files of this type require different
* displays (for example, the code required to display a YouTube video is
* different than the code required to display a local QuickTime video).
* Therefore, the site administrator can configure multiple displays for a given
* file type. This function returns all of the displays that the administrator
* enabled for the given file type in the given view mode. file_view_file() then
* invokes each of these, and passes the specific file to display. Each display
* implementation can inspect the file, and either return a render array (if it
* is capable of displaying the file), or return nothing (if it is incapable of
* displaying the file). The first render array returned is the one used.
*
* @param $file_type
* The type of file.
* @param $view_mode
* The view mode.
*
* @return
* An array keyed by the formatter type name. Each item in the array contains
* the following key/value pairs:
* - status: Whether this display is enabled. If not TRUE, file_view_file()
* skips over it.
* - weight: An integer that determines the order of precedence within the
* returned array. The lowest weight display capable of displaying the file
* is used.
* - settings: An array of key/value pairs specific to the formatter type. See
* hook_file_formatter_info() for details.
*
* @see hook_file_formatter_info()
* @see file_view_file()
*/
function file_displays($file_type, $view_mode = 'default') {
$cache = &drupal_static(__FUNCTION__, array());
// If the requested view mode isn't configured to use a custom display for its
// fields, then don't use a custom display for its file either.
if ($view_mode != 'default') {
$view_mode_settings = field_view_mode_settings('file', $file_type);
$view_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default';
}
if (!isset($cache[$file_type][$view_mode])) {
// Load the display configurations for the file type and view mode. If none
// exist for the view mode, use the default view mode.
$displays = file_displays_load($file_type, $view_mode, TRUE);
if (empty($displays) && $view_mode != 'default') {
$cache[$file_type][$view_mode] = file_displays($file_type, 'default');
}
else {
// Convert the display objects to arrays and remove unnecessary keys.
foreach ($displays as $formatter_name => $display) {
$displays[$formatter_name] = array_intersect_key((array) $display, drupal_map_assoc(array('status', 'weight', 'settings')));
}
$cache[$file_type][$view_mode] = $displays;
}
}
return $cache[$file_type][$view_mode];
}
/**
* Returns an array of {file_display} objects for the file type and view mode.
*/
function file_displays_load($file_type, $view_mode, $key_by_formatter_name = FALSE) {
ctools_include('export');
$display_names = array();
$prefix = $file_type . '__' . $view_mode . '__';
foreach (array_keys(file_info_formatter_types()) as $formatter_name) {
$display_names[] = $prefix . $formatter_name;
}
$displays = ctools_export_load_object('file_display', 'names', $display_names);
if ($key_by_formatter_name) {
$prefix_length = strlen($prefix);
$rekeyed_displays = array();
foreach ($displays as $name => $display) {
$rekeyed_displays[substr($name, $prefix_length)] = $display;
}
$displays = $rekeyed_displays;
}
return $displays;
}
/**
* Saves a {file_display} object to the database.
*/
function file_display_save($display) {
ctools_include('export');
ctools_export_crud_save('file_display', $display);
}
/**
* Creates a new {file_display} object.
*/
function file_display_new($file_type, $view_mode, $formatter_name) {
ctools_include('export');
$display = ctools_export_crud_new('file_display');
$display->name = implode('__', array($file_type, $view_mode, $formatter_name));
return $display;
}
/**
* Helper function to sort an array by the value of each item's 'weight' key, while preserving relative order of items that have equal weight.
*/
function _file_sort_array_by_weight(&$a) {
$i=0;
foreach ($a as $key => $item) {
if (!isset($a[$key]['weight'])) {
$a[$key]['weight'] = 0;
}
$original_weight[$key] = $a[$key]['weight'];
$a[$key]['weight'] += $i/1000;
$i++;
}
uasort($a, 'drupal_sort_weight');
foreach ($a as $key => $item) {
$a[$key]['weight'] = $original_weight[$key];
}
}

View File

@@ -0,0 +1,13 @@
name = File entity
description = "Extends Drupal file entities to be fieldable and viewable."
package = Media
core = 7.x
dependencies[] = field
dependencies[] = ctools
; Information added by drupal.org packaging script on 2012-03-23
version = "7.x-1.0"
core = "7.x"
project = "media"
datestamp = "1332537952"

View File

@@ -0,0 +1,207 @@
<?php
/**
* @file
* Install, update and uninstall functions for the file_entity module.
*/
/**
* Implements hook_schema().
*/
function file_entity_schema() {
$schema['file_display'] = array(
'description' => 'Stores configuration options for file displays.',
'fields' => array(
// @todo Can be refactored as a compond primary key after
// http://drupal.org/node/924236 is implemented.
'name' => array(
'description' => 'A combined string (FILE_TYPE__VIEW_MODE__FILE_FORMATTER) identifying a file display configuration. For integration with CTools Exportables, stored as a single string rather than as a compound primary key.',
'type' => 'varchar',
'length' => '255',
'not null' => TRUE,
),
'weight' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'Weight of formatter within the display chain for the associated file type and view mode. A file is rendered using the lowest weighted enabled display configuration that matches the file type and view mode and that is capable of displaying the file.',
),
'status' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'The status of the display. (1 = enabled, 0 = disabled)',
),
'settings' => array(
'type' => 'blob',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of name value pairs that store the formatter settings for the display.',
),
),
'primary key' => array('name'),
// Exportable support via CTools.
'export' => array(
'key' => 'name',
'key name' => 'Name',
'primary key' => 'name',
// The {file_display}.status field is used to control whether the display
// is active in the display chain. CTools-level disabling is something
// different, and it's not yet clear how to interpret it for file displays.
// Until that's figured out, prevent CTools-level disabling.
'can disable' => FALSE,
'default hook' => 'file_default_displays',
'identifier' => 'file_display',
'api' => array(
'owner' => 'file_entity',
'api' => 'file_default_displays',
'minimum_version' => 1,
'current_version' => 1,
),
),
);
return $schema;
}
/**
* Implements hook_schema_alter().
*/
function file_entity_schema_alter(&$schema) {
$schema['file_managed']['fields']['type'] = array(
'description' => 'The type of this file.',
'type' => 'varchar',
'length' => 50,
'not null' => TRUE,
// If the FILE_TYPE_NONE constant ever changes, then change the value here
// too, and add an update function to deal with existing records. The
// constant isn't used here, because there may be cases where this function
// runs without the module file loaded.
'default' => 'undefined',
);
$schema['file_managed']['indexes']['file_type'] = array('type');
}
/**
* Implements hook_install().
*/
function file_entity_install() {
$schema = array();
file_entity_schema_alter($schema);
$spec = $schema['file_managed']['fields']['type'];
$indexes_new = array('indexes' => $schema['file_managed']['indexes']);
// If another module (e.g., Media) had added a {file_managed}.type field,
// then change it to the expected specification. Otherwise, add the field.
if (db_field_exists('file_managed', 'type')) {
// db_change_field() will fail if any records have type=NULL, so update
// them to the new default value.
db_update('file_managed')->fields(array('type' => $spec['default']))->isNull('type')->execute();
// Indexes using a field being changed must be dropped prior to calling
// db_change_field(). However, the database API doesn't provide a way to do
// this without knowing what the old indexes are. Therefore, it is the
// responsibility of the module that added them to drop them prior to
// allowing this module to be installed.
db_change_field('file_managed', 'type', 'type', $spec, $indexes_new);
}
else {
db_add_field('file_managed', 'type', $spec, $indexes_new);
}
}
/**
* Implements hook_uninstall().
*/
function file_entity_uninstall() {
db_drop_field('file_managed', 'type');
}
/**
* Create the {file_display} database table.
*/
function file_entity_update_7000() {
$schema['file_display'] = array(
'description' => 'Stores configuration options for file displays.',
'fields' => array(
'name' => array(
'description' => 'A combined string (FILE_TYPE__VIEW_MODE__FILE_FORMATTER) identifying a file display configuration. For integration with CTools Exportables, stored as a single string rather than as a compound primary key.',
'type' => 'varchar',
'length' => '255',
'not null' => TRUE,
),
'weight' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'Weight of formatter within the display chain for the associated file type and view mode. A file is rendered using the lowest weighted enabled display configuration that matches the file type and view mode and that is capable of displaying the file.',
),
'status' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'The status of the display. (1 = enabled, 0 = disabled)',
),
'settings' => array(
'type' => 'blob',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of name value pairs that store the formatter settings for the display.',
),
),
'primary key' => array('name'),
);
db_create_table('file_display', $schema['file_display']);
}
/**
* Move file display configurations from the 'file_displays' variable to the
* {file_display} database table.
*/
function file_entity_update_7001() {
$file_displays = variable_get('file_displays');
if (!empty($file_displays)) {
foreach ($file_displays as $file_type => $file_type_displays) {
if (!empty($file_type_displays)) {
foreach ($file_type_displays as $view_mode => $view_mode_displays) {
if (!empty($view_mode_displays)) {
foreach ($view_mode_displays as $formatter_name => $display) {
if (!empty($display)) {
db_merge('file_display')
->key(array(
'name' => implode('__', array($file_type, $view_mode, $formatter_name)),
))
->fields(array(
'status' => isset($display['status']) ? $display['status'] : 0,
'weight' => isset($display['weight']) ? $display['weight'] : 0,
'settings' => isset($display['settings']) ? serialize($display['settings']) : NULL,
))
->execute();
}
}
}
}
}
}
}
variable_del('file_displays');
}
/**
* Drupal 7.8 disallows empty string as the value for a bundle key, so update
* empty {file_managed}.type records to 'undefined' instead.
*/
function file_entity_update_7002() {
db_update('file_managed')
// Using 'undefined' instead of FILE_TYPE_NONE, because update functions can
// run for disabled modules.
->fields(array('type' => 'undefined'))
->condition('type', '')
->execute();
}

View File

@@ -0,0 +1,467 @@
<?php
/**
* @file
* Extends Drupal file entities to be fieldable and viewable.
*/
/**
* 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';
/**
* Implements hook_help().
*/
function file_entity_help($path, $arg) {
switch ($path) {
case 'admin/config/media/file-types':
$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;
}
}
/**
* Implements hook_menu().
*/
function file_entity_menu() {
$items['admin/config/media/file-types'] = array(
'title' => 'File types',
'description' => 'Manage files used on your site.',
'page callback' => 'file_entity_list_types_page',
'access arguments' => array('administer site configuration'),
'file' => 'file_entity.admin.inc',
);
$items['admin/config/media/file-types/manage/%'] = array(
'title' => 'Manage file types',
'description' => 'Manage files used on your site.',
);
// 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',
'access arguments' => array('administer site configuration'),
);
// 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;
// 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']),
);
}
}
}
return $items;
}
/**
* Implements hook_theme().
*/
function file_entity_theme() {
return array(
'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',
),
);
}
/**
* Implements hook_entity_info_alter().
*
* Extends the core file entity to be fieldable. Modules can define file types
* via hook_file_type_info(). For each defined type, create a bundle, so that
* fields can be configured per file type.
*/
function file_entity_entity_info_alter(&$entity_info) {
$entity_info['file']['fieldable'] = TRUE;
$entity_info['file']['entity keys']['bundle'] = 'type';
$entity_info['file']['bundle keys']['bundle'] = 'type';
$entity_info['file']['bundles'] = array();
foreach (file_info_file_types() as $type => $info) {
$info += array(
// Provide a default administration path for Field UI, but not if 'admin'
// has been explicitly set to NULL.
'admin' => array(
'path' => 'admin/config/media/file-types/manage/%file_type',
'real path' => 'admin/config/media/file-types/manage/' . $type,
'bundle argument' => 5,
),
);
$entity_info['file']['bundles'][$type] = array_intersect_key($info, drupal_map_assoc(array('label', 'admin')));
}
}
/**
* 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() {
$return = array();
$info = entity_get_info('file');
foreach (array_keys($info['bundles']) as $bundle) {
$return['file'][$bundle] = array(
'form' => array(
'file' => array(
'label' => t('File'),
'description' => t('File preview'),
'weight' => 0,
),
),
'display' => array(
'file' => array(
'label' => t('File'),
'description' => t('File display'),
'weight' => 0,
),
),
);
}
return $return;
}
/**
* Implements hook_file_presave().
*/
function file_entity_file_presave($file) {
// The file type is a bundle key, so can't be NULL. file_entity_schema_alter()
// ensures that it isn't NULL after a file_load(). However, file_save() can be
// called on a new file object, so we apply the default here as well.
if (!isset($file->type)) {
$file->type = FILE_TYPE_NONE;
}
// If the file doesn't already have a real type, attempt to assign it one.
if ($file->type == FILE_TYPE_NONE && ($type = file_get_type($file))) {
$file->type = $type;
}
field_attach_presave('file', $file);
}
/**
* Implements hook_file_insert().
*/
function file_entity_file_insert($file) {
field_attach_insert('file', $file);
}
/**
* Implement hook_file_update().
*/
function file_entity_file_update($file) {
field_attach_update('file', $file);
}
/**
* Implements hook_file_delete().
*/
function file_entity_file_delete($file) {
field_attach_delete('file', $file);
}
/**
* 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.
if (module_exists('file')) {
foreach (field_info_formatter_types() as $field_formatter_type => $field_formatter_info) {
if (in_array('file', $field_formatter_info['field types'])) {
$formatters['file_field_' . $field_formatter_type] = array(
'label' => $field_formatter_info['label'],
'view callback' => 'file_entity_file_formatter_file_field_view',
);
if (isset($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',
);
}
}
}
}
// Add a simple file formatter for displaying an image in a chosen style.
if (module_exists('image')) {
$formatters['file_image'] = array(
'label' => t('Image'),
'default settings' => array('image_style' => ''),
'view callback' => 'file_entity_file_formatter_file_image_view',
'settings callback' => 'file_entity_file_formatter_file_image_settings',
);
}
return $formatters;
}
/**
* Implements hook_file_formatter_FORMATTER_view().
*
* This function provides a bridge to the field formatter API, so that file
* field formatters can be reused for displaying the file entity's file
* pseudo-field.
*/
function file_entity_file_formatter_file_field_view($file, $display, $langcode) {
if (strpos($display['type'], 'file_field_') === 0) {
$field_formatter_type = substr($display['type'], strlen('file_field_'));
$field_formatter_info = field_info_formatter_types($field_formatter_type);
if (isset($field_formatter_info['module'])) {
// Set $display['type'] to what hook_field_formatter_*() expects.
$display['type'] = $field_formatter_type;
// Set $items to what file field formatters expect. See file_field_load(),
// and note that, here, $file is already a fully loaded entity.
$items = array((array) $file);
// Invoke hook_field_formatter_prepare_view() and
// hook_field_formatter_view(). Note that we are reusing field formatter
// functions, but we are not displaying a Field API field, so we set
// $field and $instance accordingly, and do not invoke
// hook_field_prepare_view(). This assumes that the formatter functions do
// not rely on $field or $instance. A module that implements formatter
// functions that rely on $field or $instance (and therefore, can only be
// used for real fields) can prevent this formatter from being used on the
// pseudo-field by removing it within hook_file_formatter_info_alter().
$field = $instance = NULL;
if (($function = ($field_formatter_info['module'] . '_field_formatter_prepare_view')) && function_exists($function)) {
$fid = $file->fid;
// hook_field_formatter_prepare_view() alters $items by reference.
$grouped_items = array($fid => &$items);
$function('file', array($fid => $file), $field, array($fid => $instance), $langcode, $grouped_items, array($fid => $display));
}
if (($function = ($field_formatter_info['module'] . '_field_formatter_view')) && function_exists($function)) {
$element = $function('file', $file, $field, $instance, $langcode, $items, $display);
// We passed the file as $items[0], so return the corresponding element.
if (isset($element[0])) {
return $element[0];
}
}
}
}
}
/**
* Implements hook_file_formatter_FORMATTER_settings().
*
* This function provides a bridge to the field formatter API, so that file
* field formatters can be reused for displaying the file entity's file
* pseudo-field.
*/
function file_entity_file_formatter_file_field_settings($form, &$form_state, $settings, $formatter_type, $file_type, $view_mode) {
if (strpos($formatter_type, 'file_field_') === 0) {
$field_formatter_type = substr($formatter_type, strlen('file_field_'));
$field_formatter_info = field_info_formatter_types($field_formatter_type);
// Invoke hook_field_formatter_settings_form(). We are reusing field
// formatter functions, but we are not working with a Field API field, so
// set $field accordingly. Unfortunately, the API is for $settings to be
// transfered via the $instance parameter, so we must mock it.
if (isset($field_formatter_info['module']) && ($function = ($field_formatter_info['module'] . '_field_formatter_settings_form')) && function_exists($function)) {
$field = NULL;
$mock_instance['display'][$view_mode] = array(
'type' => $field_formatter_type,
'settings' => $settings,
);
return $function($field, $mock_instance, $view_mode, $form, $form_state);
}
}
}
/**
* Implements hook_file_formatter_FORMATTER_view().
*
* Returns a drupal_render() array to display an image of the chosen style.
*
* This formatter is only capable of displaying local images. If the passed in
* file is either not local or not an image, nothing is returned, so that
* file_view_file() can try another formatter.
*/
function file_entity_file_formatter_file_image_view($file, $display, $langcode) {
// Prevent PHP notices when trying to read empty files.
// @see http://drupal.org/node/681042
if (!filesize($file->uri)) {
return;
}
// Do not bother proceeding if this file does not have an image mime type.
if (strpos($file->filemime, 'image/') !== 0) {
return;
}
if (file_entity_file_is_local($file) && $image = image_load($file->uri)) {
if (!empty($display['settings']['image_style'])) {
$element = array(
'#theme' => 'image_style',
'#style_name' => $display['settings']['image_style'],
'#path' => $file->uri,
'#width' => $image->info['width'],
'#height' => $image->info['height'],
);
}
else {
$element = array(
'#theme' => 'image',
'#path' => $file->uri,
'#width' => $image->info['width'],
'#height' => $image->info['height'],
);
}
return $element;
}
}
/**
* Implements hook_file_formatter_FORMATTER_settings().
*
* Returns form elements for configuring the 'file_image' formatter.
*/
function file_entity_file_formatter_file_image_settings($form, &$form_state, $settings) {
$element = array();
$element['image_style'] = array(
'#title' => t('Image style'),
'#type' => 'select',
'#options' => image_style_options(FALSE),
'#default_value' => $settings['image_style'],
'#empty_option' => t('None (original image)'),
);
return $element;
}
/**
* Menu access callback for the 'view mode file display settings' pages.
*
* Based on _field_ui_view_mode_menu_access(), but the Field UI module might not
* be enabled.
*/
function _file_entity_view_mode_menu_access($bundle, $view_mode, $access_callback) {
// Deny access if the view mode isn't configured to use custom display
// settings.
$file_type = field_extract_bundle('file', $bundle);
$view_mode_settings = field_view_mode_settings('file', $file_type);
$visibility = ($view_mode == 'default') || !empty($view_mode_settings[$view_mode]['custom_settings']);
if (!$visibility) {
return FALSE;
}
// Otherwise, continue to an $access_callback check.
$args = array_slice(func_get_args(), 3);
$callback = empty($access_callback) ? 0 : trim($access_callback);
if (is_numeric($callback)) {
return (bool) $callback;
}
elseif (function_exists($access_callback)) {
return call_user_func_array($access_callback, $args);
}
}
/**
* Implements hook_modules_enabled().
*/
function file_entity_modules_enabled($modules) {
file_info_cache_clear();
}
/**
* Implements hook_modules_disabled().
*/
function file_entity_modules_disabled($modules) {
file_info_cache_clear();
}
/**
* Implements hook_file_mimetype_mapping_alter().
*/
function file_entity_file_mimetype_mapping_alter(&$mapping) {
// Fix the mime type mapping for ogg.
// @todo Remove when http://drupal.org/node/1239376 is fixed in core.
$new_mappings['ogg'] = 'audio/ogg';
// Add support for m4v.
// @todo Remove when http://drupal.org/node/1290486 is fixed in core.
$new_mappings['m4v'] = 'video/x-m4v';
// Add support for mka and mkv.
// @todo Remove when http://drupal.org/node/1293140 is fixed in core.
$new_mappings['mka'] = 'audio/x-matroska';
$new_mappings['mkv'] = 'video/x-matroska';
// Add support for weba, webm, and webp.
// @todo Remove when http://drupal.org/node/1347624 is fixed in core.
$new_mappings['weba'] = 'audio/webm';
$new_mappings['webm'] = 'video/webm';
$new_mappings['webp'] = 'image/webp';
foreach ($new_mappings as $extension => $mime_type) {
if (!in_array($mime_type, $mapping['mimetypes'])) {
// If the mime type does not already exist, add it.
$mapping['mimetypes'][] = $mime_type;
}
// Get the index of the mime type and assign the extension to that key.
$index = array_search($mime_type, $mapping['mimetypes']);
$mapping['extensions'][$extension] = $index;
}
}
/**
* Check if a file entity is considered local or not.
*
* @param object $file
* A file entity object from file_load().
*
* @return
* TRUE if the file is using a local stream wrapper, or FALSE otherwise.
*/
function file_entity_file_is_local($file) {
$scheme = file_uri_scheme($file->uri);
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
return !empty($wrappers[$scheme]) && empty($wrappers[$scheme]['remote']);
}

View File

@@ -0,0 +1,13 @@
name = "File Entity Test"
description = "Support module for File Entity tests."
package = Testing
core = 7.x
dependencies[] = file_entity
hidden = TRUE
; Information added by drupal.org packaging script on 2012-03-23
version = "7.x-1.0"
core = "7.x"
project = "media"
datestamp = "1332537952"

View File

@@ -0,0 +1,100 @@
<?php
/**
* @file
* File Entity Test
*/
/**
* Implements hook_menu().
*/
function file_entity_test_menu() {
$items = array();
$items['file-entity-test/file/add'] = array(
'title' => 'Add file',
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_test_add_form'),
'access arguments' => array('administer site configuration'),
'file' => 'file_entity_test.pages.inc',
);
$items['file-entity-test/file/%file'] = array(
'title' => 'View file',
'page callback' => 'file_entity_test_view_page',
'page arguments' => array(2),
'access arguments' => array('administer site configuration'),
'file' => 'file_entity_test.pages.inc',
);
$items['file-entity-test/file/%file/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['file-entity-test/file/%file/preview'] = array(
'title' => 'Preview',
'page callback' => 'file_entity_test_preview_page',
'page arguments' => array(2),
'access arguments' => array('administer site configuration'),
'weight' => 0,
'type' => MENU_LOCAL_TASK,
'file' => 'file_entity_test.pages.inc',
);
$items['file-entity-test/file/%file/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array('file_entity_test_edit_form', 2),
'access arguments' => array('administer site configuration'),
'weight' => 1,
'type' => MENU_LOCAL_TASK,
'file' => 'file_entity_test.pages.inc',
);
return $items;
}
/**
* Implements hook_file_type_info().
*/
function file_entity_test_file_type_info() {
return array(
'file_entity_test' => array(
'label' => t('Test'),
'description' => t('A file type defined by the File Entity Test module. Used for testing only.'),
'claim callback' => 'file_entity_test_file_type_file_entity_test_claim',
'default view callback' => 'file_entity_test_file_type_file_entity_test_default_view',
'weight' => 100,
),
);
}
/**
* Implements hook_file_type_TYPE_claim().
*
* Returns TRUE if the passed in file should be assigned the 'file_entity_test'
* file type.
*/
function file_entity_test_file_type_file_entity_test_claim($file) {
return TRUE;
}
/**
* Implements hook_file_type_TYPE_default_view().
*/
function file_entity_test_file_type_file_entity_test_default_view($file, $view_mode, $langcode) {
return array(
'#type' => 'link',
'#title' => $file->filename,
'#href' => file_create_url($file->uri),
);
}
/**
* Implements hook_entity_info_alter().
*/
function file_entity_test_entity_info_alter(&$entity_info) {
$entity_info['file']['view modes']['file_entity_test_preview'] = array(
'label' => t('Test Preview'),
'custom settings' => TRUE,
);
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* @file
* Test pages for the File Entity Test module.
*/
/**
* Form callback; upload a file.
*/
function file_entity_test_add_form($form, &$form_state) {
$form['file'] = array(
'#type' => 'managed_file',
'#required' => TRUE,
'#title' => 'File',
'#upload_location' => 'public://',
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
* Form submit callback; save the uploaded file.
*/
function file_entity_test_add_form_submit($form, &$form_state) {
$file = file_load($form_state['values']['file']);
if (!$file->status) {
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
drupal_set_message(t('Your file has been saved.'));
$form_state['redirect'] = 'file-entity-test/file/' . $file->fid;
}
/**
* Page callback; view a file.
*/
function file_entity_test_view_page($file) {
return file_view($file, 'default');
}
/**
* Page callback; preview a file.
*/
function file_entity_test_preview_page($file) {
return file_view($file, 'file_entity_test_preview');
}
/**
* Form callback; edit a file.
*/
function file_entity_test_edit_form($form, &$form_state, $file) {
$form_state['file'] = $file;
field_attach_form('file', $file, $form, $form_state);
$form['file'] = file_view($file, 'file_entity_test_preview');
// Add internal file properties needed by
// file_entity_test_edit_form_validate().
foreach (array('fid', 'type') as $key) {
$form[$key] = array('#type' => 'value', '#value' => $file->$key);
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
* Form validation handler for the file edit form.
*/
function file_entity_test_edit_form_validate($form, &$form_state) {
entity_form_field_validate('file', $form, $form_state);
}
/**
* Form submit handler for the file edit form
*/
function file_entity_test_edit_form_submit($form, &$form_state) {
$file = $form_state['file'];
entity_form_submit_build_entity('file', $file, $form, $form_state);
file_save($file);
drupal_set_message(t('Your changes to the file have been saved.'));
$form_state['redirect'] = 'file-entity-test/file/' . $file->fid;
}