/[drupal]/contributions/modules/filefield_paths/filefield_paths.module
ViewVC logotype

Contents of /contributions/modules/filefield_paths/filefield_paths.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.22 - (show annotations) (download) (as text)
Tue Nov 3 21:41:39 2009 UTC (3 weeks, 4 days ago) by deciphered
Branch: MAIN
Changes since 1.21: +3 -45 lines
File MIME type: text/x-php
Drupal 7 port
1 <?php
2 // $Id: filefield_paths.module,v 1.21 2009/11/02 00:37:02 deciphered Exp $
3
4 /**
5 * @file
6 * Adds extra functionality to FileFields Path settings.
7 */
8
9 /**
10 * Implements hook_filefield_paths_field_settings().
11 */
12 function filefield_paths_filefield_paths_field_settings() {
13 return array(
14 'file_path' => array(
15 'title' => 'File path',
16 'sql' => 'filepath',
17
18 'form' => array(
19 'file_path' => array(
20 '#maxlength' => 512,
21 '#size' => 128,
22 ),
23 ),
24 ),
25
26 'file_name' => array(
27 'title' => 'File name',
28 'sql' => 'filename',
29
30 'form' => array(
31 'file_name' => array(
32 '#type' => 'textfield',
33 '#title' => t('File name'),
34 '#default_value' => '[file:ffp:onlyname:original].[file:ffp:extension:original]',
35 ),
36 ),
37 )
38 );
39 }
40
41 /**
42 * Implements hook_theme().
43 */
44 function filefield_paths_theme() {
45 return array(
46 'filefield_paths_token_help' => array(
47 'arguments' => array($types = array())
48 ),
49 );
50 }
51
52 function theme_filefield_paths_token_help($types) {
53 $types = count($types) == 0 ? array('file', 'node', 'site', 'user') : $types;
54 $full_list = token_info();
55 $table = array(
56 //'header' => array(t('Token'), t('Replacement value')),
57 'rows' => array(),
58 'attributes' => array('class' => 'description'),
59 );
60
61 foreach ($types as $type) {
62 $table['rows'][] = array(array('data' => drupal_ucfirst($type) . ' ' . t('tokens'), 'class' => 'region', 'colspan' => 2));
63 foreach ($full_list['tokens'][$type] as $token => $data) {
64 $table['rows'][] = array(
65 '[' . $type . ':' . $token . ']',
66 $data['description'],
67 );
68 }
69 }
70
71 return theme('table', $table);
72 }
73
74 /**
75 * Implements hook_init().
76 */
77 function filefield_paths_init() {
78 foreach (module_list() as $module) {
79 if (file_exists($file = drupal_get_path('module', 'filefield_paths') . '/modules/' . $module . '.inc')) {
80 require_once $file;
81 }
82 }
83 }
84
85 /**
86 * Implements hook_form_alter().
87 */
88 function filefield_paths_form_alter(&$form, $form_state, $form_id) {
89 $ffp = array();
90
91 // Invoke hook_filefield_paths_form_alter().
92 foreach (module_implements('filefield_paths_form_alter') as $module) {
93 $function = $module . '_filefield_paths_form_alter';
94 $function($form, $ffp);
95 }
96
97 // If supporting module enabled, show FileField Paths settings form.
98 if (count($ffp) > 0) {
99 $fields = module_invoke_all('filefield_paths_field_settings');
100 foreach ($ffp as $field_name => $field_data) {
101
102 $results = db_query("SELECT * FROM {filefield_paths} WHERE type = :type AND field = :field", array(
103 ':type' => $field_data['type'],
104 ':field' => $field_name
105 ));
106 foreach ($results as $result) { break; }
107 if (!empty($result)) {
108 foreach ($fields as &$field) {
109 $field['settings'] = unserialize($result->$field['sql']);
110 }
111 unset($field);
112 }
113
114 $count = 0;
115 foreach ($fields as $name => $field) {
116 $count++;
117
118 if (isset($field['form']) && is_array($field['form'])) {
119 $keys = array_keys($field['form']);
120 for ($i = 1; $i < count($field['form']); $i++) {
121 $field['form'][$keys[$i]]['#weight'] = ($count - 1) * 3 + 2 + $i;
122 }
123 unset($keys);
124
125 $field_data['form_path'] = array_merge_recursive($field_data['form_path'], $field['form']);
126 }
127
128 $field_data['form_path']['#tree'] = TRUE;
129 $field_data['form_path'][$name]['#weight'] = ($count - 1) * 3;
130
131 // Set defualt value for patterns.
132 if (isset($field['settings']['value'])) {
133 $field_data['form_path'][$name]['#default_value'] = $field['settings']['value'];
134
135 if (isset($field['data'])) {
136 foreach ($field['data'] as $key => $value) {
137 $field_data['form_path'][$value]['#default_value'] = $field['settings'][$key];
138 }
139 }
140 }
141
142 $field_data['form_path'][$name . '_cleanup'] = array(
143 '#type' => 'fieldset',
144 '#title' => t('!title cleanup settings', array('!title' => $field['title'])),
145 '#collapsible' => TRUE,
146 '#collapsed' => TRUE,
147 '#weight' => ($count - 1) * 3 + 1,
148 '#attributes' => array(
149 'class' => array($name . ' cleanup')
150 )
151 );
152
153 // Cleanup field with Pathauto module.
154 $field_data['form_path'][$name . '_cleanup'][$name . '_pathauto'] = array(
155 '#type' => 'checkbox',
156 '#title' => t('Cleanup using Pathauto') . '.',
157 '#default_value' => isset($field['settings']['pathauto'])
158 ? $field['settings']['pathauto']
159 : 0
160 ,
161 '#description' => t('Cleanup !title using !url', array('!title' => $field['title'], '!url' => l(t('Pathauto settings'), 'admin/build/path/pathauto'))),
162 );
163 if (!module_exists('pathauto')) {
164 $field_data['form_path'][$name . '_cleanup'][$name . '_pathauto']['#disabled'] = TRUE;
165 $field_data['form_path'][$name . '_cleanup'][$name . '_pathauto']['#default_value'] = 0;
166 }
167
168 // Convert field to lower case.
169 $field_data['form_path'][$name . '_cleanup'][$name . '_tolower'] = array(
170 '#type' => 'checkbox',
171 '#title' => t('Convert to lower case') . '.',
172 '#default_value' => isset($field['settings']['tolower'])
173 ? $field['settings']['tolower']
174 : 0
175 ,
176 '#description' => t('Convert !title to lower case', array('!title' => $field['title'])) . '.'
177 );
178
179 // Transliterate field with Transliteration module.
180 $field_data['form_path'][$name . '_cleanup'][$name . '_transliterate'] = array(
181 '#type' => 'checkbox',
182 '#title' => t('Transliterate') . '.',
183 '#default_value' => isset($field['settings']['transliterate'])
184 ? $field['settings']['transliterate']
185 : 0
186 ,
187 '#description' => t('Transliterate !title', array('!title' => $field['title'])) . '.'
188 );
189 if (!module_exists('transliteration')) {
190 $field_data['form_path'][$name . '_cleanup'][$name . '_transliterate']['#disabled'] = TRUE;
191 $field_data['form_path'][$name . '_cleanup'][$name . '_transliterate']['#default_value'] = 0;
192 }
193
194 // Replacement patterns for field.
195 $field_data['form_path'][$name . '_tokens'] = array(
196 '#type' => 'fieldset',
197 '#title' => t('!title replacement patterns', array('!title' => $field['title'])),
198 '#collapsible' => TRUE,
199 '#collapsed' => TRUE,
200 '#description' => theme('filefield_paths_token_help'),
201 '#weight' => ($count - 1) * 3 + 2,
202 '#attributes' => array(
203 'class' => array($name . ' tokens')
204 )
205 );
206 }
207
208 // Retroactive updates.
209 $field_data['form_path']['retroactive_update'] = array(
210 '#type' => 'checkbox',
211 '#title' => t('Retroactive update'),
212 '#description' => t('Move and rename previously uploaded files') . '.' .
213 '<br /> <strong style="color: #FF0000;">' . t('Warning') . ':</strong> ' .
214 t('This feature should only be used on developmental servers or with extreme caution') . '.',
215 '#weight' => 10
216 );
217
218 // Active updating.
219 $field_data['form_path']['active_updating'] = array(
220 '#type' => 'checkbox',
221 '#title' => t('Active updating'),
222 '#default_value' => variable_get("ffp_{$field_data['type']}_{$field_name}", 0),
223 '#description' => t('Actively move and rename previously uploaded files as required') . '.' .
224 '<br /> <strong style="color: #FF0000;">' . t('Warning') . ':</strong> ' .
225 t('This feature should only be used on developmental servers or with extreme caution') . '.',
226 '#weight' => 11
227 );
228
229 if (!in_array('filefield_paths_form_submit', $form['#submit'])) {
230 $form['#submit'][] = 'filefield_paths_form_submit';
231 }
232 }
233 }
234 }
235
236 /**
237 * Implements hook_form_submit().
238 */
239 function filefield_paths_form_submit($form, &$form_state) {
240 $ffp = array();
241
242 // Invoke hook_filefield_paths_form_submit().
243 foreach (module_implements('filefield_paths_form_submit') as $module) {
244 $function = $module . '_filefield_paths_form_submit';
245 $function($form_state, $ffp);
246 }
247
248 if (count($ffp) > 0) {
249 $retroactive_update = FALSE;
250 $fields = module_invoke_all('filefield_paths_field_settings');
251 foreach ($ffp as $field_name => $field_data) {
252 $cols = array();
253
254 foreach ($fields as $name => &$field) {
255 $field['settings'] = array(
256 'value' => $form_state['values']['ffp_' . $field_name][$name],
257 'tolower' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_tolower'],
258 'pathauto' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_pathauto'],
259 'transliterate' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_transliterate']
260 );
261
262 // Store additional settings from addon modules.
263 if (isset($field['data'])) {
264 foreach ($field['data'] as $key => $value) {
265 $field['settings'][$key] = $form_state['values']['ffp_' . $field_name][$value];
266 }
267 }
268
269 $cols[$field['sql']] = serialize($field['settings']);
270 }
271
272 $results = db_query(
273 "SELECT * FROM {filefield_paths} WHERE type = :type AND field = :field", array(
274 ':type' => $field_data['type'],
275 ':field' => $field_name
276 ));
277 foreach ($results as $result) { break; }
278
279 // Update existing entry.
280 if (!empty($result)) {
281 db_update('filefield_paths')
282 ->fields($cols)
283 ->condition('type', $field_data['type'])
284 ->condition('field', $field_name)
285 ->execute();
286 }
287
288 // Create new entry.
289 else {
290 db_insert('filefield_paths')
291 ->fields(array_merge(array(
292 'type' => $field_data['type'],
293 'field' => $field_name,
294 ), $cols))
295 ->execute();
296 }
297
298 if ($form_state['values']['ffp_' . $field_name]['retroactive_update']) {
299 $retroactive_update = TRUE;
300 filefield_paths_batch_update(arg(5), $field_name, arg(3));
301 }
302
303 variable_set("ffp_{$field_data['type']}_{$field_name}", $form_state['values']['ffp_' . $field_name]['active_updating']);
304 }
305
306 if ($retroactive_update) {
307 // Run batch.
308 batch_process($form_state['redirect']);
309 }
310 }
311 }
312
313 //function filefield_paths_batch_update($field_name = NULL, $field_module, $type_name) {
314 // $objects = array();
315 // $module = (!empty($field_name)) ? 'filefield' : $field_module;
316 //
317 // // Invoke hook_filefield_paths_update().
318 // if (function_exists($function = $module . '_filefield_paths_batch_update')) {
319 // $function($field_name, str_replace('-', '_', $type_name), $objects);
320 // }
321 //
322 // // Create batch.
323 // $batch = array(
324 // 'title' => t('Updating FileField Paths'),
325 // 'operations' => array(
326 // array('_filefield_paths_batch_update_process', array($objects, $field_name))
327 // ),
328 // );
329 // batch_set($batch);
330 //}
331
332 //function _filefield_paths_batch_update_process($objects, $field_name, &$context) {
333 // if (!isset($context['sandbox']['progress'])) {
334 // $context['sandbox']['progress'] = 0;
335 // $context['sandbox']['max'] = count($objects);
336 // $context['sandbox']['objects'] = $objects;
337 // }
338 //
339 // // Process nodes by groups of 5.
340 // $count = min(5, count($context['sandbox']['objects']));
341 // for ($i = 1; $i <= $count; $i++) {
342 // // For each oid, load the object, update the files and save it.
343 // $oid = array_shift($context['sandbox']['objects']);
344 //
345 // foreach (module_implements('filefield_paths_update') as $module) {
346 // $function = $module . '_filefield_paths_update';
347 // $function($oid, $field_name);
348 // }
349 //
350 // // Update our progress information.
351 // $context['sandbox']['progress']++;
352 // }
353 //
354 // // Inform the batch engine that we are not finished,
355 // // and provide an estimation of the completion level we reached.
356 // if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
357 // $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
358 // }
359 //}
360
361 ///**
362 // * Implements hook_nodeapi().
363 // */
364 //function filefield_paths_node_presave($node) {
365 // if (module_exists('content')) {
366 // $content_type = content_types($node->type);
367 // foreach ($content_type['fields'] as $field) {
368 // if ($field['type'] == 'filefield' && is_array($node->$field['field_name'])) {
369 // foreach ($node->$field['field_name'] as $count => &$file) {
370 // if (empty($file['filepath'])) {
371 // continue;
372 // }
373 // // If file is newly uploaded, flag to be processed
374 // if ($file['status'] == 0) {
375 // $file['data']['process'] = TRUE;
376 // }
377 // }
378 // }
379 // }
380 // }
381 //}
382
383 /**
384 * Implements hook_node_insert().
385 */
386 function filefield_paths_node_insert($node) {
387 filefield_paths_node_update($node);
388 }
389
390 /**
391 * Implements hook_node_update().
392 */
393 function filefield_paths_node_update($node) {
394 if (($ffp = filefield_paths_get_fields($node)) !== FALSE) {
395 $update = new stdClass;
396 $update->node = FALSE;
397
398 // Process files.
399 foreach ($ffp['#files'] as &$file) {
400 // Invoke hook_filefield_paths_process_file().
401 foreach (module_implements('filefield_paths_process_file') as $module) {
402 $function = $module . '_filefield_paths_process_file';
403 $function(($file['new'] || variable_get("ffp_{$node->type}_{$file['name']}", 0)), $file, $ffp['#settings'][$file['name']], $node, $update);
404 }
405 }
406
407 // Re-write node entry if required.
408 if ($update->node == TRUE) {
409 field_attach_update('node', $node);
410 }
411
412 // // Cleanup temporary paths.
413 // if ($ffp['#settings']) {
414 // foreach ($ffp['#settings'] as $name => $field) {
415 // $paths = explode('/', $field['filepath']['value']);
416 // filefield_paths_cleanup_temp($paths);
417 //
418 // // Invoke hook_filefield_paths_cleanup().
419 // foreach (module_implements('filefield_paths_cleanup') as $module) {
420 // $function = $module . '_filefield_paths_cleanup';
421 // $function($ffp, $paths, $name);
422 // }
423 // }
424 // }
425 }
426 }
427
428 /**
429 * Implementation of hook_content_fieldapi().
430 */
431 function filefield_paths_field_delete_field($field) {
432 db_delete('filefield_paths')
433 ->condition('type', $field['bundles']['node'][0])
434 ->condition('field', $field['field_name'])
435 ->execute();
436 }
437
438 //function filefield_paths_cleanup_temp($paths) {
439 // while ($paths) {
440 // if (@rmdir(file_directory_path() . '/' . implode('/', $paths)) === TRUE) {
441 // array_pop($paths);
442 // continue;
443 // }
444 // break;
445 // }
446 //}
447
448 function filefield_paths_get_fields(&$node, $op = NULL) {
449 $ffp = array();
450
451 // Invoke hook_filefield_paths_get_fields().
452 foreach (module_implements('filefield_paths_get_fields') as $module) {
453 $function = $module . '_filefield_paths_get_fields';
454 $function($node, $ffp);
455 }
456
457 if (count($ffp) == 0 || (isset($ffp['#types']) && !is_array($ffp['#types']))) {
458 return FALSE;
459 }
460
461 $fields = module_invoke_all('filefield_paths_field_settings');
462
463 // Load fields settings
464 foreach ($ffp['#types'] as $name => $temp) {
465 $results = db_query("SELECT * FROM {filefield_paths} WHERE type = :type AND field = :field", array(
466 ":type" => $node->type,
467 ":field" => $name
468 ));
469 foreach ($results as $result) { break; }
470
471 if (!empty($result)) {
472 foreach ($fields as $field) {
473 $ffp['#settings'][$name][$field['sql']] = unserialize($result->$field['sql']);
474 }
475 }
476 }
477
478 return $ffp;
479 }
480
481 /**
482 * Implements hook_filefield_paths_process_file().
483 */
484 function filefield_paths_filefield_paths_process_file($new, &$file, $settings, &$node, &$update) {
485 if ($new) {
486 global $user;
487 $token_data = array('file' => file_load($file['field']['fid']), 'node' => $node, 'user' => $user);
488
489 // Process filename.
490 $file['filename']['old'] = $file['field']['filename'];
491 $file['filename']['new'] = (($settings['filename']['value']) != '')
492 ? filefield_paths_process_string($settings['filename']['value'], $token_data, $settings['filename'])
493 : $file['field']['filename'];
494
495 // Process filepath.
496 $file['filepath']['old'] = $file['field']['uri'];
497 $file['filepath']['new'] = file_uri_scheme($file['field']['uri']) . '://' . filefield_paths_process_string($settings['filepath']['value'] . '/' . $file['filename']['new'], $token_data, $settings['filepath']);
498
499 // Finalize files if necessary.
500 if (dirname($file['filepath']['new']) != dirname($file['field']['uri']) || $file['filename']['new'] != $file['field']['uri']) {
501 if (file_prepare_directory(dirname($file['filepath']['new']), FILE_CREATE_DIRECTORY) && file_move((object) $file['field'], $file['filepath']['new'])) {
502
503 // Fix reference to old paths.
504 $file_directory_path = file_uri_scheme($file['field']['uri']) !== 'private' ? file_directory_path(file_uri_scheme($file['field']['uri'])) : 'system/files';
505
506 $pattern = array(
507 'regex' => str_replace('/', '\/', $file_directory_path) . '([^"]*?)' . str_replace('/', '\/', str_replace(file_directory_path(), '', file_uri_target($file['filepath']['old']))),
508 'regex_enc' => str_replace('/', '\/', drupal_encode_path($file_directory_path)) . '([^"]*?)' . str_replace('/', '\/', str_replace(drupal_encode_path(file_directory_path()), '', drupal_encode_path(file_uri_target($file['filepath']['old'])))),
509 'replace' => $file_directory_path . '$1' . str_replace(file_directory_path(), '', file_uri_target($file['filepath']['new'])),
510 );
511
512 // TODO: Replace with field_info_fields() when http://drupal.org/node/613754 is fixed.
513 $instances = field_info_instances('node', $node->type);
514 $fields = array();
515 foreach ($instances as $field_name => $instance) {
516 $fields[$field_name] = field_info_field($field_name);
517 }
518
519 foreach ($fields as $name => $field) {
520 if ($field['module'] == 'text' && isset($node->{$field['field_name']}) && is_array($node->{$field['field_name']})) {
521 foreach ($node->{$field['field_name']}['zxx'] as &$item) {
522 $original = $item['value'];
523 $item['value'] = (preg_match('/' . $pattern['regex'] . '/s', $item['value']))
524 ? preg_replace('/' . $pattern['regex'] . '/s', $pattern['replace'], $item['value'])
525 : preg_replace('/' . $pattern['regex_enc'] . '/s', $pattern['replace'], $item['value']);
526
527 if ($item['value'] !== $original) {
528 $update->node = TRUE;
529 }
530 }
531 }
532 }
533
534 // Store new filename in file Array
535 $file['field']['filename'] = $file['filename']['new'];
536 $file['field']['uri'] = $file['filepath']['new'];
537 }
538 }
539
540 // Replace description.
541 //if ($file['field']['description'] == $file['filename']['old']) {
542 // $file['field']['description'] = $file['filename']['new'];
543 //}
544 }
545 }
546
547 /**
548 * Implements hook_token_info().
549 */
550 function filefield_paths_token_info() {
551 $file['ffp:onlyname'] = array(
552 'name' => t("File name"),
553 'description' => t("File name without extension."),
554 );
555 $file['ffp:onlyname:original'] = array(
556 'onlyname' => t("File name - original"),
557 'description' => t("File name without extension - original."),
558 );
559 $file['ffp:extension'] = array(
560 'name' => t("File extension"),
561 'description' => t("File extension."),
562 );
563 $file['ffp:extension:original'] = array(
564 'name' => t("File extension - original"),
565 'description' => t("File extension - original."),
566 );
567
568 return array(
569 'tokens' => array('file' => $file),
570 );
571 }
572
573 /**
574 * Implements hook_tokens().
575 */
576 function filefield_paths_tokens($type, $tokens, array $data = array(), array $options = array()) {
577 $url_options = array('absolute' => TRUE);
578 if (isset($language)) {
579 $url_options['language'] = $language;
580 }
581 $sanitize = !empty($options['sanitize']);
582
583 $replacements = array();
584
585 if ($type == 'file' && !empty($data['file'])) {
586 $file = $data['file'];
587
588 foreach ($tokens as $name => $original) {
589 switch ($name) {
590 case 'ffp:onlyname':
591 $info = pathinfo($file->filename);
592 // PHP < 5.2: pathinfo() doesn't return 'filename' variable.
593 $replacements[$original] = isset($orig['filename']) ? $info['filename'] : basename($file->filename, '.' . $info['extension']);
594 break;
595
596 case 'ffp:onlyname:original':
597 $info = pathinfo($file->origname);
598 // PHP < 5.2: pathinfo() doesn't return 'filename' variable.
599 $replacements[$original] = isset($orig['filename']) ? $info['filename'] : basename($file->origname, '.' . $info['extension']);
600 break;
601
602 case 'ffp:extension':
603 $info = pathinfo($file->filename);
604 $replacements[$original] = $info['extension'];
605 break;
606
607 case 'ffp:extension:original':
608 $info = pathinfo($file->origname);
609 $replacements[$original] = $info['extension'];
610 break;
611 }
612 }
613 }
614
615 return $replacements;
616 }
617
618 /**
619 * Process and cleanup strings.
620 */
621 function filefield_paths_process_string($value, $data, $settings = array()) {
622 // Process string tokens.
623 $value = token_replace($value, $data);
624
625 // Transliterate string.
626 if (module_exists('transliteration') && isset($settings['transliterate']) && $settings['transliterate']) {
627 $value = transliteration_get($value);
628 if ($type == 'field') {
629 $paths = explode('/', $value);
630 foreach ($paths as &$path) {
631 $path = transliteration_clean_filename($path);
632 }
633
634 $value = implode('/', $paths);
635 }
636 }
637
638 // Convert string to lower case.
639 if ((isset($settings['tolower']) && $settings['tolower']) || (isset($settings['pathauto']) && $settings['pathauto'] && variable_get('pathauto_case', 0))) {
640 // Convert string to lower case
641 $value = drupal_strtolower($value);
642 }
643
644 // Ensure that there are no double-slash sequences due to empty token values.
645 $value = preg_replace('/\/+/', '/', $value);
646
647 return $value;
648 }
649
650 /**
651 * Implements hook_file_insert().
652 */
653 function filefield_paths_file_insert(&$file) {
654 // Store original filename in the database.
655 if (empty($file->origname)) {
656 $file->origname = $file->filename;
657 db_update('file')
658 ->fields(array('origname' => $file->filename))
659 ->condition('fid', $file->fid)
660 ->execute();
661 }
662 }

  ViewVC Help
Powered by ViewVC 1.1.2