0) { $entity_info = entity_get_info($form['#instance']['entity_type']); $fields = module_invoke_all('filefield_paths_field_settings'); foreach ($ffp as $field_name => $field_data) { $active_updating = 0; $results = db_select('filefield_paths', 'f') ->fields('f') ->condition('type', $field_data['type']) ->condition('field', $field_name) ->execute() ->fetchAllAssoc('type'); if (!empty($results[$field_data['type']])) { $result = $results[$field_data['type']]; foreach ($fields as &$field) { $field['settings'] = unserialize($result->{$field['sql']}); } unset($field); $active_updating = $result->active_updating; } $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; $field['form'][$keys[$i]]['#element_validate'] = array('token_element_validate'); $field['form'][$keys[$i]]['#token_types'] = array('file', $entity_info['token type']); } unset($keys); $field_data['form_path'] = array_merge_recursive($field_data['form_path'], $field['form']); } $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' => array("{$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', array('@title' => $field['title'])) . ' ' . l(t('Pathauto settings'), 'admin/config/search/path/settings'), ); 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']['token_tree'] = array( '#type' => 'fieldset', '#title' => t('Replacement patterns'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => theme('token_tree', array('token_types' => array('file', $entity_info['token type']))), '#weight' => 10, ); // Retroactive updates. $field_data['form_path']['retroactive_update'] = array( '#type' => 'checkbox', '#title' => t('Retroactive update'), '#description' => t('Move and rename previously uploaded files') . '.' . '
' . t('Warning') . ': ' . t('This feature should only be used on developmental servers or with extreme caution') . '.', '#weight' => 11 ); // Active updating. $field_data['form_path']['active_updating'] = array( '#type' => 'checkbox', '#title' => t('Active updating'), '#default_value' => $active_updating, '#description' => t('Actively move and rename previously uploaded files as required') . '.' . '
' . t('Warning') . ': ' . t('This feature should only be used on developmental servers or with extreme caution') . '.', '#weight' => 12 ); if (!in_array('filefield_paths_form_submit', $form['#submit'])) { $form['#submit'][] = 'filefield_paths_form_submit'; } } } } /** * Implements hook_form_submit(). */ function filefield_paths_form_submit($form, &$form_state) { $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_state, $ffp); } if (count($ffp) > 0) { $retroactive_update = FALSE; $fields = module_invoke_all('filefield_paths_field_settings'); foreach ($ffp as $field_name => $field_data) { $cols = array( 'type' => $field_data['type'], 'field' => $field_name, 'active_updating' => $form_state['values']["ffp_{$field_name}"]['active_updating'], ); foreach ($fields as $name => &$field) { $cols[$field['sql']] = array( 'value' => $form_state['values']["ffp_{$field_name}"][$name], 'tolower' => $form_state['values']["ffp_{$field_name}"]["{$name}_cleanup"]["{$name}_tolower"], 'pathauto' => $form_state['values']["ffp_{$field_name}"]["{$name}_cleanup"]["{$name}_pathauto"], 'transliterate' => $form_state['values']["ffp_{$field_name}"]["{$name}_cleanup"]["{$name}_transliterate"], ); // Store additional settings from add-on modules. if (isset($field['data'])) { foreach ($field['data'] as $key => $value) { $cols[$field['sql']][$key] = $form_state['values']["ffp_{$field_name}"][$value]; } } } $results = db_select('filefield_paths', 'f') ->fields('f') ->condition('type', $cols['type']) ->condition('field', $cols['field']) ->execute() ->fetchAll(); // Update existing entry. if (!empty($results)) { drupal_write_record('filefield_paths', $cols, array('type', 'field')); } // Create new entry. else { drupal_write_record('filefield_paths', $cols); } if ($form_state['values']["ffp_{$field_name}"]['retroactive_update']) { $retroactive_update = TRUE; $module = isset($form['#field']) ? $form['#field']['module'] : $field_name; filefield_paths_batch_update($form_state['values']['instance']); } } if ($retroactive_update) { // Run batch. batch_process($form_state['redirect']); } } } /** * Set batch process to update FileField Paths. * * @param $instance */ function filefield_paths_batch_update($instance) { $objects = array(); // Invoke hook_filefield_paths_batch_update(). if (function_exists($function = "{$instance['widget']['module']}_filefield_paths_batch_update")) { $function($instance, $objects); } // Create batch. $batch = array( 'title' => t('Updating FileField Paths'), 'operations' => array( array('_filefield_paths_batch_update_process', array($objects, $instance)) ), ); batch_set($batch); } function _filefield_paths_batch_update_process($objects, $instance, &$context) { if (!isset($context['sandbox']['progress'])) { $context['sandbox']['progress'] = 0; $context['sandbox']['max'] = count($objects); $context['sandbox']['objects'] = $objects; } // Process nodes by groups of 5. $count = min(5, count($context['sandbox']['objects'])); for ($i = 1; $i <= $count; $i++) { // For each oid, load the object, update the files and save it. $oid = array_shift($context['sandbox']['objects']); // Invoke hook_filefield_paths_update(). if (function_exists($function = "{$instance['widget']['module']}_filefield_paths_update")) { $function($oid, $instance); } // Update our progress information. $context['sandbox']['progress']++; } // Inform the batch engine that we are not finished, // and provide an estimation of the completion level we reached. if ($context['sandbox']['progress'] != $context['sandbox']['max']) { $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; } } /** * Implements hook_entity_insert(). */ function filefield_paths_entity_insert($entity, $type) { filefield_paths_entity_update($entity, $type); } /** * Implements hook_entity_update(). */ function filefield_paths_entity_update($entity, $type) { if (($ffp = filefield_paths_get_fields($entity, $type)) !== FALSE) { $update = new stdClass; $update->entity = FALSE; // Process files. foreach ($ffp['#files'] as &$file) { // Invoke hook_filefield_paths_process_file(). foreach (module_implements('filefield_paths_process_file') as $module) { $function = "{$module}_filefield_paths_process_file"; $settings = isset($ffp['#settings'][$file['name']]) ? $ffp['#settings'][$file['name']] : NULL; if (!is_null($settings)) { $function(($file['new'] || $settings['active_updating']), $file, $settings, $entity, $type, $update); } } } if ($update->entity == TRUE) { field_attach_update($type, $entity); } // Cleanup temporary paths. if ($ffp['#settings']) { foreach ($ffp['#settings'] as $name => $field) { // Invoke hook_filefield_paths_cleanup(). foreach (module_implements('filefield_paths_cleanup') as $module) { $function = "{$module}_filefield_paths_cleanup"; $function($ffp, $name); } } } } } /** * Implements hook_file_presave(). */ function filefield_paths_file_presave($file) { // Store original filename in the database. if (empty($file->origname)) { $file->origname = $file->filename; } } /** * Implements hook_field_delete_instance(). */ function filefield_paths_field_delete_instance($instance) { db_delete('filefield_paths') ->condition('type', "{$instance['entity_type']}::{$instance['bundle']}") ->condition('field', $instance['field_name']) ->execute(); } /** * */ function filefield_paths_get_fields(&$entity, $type, $op = NULL) { $ffp = array(); $entity_info = entity_get_info(); // Invoke hook_filefield_paths_get_fields(). foreach (module_implements('filefield_paths_get_fields') as $module) { $function = "{$module}_filefield_paths_get_fields"; $function($entity, $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 (array_keys($ffp['#types']) as $name) { $field_type = isset($entity->{$entity_info[$type]['entity keys']['bundle']}) ? "{$type}::{$entity->{$entity_info[$type]['entity keys']['bundle']}}" : "{$type}::{$type}"; $results = db_select('filefield_paths', 'f') ->fields('f') ->condition('type', $field_type) ->condition('field', $name) ->execute() ->fetchAllAssoc('type'); if (!empty($results[$field_type])) { $result = $results[$field_type]; foreach ($fields as $field) { $ffp['#settings'][$name][$field['sql']] = unserialize($result->$field['sql']); } $ffp['#settings'][$name]['active_updating'] = $result->active_updating; } } return $ffp; } /** * Run regular expression over all available text-based fields. */ function _filefield_paths_replace_path($old, $new, &$entity, &$update) { // Build regular expression. $info = parse_url($old); $info['path'] = !empty($info['path']) ? $info['path'] : ''; $absolute = str_replace("{$info['host']}{$info['path']}", '', file_create_url($old)); $relative = parse_url($absolute, PHP_URL_PATH); $regex = str_replace('/', '\/', "({$absolute}|{$relative}|{$info['scheme']}://)(styles/.*?/{$info['scheme']}/|)({$info['host']}{$info['path']})"); // Build replacement. $info = parse_url($new); $replacement = "\$1\$2{$info['host']}{$info['path']}"; $fields = field_info_fields(); foreach ($fields as $name => $field) { if ($field['module'] == 'text' && isset($entity->{$field['field_name']}) && is_array($entity->{$field['field_name']})) { foreach ($entity->{$field['field_name']} as &$language) { foreach ($language as &$item) { $item['value'] = preg_replace("/$regex/", $replacement, $item['value']); } } } } } /** * Process and cleanup strings. */ function filefield_paths_process_string($value, $data, $settings = array()) { $transliterate = module_exists('transliteration') && isset($settings['transliterate']) && $settings['transliterate']; $pathauto = module_exists('pathauto') && isset($settings['pathauto']) && $settings['pathauto'] == TRUE; if ($pathauto == TRUE) { module_load_include('inc', 'pathauto'); } $paths = explode('/', $value); foreach ($paths as &$path) { // Process string tokens. $path = token_replace($path, $data, array('clear' => TRUE)); // Cleanup with pathauto. if ($pathauto == TRUE) { $path_parts = explode('.', $path); foreach ($path_parts as &$path_part) { $path_part = pathauto_cleanstring($path_part); } $path = implode('.', $path_parts); } // Transliterate string. if ($transliterate == TRUE) { $path = transliteration_clean_filename($path); } } $value = implode('/', $paths); // Convert string to lower case. if (isset($settings['tolower']) && $settings['tolower'] == TRUE) { $value = drupal_strtolower($value); } // Ensure that there are no double-slash sequences due to empty token values. $value = preg_replace('/\/+/', '/', $value); return $value; }