filefield_paths.module in File (Field) Paths 5
Same filename and directory in other branches
Adds extra functionality to FileFields Path settings.
File
filefield_paths.moduleView source
<?php
/**
* @file
* Adds extra functionality to FileFields Path settings.
*/
/**
* Implementation of hook_filefield_paths_field_settings().
*/
function filefield_paths_filefield_paths_field_settings() {
return array(
'file_path' => array(
'title' => 'File path',
'sql' => 'filepath',
),
'file_name' => array(
'title' => 'File name',
'sql' => 'filename',
'form' => array(
'file_name' => array(
'#type' => 'textfield',
'#title' => t('File name'),
'#default_value' => '[filefield-onlyname-original].[filefield-extension-original]',
),
),
),
);
}
function theme_filefield_paths_token_help($prefix = '[', $suffix = ']') {
token_include();
$full_list = array_merge(filefield_paths_token_list(), token_get_list('node'));
if (function_exists('filefield_token_list')) {
$temp_tokens = filefield_token_list();
$full_list['file'] = array_merge($temp_tokens['file'], $full_list['file']);
}
$headers = array(
t('Token'),
t('Replacement value'),
);
$rows = array();
foreach ($full_list as $key => $category) {
$rows[] = array(
array(
'data' => drupal_ucfirst($key) . ' ' . t('tokens'),
'class' => 'region',
'colspan' => 2,
),
);
foreach ($category as $token => $description) {
$row = array();
$row[] = $prefix . $token . $suffix;
$row[] = $description;
$rows[] = $row;
}
}
$output = theme('table', $headers, $rows, array(
'class' => 'description',
));
return $output;
}
/**
* Implementation of hook_init().
*/
function filefield_paths_init() {
foreach (module_list() as $module) {
if (file_exists($file = drupal_get_path('module', 'filefield_paths') . '/modules/' . $module . '.inc')) {
require_once $file;
}
}
}
/**
* Implementation of hook_form_alter().
*/
function filefield_paths_form_alter($form_id, &$form) {
$ffp = array();
// Invoke hook_filefield_paths_form_alter().
foreach (module_implements('filefield_paths_form_alter') as $module) {
$function = $module . '_filefield_paths_form_alter';
$function($form, $ffp);
}
// If supporting module enabled, show FileField Paths settings form.
if (count($ffp) > 0) {
$fields = module_invoke_all('filefield_paths_field_settings');
foreach ($ffp as $field_name => $field_data) {
$result = db_fetch_object(db_query("SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'", $field_data['type'], $field_name));
if (!empty($result)) {
foreach ($fields as &$field) {
$field['settings'] = unserialize($result->{$field}['sql']);
}
unset($field);
}
$count = 0;
foreach ($fields as $name => $field) {
$count++;
if (isset($field['form']) && is_array($field['form'])) {
$keys = array_keys($field['form']);
for ($i = 1; $i < count($field['form']); $i++) {
$field['form'][$keys[$i]]['#weight'] = ($count - 1) * 3 + 2 + $i;
}
unset($keys);
$field_data['form_path'] = array_merge($field_data['form_path'], $field['form']);
}
$name = isset($field_data['form_path'][$name]) ? $name : 'image_path';
$field_data['form_path']['#tree'] = TRUE;
$field_data['form_path'][$name]['#weight'] = ($count - 1) * 3;
// Set defualt value for patterns.
if (isset($field['settings']['value'])) {
$field_data['form_path'][$name]['#default_value'] = $field['settings']['value'];
if (isset($field['data'])) {
foreach ($field['data'] as $key => $value) {
$field_data['form_path'][$value]['#default_value'] = $field['settings'][$key];
}
}
}
$field_data['form_path'][$name . '_cleanup'] = array(
'#type' => 'fieldset',
'#title' => t('!title cleanup settings', array(
'!title' => $field['title'],
)),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => ($count - 1) * 3 + 1,
'#attributes' => array(
'class' => $name . ' cleanup',
),
);
// Cleanup field with Pathauto module.
$field_data['form_path'][$name . '_cleanup'][$name . '_pathauto'] = array(
'#type' => 'checkbox',
'#title' => t('Cleanup using Pathauto') . '.',
'#default_value' => isset($field['settings']['pathauto']) ? $field['settings']['pathauto'] : 0,
'#description' => t('Cleanup !title using !url', array(
'!title' => $field['title'],
'!url' => l(t('Pathauto settings'), 'admin/build/path/pathauto'),
)),
);
if (!module_exists('pathauto')) {
$field_data['form_path'][$name . '_cleanup'][$name . '_pathauto']['#disabled'] = TRUE;
$field_data['form_path'][$name . '_cleanup'][$name . '_pathauto']['#default_value'] = 0;
}
// Convert field to lower case.
$field_data['form_path'][$name . '_cleanup'][$name . '_tolower'] = array(
'#type' => 'checkbox',
'#title' => t('Convert to lower case') . '.',
'#default_value' => isset($field['settings']['tolower']) ? $field['settings']['tolower'] : 0,
'#description' => t('Convert !title to lower case', array(
'!title' => $field['title'],
)) . '.',
);
// Transliterate field with Transliteration module.
$field_data['form_path'][$name . '_cleanup'][$name . '_transliterate'] = array(
'#type' => 'checkbox',
'#title' => t('Transliterate') . '.',
'#default_value' => isset($field['settings']['transliterate']) ? $field['settings']['transliterate'] : 0,
'#description' => t('Transliterate !title', array(
'!title' => $field['title'],
)) . '.',
);
if (!module_exists('transliteration')) {
$field_data['form_path'][$name . '_cleanup'][$name . '_transliterate']['#disabled'] = TRUE;
$field_data['form_path'][$name . '_cleanup'][$name . '_transliterate']['#default_value'] = 0;
}
// Replacement patterns for field.
$field_data['form_path'][$name . '_tokens'] = array(
'#type' => 'fieldset',
'#title' => t('!title replacement patterns', array(
'!title' => $field['title'],
)),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#description' => theme('filefield_paths_token_help'),
'#weight' => ($count - 1) * 3 + 2,
'#attributes' => array(
'class' => $name . ' tokens',
),
);
}
// Retroactive updates.
$field_data['form_path']['retroactive_update'] = array(
'#type' => 'checkbox',
'#title' => t('Retroactive update'),
'#description' => t('Move and rename previously uploaded files') . '.' . '<br /> <strong style="color: #FF0000;">' . t('Warning') . ':</strong> ' . t('This feature should only be used on developmental servers or with extreme caution') . '.',
'#weight' => 10,
);
$form['#submit']['filefield_paths_form_submit'] = array();
}
}
}
/**
* Implementation of hook_form_submit().
*/
function filefield_paths_form_submit($form, $form_values) {
$ffp = array();
// Invoke hook_filefield_paths_form_submit().
foreach (module_implements('filefield_paths_form_submit') as $module) {
$function = $module . '_filefield_paths_form_submit';
$function($form_values, $ffp);
}
if (count($ffp) > 0) {
$fields = module_invoke_all('filefield_paths_field_settings');
foreach ($ffp as $field_name => $field_data) {
$cols = $vals = $data = array();
foreach ($fields as $name => &$field) {
$field['settings'] = array(
'value' => isset($form_values['ffp_' . $field_name][$name]) ? $form_values['ffp_' . $field_name][$name] : $form_values['ffp_' . $field_name]['image_path'],
'tolower' => $form_values['ffp_' . $field_name][$name . '_cleanup'][$name . '_tolower'],
'pathauto' => $form_values['ffp_' . $field_name][$name . '_cleanup'][$name . '_pathauto'],
'transliterate' => $form_values['ffp_' . $field_name][$name . '_cleanup'][$name . '_transliterate'],
);
// Store additional settings from addon modules.
if (isset($field['data'])) {
foreach ($field['data'] as $key => $value) {
$field['settings'][$key] = $form_values['ffp_' . $field_name][$value];
}
}
$cols[] = $field['sql'];
$vals[] = "'%s'";
$data[] = serialize($field['settings']);
}
$result = db_fetch_object(db_query("SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'", $field_data['type'], $field_name));
if (!empty($result)) {
foreach ($cols as &$col) {
$col .= " = '%s'";
}
db_query("UPDATE {filefield_paths} SET " . implode(', ', $cols) . " WHERE type = '%s' AND field = '%s'", array_merge($data, array(
$field_data['type'],
$field_name,
)));
}
else {
db_query("INSERT INTO {filefield_paths} (type, field, " . implode(', ', $cols) . ") VALUES ('%s', '%s', " . implode(', ', $vals) . ")", array_merge(array(
$field_data['type'],
$field_name,
), $data));
}
if ($form_values['ffp_' . $field_name]['retroactive_update']) {
filefield_paths_update(arg(5), $field_name, arg(3));
}
}
}
}
function filefield_paths_update($field_name = NULL, $field_module, $type_name) {
$module = !empty($field_name) ? 'filefield' : $field_module;
// Invoke hook_filefield_paths_update().
if (function_exists($function = $module . '_filefield_paths_update')) {
$function($field_name, str_replace('-', '_', $type_name));
}
}
/**
* Implementation of hook_nodeapi().
*/
function filefield_paths_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'submit':
if (module_exists('content')) {
$content_type = content_types($node->type);
foreach ($content_type['fields'] as $field) {
if (preg_match('/\\bfile\\b|\\bimage\\b/', $field['type']) && is_array($node->{$field}['field_name'])) {
foreach ($node->{$field}['field_name'] as $count => &$file) {
if (empty($file['filepath'])) {
continue;
}
// If file is newly uploaded, flag to be processed
if ($file['fid'] == 'upload') {
$file['data']['process'] = TRUE;
}
}
}
}
}
break;
case 'insert':
case 'update':
$update = new stdClass();
$update->node = FALSE;
if (($ffp = filefield_paths_get_fields($node)) == FALSE) {
break;
}
// Process files.
foreach ($ffp['#files'] as &$file) {
// Convert Upload.module file to Array.
if ($file['module'] == 'upload') {
$file['field'] = (array) $file['field'];
}
module_invoke_all('filefield_paths_process_file', $file['new'], $file, $ffp['#settings'][$file['name']], $node, $update);
// Convert Upload.module file back to Object.
if ($file['module'] == 'upload') {
$file['field'] = (object) $file['field'];
}
}
// Re-write node entry if required.
if ($update->node == TRUE) {
$arr = array();
foreach ($node_table_types as $key => $value) {
$arr[] = $key . ' = ' . $value;
}
$node_table_values[] = $node->nid;
$node_query = 'UPDATE {node} SET ' . implode(', ', $arr) . ' WHERE nid = %d';
if ($node->revision) {
$revisions_query = 'INSERT INTO {node_revisions} (' . implode(', ', array_keys($revisions_table_types)) . ') VALUES (' . implode(', ', $revisions_table_types) . ')';
}
else {
$arr = array();
foreach ($revisions_table_types as $key => $value) {
$arr[] = $key . ' = ' . $value;
}
$revisions_table_values[] = $node->vid;
$revisions_query = 'UPDATE {node_revisions} SET ' . implode(', ', $arr) . ' WHERE vid = %d';
}
db_query($node_query, $node_table_values);
db_query($revisions_query, $revisions_table_values);
}
// Re-write cck fields.
if (module_exists('content')) {
_content_field_invoke_default('update', $node);
cache_clear_all('content:' . $node->nid . ':' . $node->vid, 'cache_content');
}
// Cleanup temporary paths.
if ($ffp['#settings']) {
foreach ($ffp['#settings'] as $name => $field) {
$paths = explode('/', $field['filepath']['value']);
filefield_paths_cleanup_temp($paths);
}
}
break;
}
}
function filefield_paths_cleanup_temp($paths) {
while ($paths) {
if (@rmdir(file_directory_path() . '/' . implode('/', $paths)) === TRUE) {
array_pop($paths);
continue;
}
break;
}
}
function filefield_paths_get_fields($node, $op = NULL) {
$ffp = array();
// Invoke hook_filefield_paths_get_fields().
foreach (module_implements('filefield_paths_get_fields') as $module) {
$function = $module . '_filefield_paths_get_fields';
$function($node, $ffp);
}
if (count($ffp) == 0 || isset($ffp['#types']) && !is_array($ffp['#types'])) {
return FALSE;
}
$fields = module_invoke_all('filefield_paths_field_settings');
// Load fields settings
foreach ($ffp['#types'] as $name => $temp) {
$result = db_fetch_object(db_query("SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'", $node->type, $name));
if (!empty($result)) {
foreach ($fields as $field) {
$ffp['#settings'][$name][$field['sql']] = unserialize($result->{$field}['sql']);
}
}
}
return $ffp;
}
/**
* Implementation of hook_filefield_paths_process_file().
*/
function filefield_paths_filefield_paths_process_file($new, &$file, $settings, &$node, &$update) {
if ($new) {
// Process filename
$file['filename']['old'] = $file['field']['filename'];
if (($file['filename']['new'] = $settings['filename']['value']) != '') {
$file['filename']['new'] = filefield_paths_process_string($file['filename']['new'], 'node', $node, $settings['filename']);
$file['filename']['new'] = filefield_paths_process_string($file['filename']['new'], 'field', array(
0 => $file['field'],
), $settings['filename']);
}
else {
$file['filename']['new'] = $file['field']['filename'];
}
// Process filepath
$file['filepath']['old'] = $file['field']['filepath'];
$file['filepath']['new'] = filefield_paths_process_string(file_directory_path() . '/' . $settings['filepath']['value'] . '/' . $file['filename']['new'], 'node', $node, $settings['filepath']);
$file['filepath']['new'] = filefield_paths_process_string($file['filepath']['new'], 'field', array(
0 => $file['field'],
), $settings['filepath']);
// Finalize files if necessary
if (dirname($file['filepath']['new']) != dirname($file['field']['filepath']) || $file['filename']['new'] != $file['field']['filename']) {
if (filefield_paths_file_move($file)) {
// Fix reference to old paths in Body and Teaser
// TODO: allow for CCK fields
if (isset($node->body)) {
$file['filepath']['new'] = str_replace($file['filename']['old'], $file['filename']['new'], $file['filepath']['new']);
$pattern = array(
'regex' => str_replace('/', '\\/', file_directory_path()) . '(.*?)' . str_replace('/', '\\/', str_replace(file_directory_path(), '', $file['filepath']['old'])),
'regex_enc' => str_replace('/', '\\/', drupal_urlencode(file_directory_path())) . '(.*?)' . str_replace('/', '\\/', str_replace(drupal_urlencode(file_directory_path()), '', drupal_urlencode($file['filepath']['old']))),
'replace' => file_directory_path() . '$1' . str_replace(file_directory_path(), '', $file['filepath']['new']),
);
$body = $node->body;
$body = preg_replace('/' . $pattern['regex'] . '/s', $pattern['replace'], $body);
$body = preg_replace('/' . $pattern['regex_enc'] . '/s', $pattern['replace'], $body);
$teaser = $node->teaser;
$teaser = preg_replace('/' . $pattern['regex'] . '/s', $pattern['replace'], $teaser);
$teaser = preg_replace('/' . $pattern['regex_enc'] . '/s', $pattern['replace'], $teaser);
if ($body != $node->body || $teaser != $node->teaser) {
$node->body = $body;
$node->teaser = $teaser;
$update->node = TRUE;
}
}
// Store new filename in file Array
$file['field']['filename'] = $file['filename']['new'];
}
}
}
}
/**
* Implementation of hook_token_list().
*/
function filefield_paths_token_list($type = 'all') {
if ($type == 'field' || $type == 'all') {
$tokens = array();
$tokens['file']['filefield-onlyname'] = t("File name without extension");
$tokens['file']['filefield-extension'] = t("File extension");
$tokens['file']['filefield-onlyname-original'] = t("File name without extension - original");
$tokens['file']['filefield-extension-original'] = t("File extension - original");
// Tokens for Image module integration.
if (module_exists('image')) {
$tokens['image']['image-derivative'] = t("Image derivative (thumbnail, preview, etc)");
}
return $tokens;
}
}
/**
* Implementation of hook_token_values().
*/
function filefield_paths_token_values($type, $object = NULL) {
if ($type == 'field') {
$item = pathinfo($object[0]['filename']);
$tokens = array();
$tokens['filefield-onlyname'] = $item['filename'];
$tokens['filefield-extension'] = $item['extension'];
// Original filename.
$orig = $item;
$filename = $object[0]['filename'];
if (!empty($object[0]['origname'])) {
$orig = pathinfo($object[0]['origname']);
$filename = $object[0]['origname'];
}
// PHP < 5.2: pathinfo() doesn't return 'filename' variable.
$tokens['filefield-onlyname-original'] = isset($orig['filename']) ? $orig['filename'] : basename($filename, '.' . $orig['extension']);
$tokens['filefield-extension-original'] = $orig['extension'];
// Tokens for Image module integration.
if (module_exists('image')) {
$tokens['image-derivative'] = isset($object[0]['type']) && $object[0]['type'] !== '_original' ? '.' . $object[0]['type'] : '';
}
return $tokens;
}
}
/**
* Process and cleanup strings.
*/
function filefield_paths_process_string($value, $type, $object, $settings = array()) {
// Process string tokens.
$placeholders = _filefield_paths_get_values($type, $object, module_exists('pathauto') && isset($settings['pathauto']) && $settings['pathauto']);
$value = str_replace($placeholders['tokens'], $placeholders['values'], $value);
// Transliterate string.
if (module_exists('transliteration') && isset($settings['transliterate']) && $settings['transliterate']) {
$value = transliteration_get($value);
if ($type == 'field') {
$paths = explode('/', $value);
foreach ($paths as &$path) {
$path = transliteration_clean_filename($path);
}
$value = implode('/', $paths);
}
}
// Convert string to lower case.
if (isset($settings['tolower']) && $settings['tolower'] || isset($settings['pathauto']) && $settings['pathauto'] && variable_get('pathauto_case', 0)) {
// Convert string to lower case
$value = drupal_strtolower($value);
}
return $value;
}
function _filefield_paths_get_values($type, $object, $pathauto = FALSE) {
switch ($type) {
case 'node':
$full = token_get_values($type, $object, TRUE);
break;
case 'field':
$all = filefield_paths_token_values($type, $object);
if (function_exists('filefield_token_values')) {
$all = array_merge(filefield_token_values($type, $object), $all);
}
$full = new stdClass();
$full->tokens = array_keys($all);
$full->values = array_values($all);
break;
}
$full->tokens = token_prepare_tokens($full->tokens);
if ($pathauto) {
$temp = clone $full;
// Strip square brackets from tokens for Pathauto.
foreach ($temp->tokens as &$token) {
$token = trim($token, "[]");
}
$full->values = pathauto_clean_token_values($temp);
}
// Temporary fix: Remove double slashes from token values.
// TODO: Remove when #420856 is committed to Pathauto.
foreach ($full->values as &$value) {
$value = str_replace('//', '/', $value);
}
return array(
'tokens' => $full->tokens,
'values' => $full->values,
);
}
/**
* Move file and update its database record.
*/
function filefield_paths_file_move(&$file, $replace = FILE_EXISTS_RENAME) {
$dest = _filefield_paths_strip_path(dirname($file['filepath']['new']));
foreach (explode('/', $dest) as $dir) {
$dirs[] = $dir;
$path = file_create_path(implode($dirs, '/'));
if (!_filefield_paths_check_directory($path, FILE_CREATE_DIRECTORY)) {
watchdog('filefield_paths', t('FileField Paths failed to create directory (%d).', array(
'%d' => $path,
)), WATCHDOG_ERROR);
return FALSE;
}
}
if (!file_move($file['field']['filepath'], $dest . '/' . $file['filename']['new'], $replace)) {
watchdog('filefield_paths', t('FileField Paths failed to move file (%o) to (%n).', array(
'%o' => $file['filepath']['old'],
'%n' => $dest . '/' . $file['filename']['new'],
)), WATCHDOG_ERROR);
return FALSE;
}
$result = db_fetch_object(db_query("SELECT origname FROM {files} WHERE fid = %d", $file['field']['fid']));
// Set 'origname' and update 'filename'.
if (empty($result->origname)) {
db_query("UPDATE {files} SET filename = '%s', filepath = '%s', origname = '%s' WHERE fid = %d", $file['filename']['new'], $file['field']['filepath'], $file['filename']['old'], $file['field']['fid']);
}
else {
db_query("UPDATE {files} SET filename = '%s', filepath = '%s' WHERE fid = %d", $file['filename']['new'], $file['field']['filepath'], $file['field']['fid']);
}
return TRUE;
}
function _filefield_paths_strip_path($path) {
$dirpath = file_directory_path();
$dirlen = drupal_strlen($dirpath);
if (drupal_substr($path, 0, $dirlen + 1) == $dirpath . '/') {
$path = drupal_substr($path, $dirlen + 1);
}
return $path;
}
function _filefield_paths_check_directory($directory, $form_element = array()) {
foreach (explode('/', $directory) as $dir) {
$dirs[] = $dir;
$path = file_create_path(implode($dirs, '/'));
file_check_directory($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
}
return TRUE;
}
Functions
Name | Description |
---|---|
filefield_paths_cleanup_temp | |
filefield_paths_filefield_paths_field_settings | Implementation of hook_filefield_paths_field_settings(). |
filefield_paths_filefield_paths_process_file | Implementation of hook_filefield_paths_process_file(). |
filefield_paths_file_move | Move file and update its database record. |
filefield_paths_form_alter | Implementation of hook_form_alter(). |
filefield_paths_form_submit | Implementation of hook_form_submit(). |
filefield_paths_get_fields | |
filefield_paths_init | Implementation of hook_init(). |
filefield_paths_nodeapi | Implementation of hook_nodeapi(). |
filefield_paths_process_string | Process and cleanup strings. |
filefield_paths_token_list | Implementation of hook_token_list(). |
filefield_paths_token_values | Implementation of hook_token_values(). |
filefield_paths_update | |
theme_filefield_paths_token_help | |
_filefield_paths_check_directory | |
_filefield_paths_get_values | |
_filefield_paths_strip_path |