security update for uuid xmlsitemap file_field_path

This commit is contained in:
2018-10-13 16:01:24 +02:00
parent f7ae17e6c4
commit a163542966
109 changed files with 5458 additions and 1952 deletions

View File

@@ -0,0 +1,121 @@
# @file
# .travis.yml - Drupal for Travis CI Integration
#
# Template provided by https://github.com/LionsAd/drupal_ti.
#
# Based for simpletest upon:
# https://github.com/sonnym/travis-ci-drupal-module-example
language: php
sudo: false
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7
matrix:
fast_finish: true
allow_failures:
- php: 7
env:
global:
# add composer's global bin directory to the path
# see: https://github.com/drush-ops/drush#install---composer
- PATH="$PATH:$HOME/.composer/vendor/bin"
# Configuration variables.
- DRUPAL_TI_MODULE_NAME="filefield_paths"
- DRUPAL_TI_SIMPLETEST_GROUP="File (Field) Paths"
# Define runners and environment vars to include before and after the
# main runners / environment vars.
#- DRUPAL_TI_SCRIPT_DIR_BEFORE="./drupal_ti/before"
#- DRUPAL_TI_SCRIPT_DIR_AFTER="./drupal_ti/after"
# The environment to use, supported are: drupal-7, drupal-8
- DRUPAL_TI_ENVIRONMENT="drupal-7"
# Drupal specific variables.
- DRUPAL_TI_DB="drupal_travis_db"
- DRUPAL_TI_DB_URL="mysql://root:@127.0.0.1/drupal_travis_db"
# Note: Do not add a trailing slash here.
- DRUPAL_TI_WEBSERVER_URL="http://127.0.0.1"
- DRUPAL_TI_WEBSERVER_PORT="8080"
# Simpletest specific commandline arguments, the DRUPAL_TI_SIMPLETEST_GROUP is appended at the end.
- DRUPAL_TI_SIMPLETEST_ARGS="--verbose --color --concurrency 4 --url $DRUPAL_TI_WEBSERVER_URL:$DRUPAL_TI_WEBSERVER_PORT"
# === Behat specific variables.
# This is relative to $TRAVIS_BUILD_DIR
- DRUPAL_TI_BEHAT_DIR="./tests/behat"
# These arguments are passed to the bin/behat command.
- DRUPAL_TI_BEHAT_ARGS=""
# Specify the filename of the behat.yml with the $DRUPAL_TI_DRUPAL_DIR variables.
- DRUPAL_TI_BEHAT_YML="behat.yml.dist"
# This is used to setup Xvfb.
- DRUPAL_TI_BEHAT_SCREENSIZE_COLOR="1280x1024x16"
# The version of seleniumthat should be used.
- DRUPAL_TI_BEHAT_SELENIUM_VERSION="2.44"
# Set DRUPAL_TI_BEHAT_DRIVER to "selenium" to use "firefox" or "chrome" here.
- DRUPAL_TI_BEHAT_DRIVER="phantomjs"
- DRUPAL_TI_BEHAT_BROWSER="firefox"
# PHPUnit specific commandline arguments.
- DRUPAL_TI_PHPUNIT_ARGS=""
# Specifying the phpunit-core src/ directory is useful when e.g. a vendor/
# directory is present in the module directory, which phpunit would then
# try to find tests in. This option is relative to $TRAVIS_BUILD_DIR.
#- DRUPAL_TI_PHPUNIT_CORE_SRC_DIRECTORY="./tests/src"
# Code coverage via coveralls.io
- DRUPAL_TI_COVERAGE="satooshi/php-coveralls:0.6.*"
# This needs to match your .coveralls.yml file.
- DRUPAL_TI_COVERAGE_FILE="build/logs/clover.xml"
# Debug options
#- DRUPAL_TI_DEBUG="-x -v"
# Set to "all" to output all files, set to e.g. "xvfb selenium" or "selenium",
# etc. to only output those channels.
#- DRUPAL_TI_DEBUG_FILE_OUTPUT="selenium xvfb webserver"
matrix:
# [[[ SELECT ANY OR MORE OPTIONS ]]]
#- DRUPAL_TI_RUNNERS="phpunit"
#- DRUPAL_TI_RUNNERS="simpletest"
#- DRUPAL_TI_RUNNERS="behat"
#- DRUPAL_TI_RUNNERS="phpunit simpletest behat"
# Use phpunit-core to test modules with phpunit with Drupal 8 core.
#- DRUPAL_TI_RUNNERS="phpunit-core"
- DRUPAL_TI_RUNNERS="simpletest"
mysql:
database: drupal_travis_db
username: root
encoding: utf8
before_install:
- composer self-update
- cd ./tests
- composer global require "lionsad/drupal_ti:1.*"
- drupal-ti before_install
install:
- drupal-ti install
before_script:
- drupal-ti before_script
- drush dl pathauto-7.x redirect-7.x token-7.x transliteration-7.x --destination="$TRAVIS_BUILD_DIR/../drupal-7/drupal/sites/all/modules"
script:
- drupal-ti script
after_script:
- drupal-ti after_script
notifications:
email: false

View File

@@ -1,4 +1,100 @@
File (Field) Paths 7.x-1.x-dev, xxxx-xx-xx (development release)
File (Field) Paths 7.x-1.1, 2018-08-14
--------------------------------------------------------------------------------
- Fixed security issue
- #2643026: Fixed issue when anonymous function not created.
File (Field) Paths 7.x-1.0, 2015-11-17
--------------------------------------------------------------------------------
- #2615704 by morenstrat: Fixed issue with temporary path and schemes.
- Added variable module integration.
File (Field) Paths 7.x-1.0-rc3, 2015-11-11
--------------------------------------------------------------------------------
- #2612396: Added watchdog message for unmoved files.
- #2607302: Added configurable temporary file location.
File (Field) Paths 7.x-1.0-rc2, 2015-10-28
--------------------------------------------------------------------------------
- #2592519: Fixed issue with temporary upload location and field collections.
- #2576547: Fixed issue with Media Youtube files being processed.
- #2570127: Added stricter checks for filefield_paths_form_alter().
- #2569589: Fixed issue with unicode characters in pathauto processing.
File (Field) Paths 7.x-1.0-rc1, 2015-09-15
--------------------------------------------------------------------------------
- #2551187: Changed token tree to dialog.
- #2514874 by Deciphered, smithmilner: Fixed issue with Drush command and
permissions.
- #2468547 by Deciphered, smithmilner: Added Redirect module integration.
- #2398411: Added default value of file_directory to file path.
- #2395903: Added truncating of long file paths.
- #2383527: Changed unprocessed destination to temporary://.
- #2276435 by Deciphered, david_garcia, rajmataj: Fixed issue with retroactive
updates and instance settings.
- #2271595 by Deciphered, tstoeckler, Reg: Fixed issue with empty batch.
- #2214409: Updated field form layout.
- #2211665: Added File path validation to remove unnecessary slashes.
- #2103151 by Deciphered, david_garcia, Sumeet.Pareek, kitikonti, kolier:
Fixed deprecated /e modifier in preg_replace().
- #2185755 by treksler: Fixed issue with regex, backreferences and numbers.
- #2119789: Fixed issue with complex characters in regex functionality.
- #2068365 by Deciphered, vinmassaro: Fixed issue when no instance in update.
- #2047835: Fixed issue with pathauto replacemenets and periods (.).
- #2019723 by Deciphered, szantog, jcandan, justafish: Fixed issue with remote
file stream wrappers.
- #1985650: Fixed issue with moved Drush file in .info.
- #1985280 by Deciphered, drasgardian: Fixed issue with hook_entity_update()
foreach loop.
- #1942720 by Deciphered, kaare, alex.designworks, pp, BWPanda: Added slash
cleanup functionality.
- #1854450: Updated file processing logic.
- #1495716/#1986472: Fixed issue with D6 -> D7 upgrade path.
- #1292436 by maximpodorov, InternetDevels: Fixed issue pathinfo and UTF files.
- Added tests.
- Removed dependency on the Token module.
File (Field) Paths 7.x-1.0-beta4, 2013-04-25
--------------------------------------------------------------------------------
- #1945148: Fixed issue with File path cleanup process.
- #1942720 by pp: Fixed issue with cleanup wehn token contains a '/' character.
- #1925298 by David_Rothstein: Fixed issue with Image derivatives.
- #1866450: Fixed issue with foreign characters in Regex.
- #1714596: Fixed issue with file_attach_update() introduced in Drupal 7.15.
- #1705298: Fixed extra beggining slash.
- #1601104 by tseven: Fixed notice when no extension present.
- #1572206: Add ability to disable for certain fields.
- #1549474: Fixed path replacement in summary text.
- #1512466 by maximpodorov, perarnet: Fixed issue with multi-value updates.
- #1499442 by hass: Improved translatable strings.
- #1464404: Fixed issue with field_attach_update().
- #1438290 by xtfer: Fixed D6 to D7 upgrade path.
- #1432200: Fixed issue with missing langcode variable.
- #1420700: Fixed issue with pass-by-reference issue.
- #1364492 by j0rd, Deciphered: Improved require_once routine.
- #1361884 by burningdog, dwkitchen, Deciphered: Fixed processing remote files.
- #1262828 by Pablo Gosse: Fixed issue with regex.
- #860848 by mostou: Fixed File name field length.
- Fixed issue with malformed URIs.
File (Field) Paths 7.x-1.0-beta3, 2012-02-08
--------------------------------------------------------------------------------
- #1429238 by ocanzillon: Fixed Drush command syntax error.
@@ -6,6 +102,7 @@ File (Field) Paths 7.x-1.x-dev, xxxx-xx-xx (development release)
- Changed a large chunk of core functionality to simplify.
File (Field) Paths 7.x-1.0-beta2, 2012-02-05
--------------------------------------------------------------------------------
@@ -16,6 +113,7 @@ File (Field) Paths 7.x-1.0-beta2, 2012-02-05
- Added support for Video module.
File (Field) Paths 7.x-1.0-beta1, 2011-11-08
--------------------------------------------------------------------------------
@@ -36,5 +134,6 @@ File (Field) Paths 7.x-1.0-beta1, 2011-11-08
- Added Entity support.
File (Field) Paths 7.x-1.0-alpha1, 2011-06-12
--------------------------------------------------------------------------------

View File

@@ -1,63 +1,66 @@
The File (Field) Paths module extends the default functionality of Drupals core
File (Field) Paths
==================
[![Build Status](https://travis-ci.org/Decipher/filefield_paths.svg)](https://travis-ci.org/Decipher/filefield_paths)
The File (Field) Paths module extends the default functionality of Drupal's core
File module, Image module and many other File upload modules, by adding the
ability to use entity based tokens in destination paths and filenames.
ability to use entity based tokens in destination paths and file names.
In simple terms, File (Field) Paths allows you to automatically sort and rename
your uploaded files using token based replacement patterns to maintain a nice
clean filesystem.
File (Field) Paths was written and is maintained by Stuart Clark (deciphered).
- http://stuar.tc/lark
- http://twitter.com/Decipher
Features
--------------------------------------------------------------------------------
--------
* Configurable file paths now use entity tokens in addition to user tokens.
* Configurable filenames.
* Support for:
* Drupal core File module.
* Drupal core Image module.
* Video module.
* Configurable file names.
* Support for file based fields, including but not limited to:
* Drupal core File module.
* Drupal core Image module.
* Video module.
* File path and filename cleanup options:
* Filter out words and punctuation by taking advantage of the Pathauto module.
* Convert unicode characters into US-ASCII with the Transliteration module.
* Remove slashes from tokens.
* Filter out words and punctuation by taking advantage of the Pathauto
module.
* Convert unicode characters into US-ASCII with the Transliteration module.
* Automatically updates unprocessed file paths in any Text fields on the entity.
* Retroactive updates - rename and/or move previously uploaded files (Use with
caution)
* Retroactive updates - rename and/or move previously uploaded files.
* Active updating - actively rename and/or move previously uploaded files.
* Create redirect - automatically create a redirect when moving uploaded files,
using the Redirect module.
Required Modules
--------------------------------------------------------------------------------
* Token - http://drupal.org/project/token
Recommended Modules
--------------------------------------------------------------------------------
-------------------
* [Pathauto](https://www.drupal.org/project/pathauto)
* [Redirect](https://www.drupal.org/project/redirect)
* [Token](https://www.drupal.org/project/token)
* [Transliteration](https://www.drupal.org/project/transliteration)
* Pathauto - http://drupal.org/project/pathauto
* Transliteration - http://drupal.org/project/transliteration
Usage/Configuration
--------------------------------------------------------------------------------
-------------------
Once installed, File (Field) Paths needs to be configured for each file field
you wish to use.
you wish to use. Settings can be found on the settings form of any supported
file based field.
* Drupal core File/Image and other Field based supported modules
Settings an be found on the fields configuration page.
Example:
*Example:*
Administration > Structure > Content types > Article > Manage fields > Image
http://[www.yoursite.com/path/to/drupal]/admin/structure/types/manage/article/fields/field_image
http://example.com/admin/structure/types/manage/article/fields/field_image
Frequently Asked Questions
--------------------------------------------------------------------------------
--------------------------
Q. Aren't tokens already supported in the File module?
@@ -71,9 +74,9 @@ Q. Why aren't my files in the correct folder?
A. When you are creating or updating an entity the full values for the tokens
may not yet be known by Drupal, so the File (Field) Paths module will upload
your files to the Fields old file path temporarily and then once you save the
entity and Drupal is provided with the tokens values the file will be moved
to the appropriate location.
your files to a temporary location and then once you save the entity and
Drupal is provided with the tokens values the file will be moved to the
appropriate location.
Q. Why is there a warning on the 'Retroactive updates' feature?
@@ -85,3 +88,13 @@ A. Retroactive updates will go through every single entity of the particular
possible that the moving/renaming of these files could break links. It is
strongly advised that you only use this functionality on your developmental
servers so that you can make sure not to introduce any linking issues.
History and Maintainers
-----------------------
File (Field) Paths was written and is maintained by Stuart Clark (deciphered).
* http://stuar.tc/lark
* http://twitter.com/Decipher

View File

@@ -0,0 +1,49 @@
<?php
/**
* @file
*
* Administration functions for the File (Field) Paths module.
*/
/**
* @param $form
* @param $form_state
* @return mixed
*/
function filefield_paths_settings_form($form, $form_state) {
$form['filefield_paths_temp_location'] = array(
'#title' => t('Temporary file location'),
'#type' => 'textfield',
'#default_value' => variable_get('filefield_paths_temp_location', 'public://filefield_paths'),
'#description' => t('The location that unprocessed files will be uploaded priot to being processed by File (Field) Paths.<br />It is recommended that you use the temporary file system (temporary://) if your server configuration allows for that.'),
'#element_validate' => array('filefield_paths_settings_form_temp_location_validate'),
);
return system_settings_form($form);
}
/**
* Validation callback for 'Temporary file location' setting.
*
* @param $element
* @param $form_state
* @return bool
*/
function filefield_paths_settings_form_temp_location_validate($element, $form_state) {
$scheme = file_uri_scheme($element['#value']);
if (!$scheme) {
form_error($element, t('Invalid file location. You must include a file stream wrapper (e.g., public://).'));
return FALSE;
}
if (!file_stream_wrapper_valid_scheme($scheme)) {
form_error($element, t('Invalid file stream wrapper.'));
return FALSE;
}
if ((!is_dir($element['#value']) || !is_writable($element['#value'])) && !file_prepare_directory($element['#value'], FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
form_error($element, t('File location can not be created or is not writable.'));
return FALSE;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* @file
* Hooks provided by the File (Field) Paths module.
*/
/**
* Define field(s) to be displayed on the File (Field) Paths settings form and
* used during the processing of uploaded files.
*
* @param $field
* The field definition this File (Field) Paths settings field applies to.
* @param $instance
* The field instance this File (Field) Paths settings field applies to.
*
* @return array
* An array whose keys are field names and whose values are arrays defining
* the field, with the following key/value pairs:
* - title: The title fo the field.
* - form: A keyed array of Form API elements.
*
* @see hook_filefield_paths_process_file().
*/
function hook_filefield_paths_field_settings($field, $instance) {
return array(
'file_path' => array(
'title' => 'File path',
'form' => array(
'value' => array(
'#type' => 'textfield',
'#title' => t('File path'),
'#maxlength' => 512,
'#size' => 128,
'#element_validate' => array('_file_generic_settings_file_directory_validate'),
'#default_value' => $instance['settings']['file_directory'],
),
),
),
);
}
/**
* Declare a compatible field type for use with File (Field) Paths.
*
* @return array
*/
function hook_filefield_paths_field_type_info() {
return array('file');
}
/**
* Process the uploaded files.
*
* @param $type
* The entity type containing the files for processing.
* @param $entity
* The entity containing the files for processing.
* @param $field
* The definition of the field containing the files for processing.
* @param $instance
* The instance of the field containing the files for processing.
* @param $langcode
* The language code of the field containing the files for processing.
* @param $items
* A pass-by-reference array of all the files for processing.
*
* @see filefield_paths_filefield_paths_process_file().
*/
function hook_filefield_paths_process_file($type, $entity, $field, $instance, $langcode, &$items) {
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* Drush integration.
@@ -12,20 +13,20 @@ function filefield_paths_drush_command() {
$items['ffp-update'] = array(
'description' => 'Retroactively updates all File (Field) Paths of a chosen field instance.',
'arguments' => array(
'arguments' => array(
'entity_type' => 'Entity type.',
'bundle_name' => 'Bundle name.',
'field_name' => 'Field name.'
'field_name' => 'Field name.'
),
'options' => array(
'options' => array(
'all' => 'Retroactively update all File (Field) Paths.',
),
'examples' => array(
'drush ffp-update' => 'Retroactively updates the File (Field) Paths of the instances choosen via an interactive menu.',
'examples' => array(
'drush ffp-update' => 'Retroactively updates the File (Field) Paths of the instances choosen via an interactive menu.',
'drush ffp-update node article field_image' => 'Retroactively updates the File (Field) Paths of all instances of the Article content types Image field.',
'drush ffp-update --all' => 'Retroactively update all File (Field) Paths.',
'drush ffp-update --all' => 'Retroactively update all File (Field) Paths.',
),
'aliases' => array('ffpu'),
'aliases' => array('ffpu'),
);
return $items;
@@ -33,17 +34,23 @@ function filefield_paths_drush_command() {
/**
* Retroactively updates all File (Field) Paths of a chosen field instance.
*
* @param null $entity_type
* @param null $bundle_name
* @param null $field_name
*
* @return string
*/
function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NULL, $field_name = NULL) {
// Build array of information of all entity types, bundle names and field
// names.
$field_types = array_keys(_filefield_paths_get_field_types());
$info = array();
$info = array();
foreach (field_info_fields() as $field) {
if (in_array($field['type'], $field_types)) {
foreach ($field['bundles'] as $entity_type_name => $bundles) {
if (!isset($info[$entity_type_name])) {
$entity_type_info = entity_get_info($entity_type_name);
$entity_type_info = entity_get_info($entity_type_name);
$info[$entity_type_name] = array(
'#label' => "{$entity_type_info['label']} ({$entity_type_name})",
);
@@ -56,6 +63,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
);
}
$field = field_info_instance($entity_type_name, $field['field_name'], $bundle);
$info[$entity_type_name][$bundle][$field['field_name']] = "{$field['label']} ({$field['field_name']})";
}
}
@@ -72,6 +80,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
return '';
}
@@ -96,6 +105,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
return '';
}
@@ -118,6 +128,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
return '';
}
@@ -138,6 +149,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
$instances[] = field_info_instance($entity_type, $field_name, $bundle_name);
}
_filefield_paths_drush_ffp_update($instances);
return '';
}
@@ -148,13 +160,16 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
/**
* Helper function; Invokes File (Field) Paths Retroactive updates.
*
* @param $instances
*/
function _filefield_paths_drush_ffp_update($instances) {
foreach ($instances as $instance) {
filefield_paths_batch_update($instance);
$batch =& batch_get();
$batch['progressive'] = FALSE;
drush_backend_batch_process();
drush_log(dt('!field_name File (Field) Paths updated.', array('!field_name' => "{$instance['label']} ({$instance['entity_type']}-{$instance['bundle']}-{$instance['field_name']})")), 'success');
if (filefield_paths_batch_update($instance)) {
$batch =& batch_get();
$batch['progressive'] = FALSE;
drush_backend_batch_process();
drush_log(dt('!field_name File (Field) Paths updated.', array('!field_name' => "{$instance['label']} ({$instance['entity_type']}-{$instance['bundle']}-{$instance['field_name']})")), 'success');
}
}
}

View File

@@ -1,25 +1,28 @@
name = File (Field) Paths
description = Adds improved Token based file sorting and renaming functionalities.
dependencies[] = token
package = Fields
test_dependencies[] = pathauto
test_dependencies[] = redirect
test_dependencies[] = token
test_dependencies[] = transliteration
configure = admin/config/media/file-system/filefield-paths
core = 7.x
files[] = filefield_paths.install
files[] = filefield_paths.module
files[] = modules/features.inc
files[] = modules/file.inc
files[] = modules/filefield_paths.drush.inc
files[] = modules/filefield_paths.inc
files[] = modules/image.inc
files[] = modules/token.inc
files[] = modules/video.inc
;files[] = tests/filefield_paths.test
; Simpletest files.
; Information added by drupal.org packaging script on 2012-02-07
version = "7.x-1.0-beta3"
files[] = tests/filefield_paths.test
files[] = tests/filefield_paths.general.test
files[] = tests/filefield_paths.text_replace.test
files[] = tests/filefield_paths.tokens.test
files[] = tests/filefield_paths.update.test
files[] = tests/pathauto.test
files[] = tests/redirect.test
files[] = tests/transliteration.test
; Information added by Drupal.org packaging script on 2018-08-14
version = "7.x-1.1"
core = "7.x"
project = "filefield_paths"
datestamp = "1328655041"
datestamp = "1534256584"

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* Install, update and uninstall functions for the File (Field) Paths module.
@@ -13,10 +14,10 @@
function filefield_paths_schema_alter(&$schema) {
$schema['file_managed']['fields']['origname'] = array(
'description' => 'Original name of the file.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
);
}
@@ -28,14 +29,12 @@ function filefield_paths_install() {
// filenames.
db_add_field('file_managed', 'origname', array(
'description' => 'Original name of the file with no path components. Used by the filefield_paths module.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
));
db_update('file_managed')
->expression('origname', 'filename')
->execute();
db_update('file_managed')->expression('origname', 'filename')->execute();
}
/**
@@ -76,10 +75,10 @@ function filefield_paths_update_7103() {
if (!db_field_exists('file_managed', 'origname')) {
db_add_field('file_managed', 'origname', array(
'description' => 'Original name of the file with no path components. Used by the filefield_paths module.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
));
}
db_update('file_managed')
@@ -93,10 +92,10 @@ function filefield_paths_update_7103() {
*/
function filefield_paths_update_7104() {
db_add_field('filefield_paths', 'active_updating', array(
'type' => 'int',
'size' => 'tiny',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => '0'
'default' => '0'
));
// migrate variable to filefield_paths table
@@ -123,10 +122,10 @@ function filefield_paths_update_7104() {
*/
function filefield_paths_update_7105() {
db_change_field('filefield_paths', 'active_updating', 'active_updating', array(
'type' => 'int',
'size' => 'tiny',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0
'default' => 0
));
}
@@ -135,16 +134,16 @@ function filefield_paths_update_7105() {
*/
function filefield_paths_update_7106() {
db_change_field('filefield_paths', 'type', 'type', array(
'type' => 'varchar',
'length' => 128,
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => ''
'default' => ''
));
db_change_field('filefield_paths', 'field', 'field', array(
'type' => 'varchar',
'length' => 128,
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => ''
'default' => ''
));
}
@@ -152,33 +151,57 @@ function filefield_paths_update_7106() {
* Removed filefield_paths table/schema.
*/
function filefield_paths_update_7107() {
$results = db_select('filefield_paths', 'ffp')->fields('ffp')->execute();
foreach ($results as $result) {
$instance = field_info_instance('node', $result->field, $result->type);
if (!is_null($instance) && isset($instance["ffp_{$result->field}}"])) {
$filepath = unserialize($result->filepath);
$filename = unserialize($result->filename);
$instance["ffp_{$result->field}"] = array(
'file_path' => $filepath['value'],
'file_path_cleanup' => array(
'file_path_pathauto' => $filepath['pathauto'],
'file_path_transliterate' => $filepath['transliterate'],
),
'file_name' => $filename['value'],
'file_name_cleanup' => array(
'file_name_pathauto' => $filename['pathauto'],
'file_name_transliterate' => $filename['transliterate'],
),
'active_updating' => $result->active_updating,
);
field_update_instance($instance);
}
}
// Remove filefield_paths table/schema.
db_drop_table('filefield_paths');
// Update field instance settings.
drupal_load('module', 'filefield_paths');
$field_types = array_keys(_filefield_paths_get_field_types());
foreach (field_info_fields() as $field) {
if (in_array($field['type'], $field_types)) {
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle_name) {
$instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
if ($instance["ffp_{$field['field_name']}"] && !isset($instance['settings']['filefield_paths'])) {
if (isset($instance["ffp_{$field['field_name']}"]) && !isset($instance['settings']['filefield_paths'])) {
$instance['settings']['filefield_paths'] = array(
'file_path' => array(
'value' => $instance["ffp_{$field['field_name']}"]['file_path'],
'file_path' => array(
'value' => $instance["ffp_{$field['field_name']}"]['file_path'],
'options' => array(
'pathauto' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_pathauto'],
'pathauto' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_pathauto'],
'transliterate' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_transliterate'],
),
),
'file_name' => array(
'value' => $instance["ffp_{$field['field_name']}"]['file_name'],
'file_name' => array(
'value' => $instance["ffp_{$field['field_name']}"]['file_name'],
'options' => array(
'pathauto' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_pathauto'],
'pathauto' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_pathauto'],
'transliterate' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_transliterate'],
),
),
'retroactive_update' => $instance["ffp_{$field['field_name']}"]['retroactive_update'],
'active_updating' => $instance["ffp_{$field['field_name']}"]['active_updating'],
);
unset($instance["ffp_{$field['field_name']}"]);

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* Contains core functions for the File (Field) Paths module.
@@ -7,36 +8,78 @@
/**
* Include additional files.
*/
$dirname = dirname(__FILE__) . "/modules";
$includes = file_scan_directory($dirname, '/.inc$/');
foreach (module_list() as $module) {
if (file_exists($file = dirname(__FILE__) . "/modules/{$module}.inc")) {
if (isset($includes[$file = "{$dirname}/{$module}.inc"])) {
require_once $file;
}
}
/**
* Implements hook_form_alter().
* Implements hook_menu().
*/
function filefield_paths_form_alter(&$form, $form_state, $form_id) {
function filefield_paths_menu() {
$items['admin/config/media/file-system/filefield-paths'] = array(
'title' => t('File (Field) Paths settings'),
'page callback' => 'drupal_get_form',
'page arguments' => array('filefield_paths_settings_form'),
'access arguments' => array('administer site configuration'),
'type' => MENU_NORMAL_ITEM,
'file' => 'filefield_paths.admin.inc',
);
return $items;
}
/**
* Implements hook_form_alter().
*
* @param $form
*/
function filefield_paths_form_alter(&$form) {
// Force all File (Field) Paths uploads to go to the temporary file system
// prior to being processed.
if (isset($form['#entity']) && isset($form['#entity_type']) && isset($form['#bundle']) && $form['#type'] == 'form') {
filefield_paths_temporary_upload_location($form);
}
$field_types = _filefield_paths_get_field_types();
if (isset($form['#field']) && in_array($form['#field']['type'], array_keys($field_types))) {
$entity_info = entity_get_info($form['#instance']['entity_type']);
$settings = isset($form['#instance']['settings']['filefield_paths']) ? $form['#instance']['settings']['filefield_paths'] : array();
$settings = isset($form['#instance']['settings']['filefield_paths']) ? $form['#instance']['settings']['filefield_paths'] : array();
$form['instance']['settings']['filefield_paths_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Enable File (Field) Paths?'),
'#default_value' => isset($form['#instance']['settings']['filefield_paths_enabled']) ? $form['#instance']['settings']['filefield_paths_enabled'] : TRUE,
'#weight' => 2,
);
// Hide standard File directory field.
$form['instance']['settings']['file_directory']['#access'] = FALSE;
$form['instance']['settings']['file_directory']['#states'] = array(
'visible' => array(
':input[name="instance[settings][filefield_paths_enabled]"]' => array('checked' => FALSE),
),
);
// File (Field) Paths fieldset element.
$form['instance']['settings']['filefield_paths'] = array(
'#type' => 'fieldset',
'#title' => t('File (Field) Path settings'),
'#type' => 'fieldset',
'#title' => t('File (Field) Path settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 1,
'#tree' => TRUE,
'#collapsed' => TRUE,
'#weight' => 3,
'#tree' => TRUE,
'#states' => array(
'visible' => array(
':input[name="instance[settings][filefield_paths_enabled]"]' => array('checked' => TRUE),
),
),
);
// Additional File (Field) Paths widget fields.
$fields = module_invoke_all('filefield_paths_field_settings');
$fields = module_invoke_all('filefield_paths_field_settings', $form['#field'], $form['#instance']);
foreach ($fields as $name => $field) {
// Attach widget fields.
$form['instance']['settings']['filefield_paths'][$name] = array(
@@ -46,13 +89,14 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
// Attach widget field form elements.
if (isset($field['form']) && is_array($field['form'])) {
foreach (array_keys($field['form']) as $delta => $key) {
$form['instance']['settings']['filefield_paths'][$name][$key] = array_merge(
$field['form'][$key],
array(
'#element_validate' => array('token_element_validate'),
'#token_types' => array('file', $entity_info['token type']),
)
);
$form['instance']['settings']['filefield_paths'][$name][$key] = $field['form'][$key];
if (module_exists('token')) {
$form['instance']['settings']['filefield_paths'][$name][$key]['#element_validate'][] = 'token_element_validate';
$form['instance']['settings']['filefield_paths'][$name][$key]['#token_types'] = array(
'file',
$entity_info['token type']
);
}
// Fetch stored value from instance.
if (isset($settings[$name][$key])) {
@@ -62,67 +106,82 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
// Field options.
$form['instance']['settings']['filefield_paths'][$name]['options'] = array(
'#type' => 'fieldset',
'#title' => t('@title options', array('@title' => $field['title'])),
'#type' => 'fieldset',
'#title' => t('@title options', array('@title' => t($field['title']))),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 1,
'#attributes' => array(
'#collapsed' => TRUE,
'#weight' => 1,
'#attributes' => array(
'class' => array("{$name} cleanup")
),
);
// @TODO - Make this more modular.
// Cleanup slashes (/).
$form['instance']['settings']['filefield_paths'][$name]['options']['slashes'] = array(
'#type' => 'checkbox',
'#title' => t('Remove slashes (/) from tokens'),
'#default_value' => isset($settings[$name]['options']['slashes']) ? $settings[$name]['options']['slashes'] : FALSE,
'#description' => t('If checked, any slashes (/) in tokens will be removed from %title.', array('%title' => t($field['title']))),
);
// Cleanup field with Pathauto module.
$form['instance']['settings']['filefield_paths'][$name]['options']['pathauto'] = array(
'#type' => 'checkbox',
'#title' => t('Cleanup using Pathauto') . '.',
'#default_value' => isset($settings[$name]['options']['pathauto']) && module_exists('pathauto')
? $settings[$name]['options']['pathauto']
: FALSE,
'#description' => t('Cleanup @title using', array('@title' => $field['title'])) . ' ' . l(t('Pathauto settings'), 'admin/config/search/path/settings'),
'#disabled' => !module_exists('pathauto'),
'#type' => 'checkbox',
'#title' => t('Cleanup using Pathauto'),
'#default_value' => isset($settings[$name]['options']['pathauto']) && module_exists('pathauto') ? $settings[$name]['options']['pathauto'] : FALSE,
'#description' => t('Cleanup %title using <a href="@pathauto">Pathauto settings</a>.', array(
'%title' => t($field['title']),
'@pathauto' => url('admin/config/search/path/settings')
)),
'#disabled' => !module_exists('pathauto'),
);
// Transliterate field with Transliteration module.
$form['instance']['settings']['filefield_paths'][$name]['options']['transliterate'] = array(
'#type' => 'checkbox',
'#title' => t('Transliterate') . '.',
'#default_value' => isset($settings[$name]['options']['transliterate']) && module_exists('transliteration')
? $settings[$name]['options']['transliterate']
: 0,
'#description' => t('Transliterate @title', array('@title' => $field['title'])) . '.',
'#disabled' => !module_exists('transliteration'),
'#type' => 'checkbox',
'#title' => t('Transliterate'),
'#default_value' => isset($settings[$name]['options']['transliterate']) && module_exists('transliteration') ? $settings[$name]['options']['transliterate'] : 0,
'#description' => t('Provides one-way string transliteration (romanization) and cleans the %title during upload by replacing unwanted characters.', array('%title' => t($field['title']))),
'#disabled' => !module_exists('transliteration'),
);
// Replacement patterns for field.
$form['instance']['settings']['filefield_paths']['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,
if (module_exists('token')) {
$form['instance']['settings']['filefield_paths']['token_tree'] = array(
'#theme' => 'token_tree',
'#token_types' => array('file', $entity_info['token type']),
'#dialog' => TRUE,
'#weight' => 10,
);
}
// Redirect
$form['instance']['settings']['filefield_paths']['redirect'] = array(
'#type' => 'checkbox',
'#title' => t('Create Redirect'),
'#description' => t('Create a redirect to the new location when a previously uploaded file is moved.'),
'#default_value' => isset($settings['redirect']) ? $settings['redirect'] : FALSE,
'#weight' => 11,
);
if (!module_exists('redirect')) {
$form['instance']['settings']['filefield_paths']['redirect']['#disabled'] = TRUE;
$form['instance']['settings']['filefield_paths']['redirect']['#description'] .= '<br />' . t('Requires the <a href="https://drupal.org/project/redirect" target="_blank">Redirect</a> module.');
}
// Retroactive updates.
$form['instance']['settings']['filefield_paths']['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' => 11,
'#type' => 'checkbox',
'#title' => t('Retroactive update'),
'#description' => t('Move and rename previously uploaded files.') . '<div>' . t('<strong class="warning">Warning:</strong> This feature should only be used on developmental servers or with extreme caution.') . '</div>',
'#weight' => 12,
);
// Active updating.
$form['instance']['settings']['filefield_paths']['active_updating'] = array(
'#type' => 'checkbox',
'#title' => t('Active updating'),
'#type' => 'checkbox',
'#title' => t('Active updating'),
'#default_value' => isset($settings['active_updating']) ? $settings['active_updating'] : FALSE,
'#description' => t('Actively move and rename previously uploaded files as required') . '.' .
'<br /> <strong style="color: #FF0000;">' . t('Warning') . ':</strong> ' .
t('This feature should only be used on developmental servers or with extreme caution') . '.',
'#weight' => 12
'#description' => t('Actively move and rename previously uploaded files as required.') . '<div>' . t('<strong class="warning">Warning:</strong> This feature should only be used on developmental servers or with extreme caution.') . '</div>',
'#weight' => 13
);
}
}
@@ -131,14 +190,38 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
}
}
/**
* Recursively set temporary upload location of all File (Field) Paths enabled
* managed file fields.
*
* @param $element
*/
function filefield_paths_temporary_upload_location(&$element) {
if (isset($element['#type']) && $element['#type'] == 'managed_file' && isset($element['#entity_type']) && isset($element['#field_name']) && isset($element['#bundle'])) {
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
if (isset($instance['settings']['filefield_paths_enabled']) && $instance['settings']['filefield_paths_enabled']) {
$element['#upload_location'] = variable_get('filefield_paths_temp_location', 'public://filefield_paths');
}
return;
}
foreach (element_children($element) as $child) {
filefield_paths_temporary_upload_location($element[$child]);
}
}
/**
* Submit callback for File (Field) Paths settings form.
*
* @param $form
* @param $form_state
*/
function filefield_paths_form_submit($form, &$form_state) {
// Retroactive updates.
if ($form_state['values']['instance']['settings']['filefield_paths']['retroactive_update']) {
filefield_paths_batch_update($form_state['values']['instance']);
batch_process($form_state['redirect']);
if ($form_state['values']['instance']['settings']['filefield_paths_enabled'] && $form_state['values']['instance']['settings']['filefield_paths']['retroactive_update']) {
if (filefield_paths_batch_update($form_state['values']['instance'])) {
batch_process($form_state['redirect']);
}
}
}
@@ -146,40 +229,58 @@ function filefield_paths_form_submit($form, &$form_state) {
* Set batch process to update File (Field) Paths.
*
* @param $instance
*
* @return bool
*/
function filefield_paths_batch_update($instance) {
$query = new EntityFieldQuery();
$query = new EntityFieldQuery();
$result = $query->entityCondition('entity_type', $instance['entity_type'])
->entityCondition('bundle', array($instance['bundle']))
->fieldCondition($instance['field_name'])
->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT')
->execute();
$objects = array_keys($result[$instance['entity_type']]);
// If there are no results, do not set a batch as there is nothing to process.
if (empty($result[$instance['entity_type']])) {
return FALSE;
}
$objects = array_keys($result[$instance['entity_type']]);
$instance = field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
// Create batch.
$batch = array(
'title' => t('Updating File (Field) Paths'),
'title' => t('Updating File (Field) Paths'),
'operations' => array(
array('_filefield_paths_batch_update_process', array($objects, $instance))
),
);
batch_set($batch);
return TRUE;
}
/**
* Batch callback for File (Field) Paths retroactive updates.
*
* @param $objects
* @param $instance
* @param $context
*
* @throws FieldException
*/
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;
$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']);
$oid = array_shift($context['sandbox']['objects']);
$entity = current(entity_load($instance['entity_type'], array($oid)));
// Enable active updating if it isn't already enabled.
@@ -189,8 +290,8 @@ function _filefield_paths_batch_update_process($objects, $instance, &$context) {
field_update_instance($instance);
}
// Invoke File (Field) Paths implementation of hook_entity_update().
filefield_paths_entity_update($entity, $instance['entity_type']);
// Invoke field_attach_update().
field_attach_update($instance['entity_type'], $entity);
// Restore active updating to it's previous state if necessary.
if (!$active_updating) {
@@ -210,93 +311,161 @@ function _filefield_paths_batch_update_process($objects, $instance, &$context) {
}
/**
* Implements hook_entity_insert().
* Implements hook_field_storage_pre_insert().
*
* @param $entity_type
* @param $entity
*/
function filefield_paths_entity_insert($entity, $type) {
filefield_paths_entity_update($entity, $type);
function filefield_paths_field_storage_pre_insert($entity_type, $entity) {
filefield_paths_field_storage_pre_update($entity_type, $entity);
}
/**
* Implements hook_entity_update().
* Implements hook_field_storage_pre_update().
*
* @param $entity_type
* @param $entity
*/
function filefield_paths_entity_update($entity, $type) {
function filefield_paths_field_storage_pre_update($entity_type, $entity) {
$field_types = _filefield_paths_get_field_types();
$entity_info = entity_get_info($type);
$bundle_name = !empty($entity_info['entity keys']['bundle']) ? $entity->{$entity_info['entity keys']['bundle']} : $type;
$entity_info = entity_get_info($entity_type);
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
if ($entity_info['fieldable']) {
foreach (field_info_fields($type, $bundle_name) as $field) {
foreach (field_info_fields() as $field) {
if (in_array($field['type'], array_keys($field_types))) {
$files = array();
$instance = field_info_instance($type, $field['field_name'], $bundle_name);
if (isset($entity->{$field['field_name']})) {
$files = array();
$instance = field_info_instance($entity_type, $field['field_name'], $bundle);
$enabled = (isset($instance['settings']['filefield_paths_enabled']) && $instance['settings']['filefield_paths_enabled']) || !isset($instance['settings']['filefield_paths_enabled']);
if ($enabled && isset($entity->{$field['field_name']}) && is_array($entity->{$field['field_name']})) {
foreach ($entity->{$field['field_name']} as $langcode => &$deltas) {
foreach ($deltas as $delta => &$file) {
// Prepare file.
if (function_exists($function = "{$field['module']}_field_load")) {
$items = array(array(&$file));
$function($type, array($entity), $field, array($instance), $langcode, $items, FIELD_LOAD_CURRENT);
$function($entity_type, array($entity), $field, array($instance), $langcode, $items, FIELD_LOAD_CURRENT);
}
$files[] = &$file;
}
}
// Invoke hook_filefield_paths_process_file().
foreach (module_implements('filefield_paths_process_file') as $module) {
if (function_exists($function = "{$module}_filefield_paths_process_file")) {
$function($type, $entity, $field, $instance, $langcode, $files);
// Invoke hook_filefield_paths_process_file().
foreach (module_implements('filefield_paths_process_file') as $module) {
if (function_exists($function = "{$module}_filefield_paths_process_file")) {
$function($entity_type, $entity, $field, $instance, $langcode, $files);
}
}
}
}
}
}
if (isset($entity->revision)) {
// Remember revision flag.
$revision = $entity->revision;
// Remove revision flag as long as fields already processed it, and no need
// to create new revision for moved files.
$entity->revision = FALSE;
}
// Save any changes back to the database.
field_attach_update($type, $entity);
if (isset($entity->revision)) {
// Restore revision flag so that other modules can process it if needed.
$entity->revision = $revision;
}
}
}
/**
* Implements hook_file_presave().
*
* @param $file
*/
function filefield_paths_file_presave($file) {
// Store original filename in the database.
if (empty($file->origname)) {
if (empty($file->origname) && isset($file->filename)) {
$file->origname = $file->filename;
}
}
/**
* Creates a redirect for a moved File field.
*
* @param $source
* @param $path
*
* @throws Exception
*/
function _filefield_paths_create_redirect($source, $path) {
global $base_path;
watchdog('filefield_paths', 'Creating redirect from @source to @path', array(
'@source' => $source,
'@path' => $path
), WATCHDOG_DEBUG);
$redirect = new stdClass();
redirect_object_prepare($redirect);
$parsed_source = parse_url(file_create_url($source), PHP_URL_PATH);
$parsed_path = parse_url(file_create_url($path), PHP_URL_PATH);
$redirect->source = drupal_substr(urldecode($parsed_source), drupal_strlen($base_path));
$redirect->redirect = drupal_substr(urldecode($parsed_path), drupal_strlen($base_path));
// Check if the redirect exists before saving.
$hash = redirect_hash($redirect);
if (!redirect_load_by_hash($hash)) {
redirect_save($redirect);
}
}
/**
* Run regular expression over all available text-based fields.
*
* @param $old
* @param $new
* @param $entity
*/
function _filefield_paths_replace_path($old, $new, $entity) {
// 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']})");
if (isset($info['path'])) {
$info['host'] .= $info['path'];
}
// Build replacement.
$info = parse_url($new);
$info['path'] = !empty($info['path']) ? $info['path'] : '';
$replacement = "_filefield_paths_replace_path_uri_scheme('\\1', '{$old}', '{$new}') . '\\2{$info['host']}{$info['path']}'";
// Generate all path prefix variations.
$prefixes = _filefield_paths_replace_path_get_prefixes($info['scheme'], TRUE);
$prefixes = implode('|', $prefixes);
// Generate all image style path variations.
$styles['raw'] = "styles/REGEX/{$info['scheme']}/";
$styles['urlencode'] = urlencode($styles['raw']);
foreach ($styles as &$style) {
$style = str_replace(array('/', 'REGEX'), array('\/', '(.*?)'), $style);
}
$styles = implode('|', $styles);
// General all path variations.
$paths['raw'] = preg_quote($info['host'], '/');
$paths['urlencode'] = preg_quote(urlencode($info['host']), '/');
$paths['drupal_encode_path'] = preg_quote(drupal_encode_path($info['host']), '/');
$paths = implode('|', $paths);
// Newer versions of the Image module add an 8 character token which is
// required if the image style hasn't been generated yet.
$itok = '';
if (defined('IMAGE_DERIVATIVE_TOKEN')) {
$itok = '((?:[\?|&](?:\S+?&)*|(?:%3F|%26)(?:\S+?%26)*)' . IMAGE_DERIVATIVE_TOKEN . '(?:=|%3D)(\S{8}))*';
}
// Build regular expression pattern.
$pattern = "/({$prefixes})({$styles})*({$paths}){$itok}/";
// Create an anonymous function for the replacement via preg_replace_callback.
$callback = function ($matches) use ($new, $old) {
return filefield_paths_replace_path_callback($matches, $new, $old);
};
if (!$callback) {
watchdog('filefield_paths', 'Unable to create an anonymous function to find references of %old and replace with %new.', array(
'%old' => $old,
'%new' => $new,
));
return;
}
$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/e", $replacement, $item['value']);
foreach (array('value', 'summary') as $column) {
if (isset($item[$column])) {
$item[$column] = preg_replace_callback($pattern, $callback, $item[$column]);
}
}
}
}
}
@@ -304,49 +473,172 @@ function _filefield_paths_replace_path($old, $new, $entity) {
}
/**
* Helper function for File (Field) Paths URI updater regular expression.
* Helper function; Returns all variations of the file path prefix.
*
* Determines what format the old URI prefix was and returns the new URI prefix
* in the same format.
* @param $scheme
* @param bool|FALSE $preg_quote
* @param bool|FALSE $reset
*
* @return mixed
*/
function _filefield_paths_replace_path_uri_scheme($prefix, $old, $new) {
switch (TRUE) {
case $prefix == file_uri_scheme($old) . '://':
return file_uri_scheme($new) . '://';
function _filefield_paths_replace_path_get_prefixes($scheme, $preg_quote = FALSE, $reset = FALSE) {
$prefixes =& drupal_static(__FUNCTION__, array());
case $prefix == file_create_url(file_uri_scheme($old) . '://'):
return file_create_url(file_uri_scheme($new) . '://');
// Force clean urls on.
$clean_url = $GLOBALS['conf']['clean_url'];
$GLOBALS['conf']['clean_url'] = TRUE;
case $prefix == parse_url(file_create_url(file_uri_scheme($old) . '://'), PHP_URL_PATH):
return parse_url(file_create_url(file_uri_scheme($new) . '://'), PHP_URL_PATH);
$id = $scheme . '::' . (string) $preg_quote;
if (!isset($prefixes[$id]) || $reset) {
$prefixes[$id]['uri'] = "{$scheme}://";
$prefixes[$id]['absolute'] = file_create_url($prefixes[$id]['uri']);
$prefixes[$id]['relative'] = parse_url($prefixes[$id]['absolute'], PHP_URL_PATH);
$prefixes[$id]['unclean'] = '?q=' . drupal_substr($prefixes[$id]['relative'], drupal_strlen(base_path()));
foreach ($prefixes[$id] as $key => $prefix) {
$prefixes[$id]["{$key}-urlencode"] = urlencode($prefix);
$prefixes[$id]["{$key}-drupal_encode_path"] = drupal_encode_path($prefix);
}
if ($preg_quote) {
foreach ($prefixes[$id] as $key => $prefix) {
$prefixes[$id][$key] = preg_quote($prefixes[$id][$key], '/');
}
}
}
return $prefix;
// Restore clean url settings.
$GLOBALS['conf']['clean_url'] = $clean_url;
return $prefixes[$id];
}
/**
* Callback for regex string replacement functionality.
*
* @param $matches
* @param $new
* @param $old
*
* @return string
*/
function filefield_paths_replace_path_callback($matches, $new, $old) {
$prefix = $matches[1];
$styles = $matches[2];
$query = isset($matches[6]) ? $matches[6] : '';
// Get file path info for old file.
$old_info = parse_url($old);
if (isset($old_info['path'])) {
$old_info['host'] .= $old_info['path'];
}
// Determine the file path variation type/modifier.
$old_prefixes = _filefield_paths_replace_path_get_prefixes($old_info['scheme']);
$modifier = NULL;
foreach ($old_prefixes as $key => $old_prefix) {
if ($prefix == $old_prefix) {
$parts = explode('-', $key);
$modifier = isset($parts[1]) ? $parts[1] : NULL;
break;
}
}
// Get file path info for new file.
$new_info = parse_url($new);
if (isset($new_info['path'])) {
$new_info['host'] .= $new_info['path'];
}
// Replace prefix.
$prefixes = _filefield_paths_replace_path_get_prefixes($new_info['scheme']);
if (isset($key) && isset($prefixes[$key])) {
$prefix = $prefixes[$key];
}
// Replace styles directory.
if (!empty($styles)) {
$styles = str_replace($old_info['scheme'], $new_info['scheme'], $styles);
// Newer versions of the Image module add an 8 character token which is
// required if the image style hasn't been generated yet.
if (defined('IMAGE_DERIVATIVE_TOKEN') && isset($matches[7])) {
$image_style = !empty($matches[3]) ? $matches[3] : $matches[4];
// Only replace the token if the old one was valid.
if ($matches[7] == image_style_path_token($image_style, $old)) {
$query = substr_replace($query, image_style_path_token($image_style, $new), -strlen($matches[7]));
}
}
}
// Replace path.
$path = $new_info['host'];
if (!is_null($modifier) && function_exists($modifier)) {
$path = call_user_func($modifier, $path);
}
return $prefix . $styles . $path . $query;
}
/**
* Process and cleanup strings.
*
* @param $value
* @param $data
* @param array $settings
*
* @return mixed|string
*/
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;
$transliterate = module_exists('transliteration') && isset($settings['transliterate']) && $settings['transliterate'];
$pathauto = module_exists('pathauto') && isset($settings['pathauto']) && $settings['pathauto'] == TRUE;
$remove_slashes = !empty($settings['slashes']);
if ($pathauto == TRUE) {
module_load_include('inc', 'pathauto');
}
// If '/' is to be removed from tokens, token replacement need to happen after
// splitting the paths to subdirs, otherwise tokens containing '/' will be
// part of the final path.
if (!$remove_slashes) {
$value = token_replace($value, $data, array('clear' => TRUE));
}
$paths = explode('/', $value);
foreach ($paths as &$path) {
// Process string tokens.
$path = token_replace($path, $data, array('clear' => TRUE));
// Cleanup with pathauto.
foreach ($paths as $i => &$path) {
if ($remove_slashes) {
$path = token_replace($path, $data, array('clear' => TRUE));
}
if ($pathauto == TRUE) {
$path_parts = explode('.', $path);
foreach ($path_parts as &$path_part) {
$path_part = pathauto_cleanstring($path_part);
if ('file_name' == $settings['context'] && count($paths) == $i + 1) {
$pathinfo = pathinfo($path);
$basename = drupal_basename($path);
$extension = preg_match('/\.[^.]+$/', $basename, $matches) ? $matches[0] : NULL;
$pathinfo['filename'] = !is_null($extension) ? drupal_substr($basename, 0, drupal_strlen($basename) - drupal_strlen($extension)) : $basename;
if ($remove_slashes) {
$path = '';
if (!empty($pathinfo['dirname']) && $pathinfo['dirname'] !== '.') {
$path .= $pathinfo['dirname'] . '/';
}
$path .= $pathinfo['filename'];
$path = pathauto_cleanstring($path);
if (!empty($pathinfo['extension'])) {
$path .= '.' . pathauto_cleanstring($pathinfo['extension']);
}
$path = str_replace('/', '', $path);
}
else {
$path = str_replace($pathinfo['filename'], pathauto_cleanstring($pathinfo['filename']), $path);
}
}
$path = implode('.', $path_parts);
else {
$path = pathauto_cleanstring($path);
}
}
elseif ($remove_slashes) {
$path = str_replace('/', '', $path);
}
// Transliterate string.
@@ -363,7 +655,11 @@ function filefield_paths_process_string($value, $data, $settings = array()) {
}
/**
* Provides a list of all available field types for use with File (Field) Paths.
*
* @param bool|FALSE $reset
*
* @return array
*/
function _filefield_paths_get_field_types($reset = FALSE) {
$field_types = &drupal_static(__FUNCTION__);
@@ -372,7 +668,7 @@ function _filefield_paths_get_field_types($reset = FALSE) {
$field_types = module_invoke_all('filefield_paths_field_type_info');
$field_types = array_flip($field_types);
foreach (array_keys($field_types) as $type) {
$info = field_info_field_types($type);
$info = field_info_field_types($type);
$field_types[$type] = array(
'label' => $info['label']
);
@@ -381,3 +677,4 @@ function _filefield_paths_get_field_types($reset = FALSE) {
return $field_types;
}

View File

@@ -0,0 +1,72 @@
<?php
/**
* @file
* Tokens for the File (Field) Paths module.
*/
/**
* Implements hook_token_info().
*
* @return mixed
*/
function filefield_paths_token_info() {
$info['tokens']['file']['ffp-name-only'] = array(
'name' => t("File name"),
'description' => t("File name without extension."),
);
$info['tokens']['file']['ffp-name-only-original'] = array(
'name' => t("File name - original"),
'description' => t("File name without extension - original."),
);
$info['tokens']['file']['ffp-extension-original'] = array(
'name' => t("File extension - original"),
'description' => t("File extension - original."),
);
return $info;
}
/**
* Implements hook_tokens().
*
* @param $type
* @param $tokens
* @param array $data
*
* @return array
*/
function filefield_paths_tokens($type, $tokens, array $data = array()) {
$url_options = array('absolute' => TRUE);
if (isset($language)) {
$url_options['language'] = $language;
}
$replacements = array();
if ($type == 'file' && !empty($data['file'])) {
$file = $data['file'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'ffp-name-only':
$basename = drupal_basename($file->filename);
$extension = preg_match('/\.[^.]+$/', $basename, $matches) ? $matches[0] : NULL;
$replacements[$original] = !is_null($extension) ? drupal_substr($basename, 0, drupal_strlen($basename) - drupal_strlen($extension)) : $basename;
break;
case 'ffp-name-only-original':
$basename = drupal_basename($file->origname);
$extension = preg_match('/\.[^.]+$/', $basename, $matches) ? $matches[0] : NULL;
$replacements[$original] = !is_null($extension) ? drupal_substr($basename, 0, drupal_strlen($basename) - drupal_strlen($extension)) : $basename;
break;
case 'ffp-extension-original':
$replacements[$original] = preg_match('/[^.]+$/', drupal_basename($file->origname), $matches) ? $matches[0] : NULL;
break;
}
}
}
return $replacements;
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* @file
* Contains Variable functions for the File (Field) Paths module.
*/
/**
* Implements hook_variable_info().
*
* @return mixed
*/
function filefield_paths_variable_info() {
$variables['filefield_paths_temp_location'] = array(
'title' => t('Temporary file location'),
'type' => 'string',
'default' => 'public://filefield_paths',
'description' => t('The location that unprocessed files will be uploaded priot to being processed by File (Field) Paths.<br />It is recommended that you use the temporary file system (temporary://) if your server configuration allows for that.'),
'validate callback' => 'filefield_paths_variable_temp_location_validate',
'group' => 'filefield_paths',
);
return $variables;
}
/**
* Validate callback for 'Temporary file location' variable.
*
* @param $element
*/
function filefield_paths_variable_temp_location_validate($element) {
// Add FAPI element keys for standard validation callback.
$element['#parents'] = array('filefield_paths_temp_location');
$element['#value'] = $element['value'];
// Pass element through standard validation callback.
module_load_include('admin.inc', 'filefield_paths');
filefield_paths_settings_form_temp_location_validate($element);
}
/**
* Implements hook_variable_group_info().
*
* @return mixed
*/
function filefield_paths_variable_group_info() {
$groups['filefield_paths'] = array(
'title' => t('File (Field) Paths'),
'description' => t('File (Field) Paths settings.'),
'access' => 'administer site configuration',
'path' => array(
'admin/config/media/file-system/filefield-paths'
),
);
return $groups;
}

View File

@@ -1,16 +1,21 @@
<?php
/**
* @file
* Features module integration.
*/
/**
* Implements hook_features_pipe_field_alter().
* Implements hook_features_pipe_field_instance_alter().
*
* This determines whether exported fields contain File (Field) Paths settings
* and if so adds File (Field) Paths as a dependency.
*
* @param $pipe
* @param $data
* @param $export
*/
function filefield_paths_features_pipe_field_alter(&$pipe, $data, &$export) {
function filefield_paths_features_pipe_field_instance_alter(&$pipe, $data, &$export) {
foreach ($data as $field_identifier) {
list($entity_type, $bundle_name, $field_name) = explode('-', $field_identifier);
$instance = field_info_instance($entity_type, $field_name, $bundle_name);
@@ -19,3 +24,14 @@ function filefield_paths_features_pipe_field_alter(&$pipe, $data, &$export) {
}
}
}
/**
* Implements hook_features_pipe_field_alter().
*
* @param $pipe
* @param $data
* @param $export
*/
function filefield_paths_features_pipe_field_alter(&$pipe, $data, &$export) {
filefield_paths_features_pipe_field_instance_alter($pipe, $data, $export);
}

View File

@@ -1,11 +1,14 @@
<?php
/**
* @file
* File module integration.
*/
/**
* Implements hook_filefield_paths_filed_type_info() on behalf of file.module.
* Implements hook_filefield_paths_field_type_info() on behalf of file.module.
*
* @return array
*/
function file_filefield_paths_field_type_info() {
return array('file');

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* File (Field) Paths module integration.
@@ -6,31 +7,35 @@
/**
* Implements hook_filefield_paths_field_settings().
*
* @param $field
* @param $instance
*
* @return array
*/
function filefield_paths_filefield_paths_field_settings() {
function filefield_paths_filefield_paths_field_settings($field, $instance) {
return array(
'file_path' => array(
'title' => 'File path',
'sql' => 'filepath',
'form' => array(
'form' => array(
'value' => array(
'#type' => 'textfield',
'#title' => t('File path'),
'#maxlength' => 512,
'#size' => 128,
'#type' => 'textfield',
'#title' => t('File path'),
'#maxlength' => 512,
'#size' => 128,
'#element_validate' => array('_file_generic_settings_file_directory_validate'),
'#default_value' => $instance['settings']['file_directory'],
),
),
),
'file_name' => array(
'title' => 'File name',
'sql' => 'filename',
'form' => array(
'form' => array(
'value' => array(
'#type' => 'textfield',
'#title' => t('File name'),
'#type' => 'textfield',
'#title' => t('File name'),
'#maxlength' => 512,
'#size' => 128,
'#default_value' => '[file:ffp-name-only-original].[file:ffp-extension-original]',
),
),
@@ -40,42 +45,86 @@ function filefield_paths_filefield_paths_field_settings() {
/**
* Implements hook_filefield_paths_process_file().
*
* @param $type
* @param $entity
* @param $field
* @param $instance
* @param $langcode
* @param $items
*/
function filefield_paths_filefield_paths_process_file($type, $entity, $field, $instance, $langcode, &$items) {
$settings = $instance['settings']['filefield_paths'];
foreach ($items as &$file) {
if ($file['timestamp'] == REQUEST_TIME || $settings['active_updating']) {
$token_data = array(
'file' => (object) $file,
$type => $entity
);
if (isset($instance['settings']['filefield_paths'])) {
$settings = $instance['settings']['filefield_paths'];
// Copy the original file for comparision purposes.
$old_file = $file;
// Process filename.
$file['filename'] = !empty($settings['file_name']['value'])
? filefield_paths_process_string($settings['file_name']['value'], $token_data, $settings['file_name']['options'])
: $file['filename'];
// Process filepath.
$file['uri'] = "{$field['settings']['uri_scheme']}://" . filefield_paths_process_string($settings['file_path']['value'] . "/{$file['filename']}", $token_data, $settings['file_path']['options']);
// Finalize file if necessary.
if ($file !== $old_file) {
if (file_prepare_directory(drupal_dirname($file['uri']), FILE_CREATE_DIRECTORY) && file_move((object) $old_file, $file['uri'])) {
// Process regular expression.
_filefield_paths_replace_path($old_file['uri'], $file['uri'], $entity);
// Remove any old empty directories.
$scheme = file_uri_scheme($old_file['uri']);
$paths = explode('/', str_replace("{$scheme}://", '', drupal_dirname($old_file['uri'])));
while ($paths) {
if (@drupal_rmdir("{$scheme}://" . implode('/', $paths)) == TRUE) {
array_pop($paths);
continue;
// Check that the destination is writeable.
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE);
foreach ($items as &$file) {
$source_scheme = file_uri_scheme($file['uri']);
$temporary_scheme = file_uri_scheme(variable_get('filefield_paths_temp_location', 'public://filefield_paths'));
$destination_scheme = $field['settings']['uri_scheme'];
if (in_array($source_scheme, array($temporary_scheme, $destination_scheme)) && !empty($wrappers[$destination_scheme])) {
// Process file if this is a new entity, 'Active updating' is set or
// file wasn't previously attached to the entity.
if (isset($entity->original) && empty($settings['active_updating']) && !empty($entity->original->{$field['field_name']}[$langcode])) {
foreach ($entity->original->{$field['field_name']}[$langcode] as $original_file) {
if ($original_file['fid'] == $file['fid']) {
continue(2);
}
break;
}
}
$token_data = array(
'file' => (object) $file,
$type => $entity
);
// Copy the original file for comparison purposes.
$old_file = $file;
// Process filename.
$settings['file_name']['options']['context'] = 'file_name';
$file['filename'] = !empty($settings['file_name']['value']) ? filefield_paths_process_string($settings['file_name']['value'], $token_data, $settings['file_name']['options']) : $file['filename'];
// Process filepath.
$settings['file_path']['options']['context'] = 'file_path';
$path = filefield_paths_process_string($settings['file_path']['value'], $token_data, $settings['file_path']['options']);
$file['uri'] = file_stream_wrapper_uri_normalize("{$destination_scheme}://{$path}/{$file['filename']}");
// Ensure file uri is no more than 255 characters.
if (drupal_strlen($file['uri']) > 255) {
watchdog('filefield_paths', 'File path was truncated.', array(), WATCHDOG_INFO);
$pathinfo = pathinfo($file['uri']);
$file['uri'] = drupal_substr($file['uri'], 0, 254 - drupal_strlen($pathinfo['extension'])) . ".{$pathinfo['extension']}";
}
// Finalize file if necessary.
if ($file !== $old_file) {
$dirname = drupal_dirname($file['uri']);
if (file_prepare_directory($dirname, FILE_CREATE_DIRECTORY) && $new_file = file_move((object) $old_file, $file['uri'])) {
// Process regular expression.
_filefield_paths_replace_path($old_file['uri'], $file['uri'], $entity);
// Create redirect from old location.
if (module_exists('redirect') && !empty($settings['redirect']) && $settings['active_updating']) {
_filefield_paths_create_redirect($old_file['uri'], $new_file->uri);
}
// Remove any old empty directories.
$paths = explode('/', str_replace("{$source_scheme}://", '', drupal_dirname($old_file['uri'])));
while ($paths) {
if (@drupal_rmdir("{$source_scheme}://" . implode('/', $paths)) == TRUE) {
array_pop($paths);
continue;
}
break;
}
}
else {
watchdog('filefield_paths', 'The file %old could not be moved to the destination of %new. Ensure your permissions are set correctly.', array(
'%old' => $old_file['uri'],
'%new' => $file['uri'],
));
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* Image module integration.
@@ -6,7 +7,23 @@
/**
* Implements hook_filefield_paths_field_type_info() on behalf of image.module.
*
* @return array
*/
function image_filefield_paths_field_type_info() {
return array('image');
}
/**
* Implements hook_menu_alter().
*
* @param $items
*/
function filefield_paths_menu_alter(&$items) {
// Workaround for issue with 'temporary://' image styles not being generated
// correctly in Drupal core Image module.
// @see https://www.drupal.org/node/2560139
if (!isset($items['system/temporary/styles/%image_style']) && isset($items['system/files/styles/%image_style'])) {
$items['system/temporary/styles/%image_style'] = $items['system/files/styles/%image_style'];
}
}

View File

@@ -1,63 +0,0 @@
<?php
/**
* @file
* Token module integration.
*/
/**
* Implements hook_token_info().
*/
function filefield_paths_token_info() {
$info['tokens']['file']['ffp-name-only'] = array(
'name' => t("File name"),
'description' => t("File name without extension."),
);
$info['tokens']['file']['ffp-name-only-original'] = array(
'name' => t("File name - original"),
'description' => t("File name without extension - original."),
);
$info['tokens']['file']['ffp-extension-original'] = array(
'name' => t("File extension - original"),
'description' => t("File extension - original."),
);
return $info;
}
/**
* Implements hook_tokens().
*/
function filefield_paths_tokens($type, $tokens, array $data = array(), array $options = array()) {
$url_options = array('absolute' => TRUE);
if (isset($language)) {
$url_options['language'] = $language;
}
$sanitize = !empty($options['sanitize']);
$replacements = array();
if ($type == 'file' && !empty($data['file'])) {
$file = $data['file'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'ffp-name-only':
$info = pathinfo($file->filename);
$replacements[$original] = $info['filename'];
break;
case 'ffp-name-only-original':
$info = pathinfo($file->origname);
$replacements[$original] = $info['filename'];
break;
case 'ffp-extension-original':
$info = pathinfo($file->origname);
$replacements[$original] = $info['extension'];
break;
}
}
}
return $replacements;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @file
* Video module integration.
@@ -6,6 +7,8 @@
/**
* Implements hook_filefield_paths_field_type_info() on behalf of video.module.
*
* @return array
*/
function video_filefield_paths_field_type_info() {
return array('video');

View File

@@ -0,0 +1,327 @@
<?php
/**
* @file
* Tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsGeneralTestCase
*/
class FileFieldPathsGeneralTestCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'General functionality',
'description' => 'Test general functionality.',
'group' => 'File (Field) Paths',
);
}
/**
* Test that the File (Field) Paths UI works as expected.
*/
public function testAddField() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$instance_settings = array('file_directory' => "fields/{$field_name}");
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Ensure File (Field) Paths settings are present.
$this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
$this->assertText('Enable File (Field) Paths?', t('File (Field) Path settings are present.'));
// Ensure that 'Enable File (Field) Paths?' is a direct sibling of
// 'File (Field) Path settings'.
$element = $this->xpath('//div[contains(@class, :class)]/following-sibling::*[1]/@id', array(':class' => 'form-item-instance-settings-filefield-paths-enabled'));
$this->assert(isset($element[0]) && 'edit-instance-settings-filefield-paths' == (string) $element[0], t('Enable checkbox is next to settings fieldset.'));
// Ensure that the File path used the File directory as it's default value.
$this->assertFieldByName('instance[settings][filefield_paths][file_path][value]', "fields/{$field_name}");
}
/**
* Test File (Field) Paths works as normal when no file uploaded.
*/
public function testNoFile() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node without a file attached.
$this->drupalCreateNode(array('type' => $this->content_type));
}
/**
* Test a basic file upload with File (Field) Paths.
*/
public function testUploadFile() {
$langcode = LANGUAGE_NONE;
// Create a File field with 'node/[node:nid]' as the File path and
// '[node:nid].[file:ffp-extension-original]' as the File name.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
$schemes = array('public', 'private');
foreach ($schemes as $scheme) {
// Set the field URI scheme.
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", array('field[settings][uri_scheme]' => $scheme), t('Save settings'));
// Upload a file to a node.
$test_file = $this->getTestFile('text');
$this->drupalGet("node/add/{$this->content_type}");
$edit['title'] = $this->randomName();
$edit["files[{$field_name}_{$langcode}_0]"] = $test_file->uri;
$this->drupalPost(NULL, $edit, t('Upload'));
// Ensure that the file was put into the Temporary file location.
$temp_location = variable_get('filefield_paths_temp_location', 'public://filefield_paths');
$this->assertRaw(file_create_url("{$temp_location}/{$test_file->filename}"), t('File has been uploaded to the temporary file location.'));
// Save the node.
$this->drupalPost(NULL, array(), t('Save'));
// Get created Node ID.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
// Ensure that the File path has been processed correctly.
$uri = file_create_url("{$scheme}://node/{$nid}/{$nid}.txt");
$this->assertRaw($uri, t('The File path has been processed correctly.'));
// Delete the node so we can change the URI scheme.
node_delete($nid);
}
}
/**
* Tests a multivalue file upload with File (Field) Paths.
*/
public function testUploadFileMultivalue() {
$langcode = LANGUAGE_NONE;
// Create a multivalue File field with 'node/[node:nid]' as the File path
// and '[file:fid].txt' as the File name.
$field_name = drupal_strtolower($this->randomName());
$field_settings['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$instance_settings['filefield_paths']['file_name']['value'] = '[file:fid].txt';
$this->createFileField($field_name, $this->content_type, $field_settings, $instance_settings);
// Create a node with three (3) test files.
$text_files = $this->drupalGetTestFiles('text');
$this->drupalGet("node/add/{$this->content_type}");
$this->drupalPost(NULL, array("files[{$field_name}_{$langcode}_0]" => drupal_realpath($text_files[0]->uri)), t('Upload'));
$this->drupalPost(NULL, array("files[{$field_name}_{$langcode}_1]" => drupal_realpath($text_files[1]->uri)), t('Upload'));
$edit = array(
'title' => $this->randomName(),
"files[{$field_name}_{$langcode}_2]" => drupal_realpath($text_files[1]->uri),
);
$this->drupalPost(NULL, $edit, t('Save'));
// Get created Node ID.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
// Ensure that the File path has been processed correctly.
$this->assertRaw("{$this->public_files_directory}/node/{$nid}/1.txt", t('The first File path has been processed correctly.'));
$this->assertRaw("{$this->public_files_directory}/node/{$nid}/2.txt", t('The second File path has been processed correctly.'));
$this->assertRaw("{$this->public_files_directory}/node/{$nid}/3.txt", t('The third File path has been processed correctly.'));
}
/**
* Test File (Field) Paths with a very long path.
*/
public function testLongPath() {
// Create a File field with 'node/[random:hash:sha256]' as the File path.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[random:hash:sha512]/[random:hash:sha512]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
// Ensure file path is no more than 255 characters.
$node = node_load($nid, NULL, TRUE);
$this->assert(drupal_strlen($node->{$field_name}[LANGUAGE_NONE][0]['uri']) <= 255, t('File path is no more than 255 characters'));
}
/**
* Test File (Field) Paths on a programmatically added file.
*/
public function testProgrammaticAttach() {
// Create a File field with 'node/[node:nid]' as the File path and
// '[node:nid].[file:ffp-extension-original]' as the File name.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node without an attached file.
$node = $this->drupalCreateNode(array('type' => $this->content_type));
// Create a file object.
$test_file = $this->getTestFile('text');
$file = new stdClass();
$file->fid = NULL;
$file->uri = $test_file->uri;
$file->filename = basename($file->uri);
$file->filemime = file_get_mimetype($file->uri);
$file->uid = $GLOBALS['user']->uid;
$file->status = FILE_STATUS_PERMANENT;
$file->display = TRUE;
file_save($file);
// Adjust timestamp to simulate real-world experience.
$file->timestamp = REQUEST_TIME - 60;
// Attach the file to the node.
$node->{$field_name}[LANGUAGE_NONE][0] = (array) $file;
node_save($node);
// Ensure that the File path has been processed correctly.
$node = node_load($node->nid, NULL, TRUE);
$this->assertEqual("public://node/{$node->nid}/{$node->nid}.txt", $node->{$field_name}[LANGUAGE_NONE][0]['uri'], t('The File path has been processed correctly.'));
}
/**
* Test File (Field) Paths slashes cleanup functionality.
*/
public function testSlashes() {
$langcode = LANGUAGE_NONE;
// Create a File field with 'node/[node:title]' as the File path and
// '[node:title].[file:ffp-extension-original]' as the File name.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
$instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$title = "{$this->randomName()}/{$this->randomName()}";
$edit['title'] = $title;
$edit["body[{$langcode}][0][value]"] = '';
$edit["files[{$field_name}_{$langcode}_0]"] = drupal_realpath($test_file->uri);
$this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
// Get created Node ID.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
// Ensure slashes are present in file path and name.
$node = node_load($nid);
$this->assertEqual("public://node/{$title}/{$title}.txt", $node->{$field_name}[$langcode][0]['uri']);
// Remove slashes.
$edit = array(
'instance[settings][filefield_paths][file_path][options][slashes]' => TRUE,
'instance[settings][filefield_paths][file_name][options][slashes]' => TRUE,
'instance[settings][filefield_paths][retroactive_update]' => TRUE,
);
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
// Ensure slashes are not present in file path and name.
$node = node_load($nid, NULL, TRUE);
$title = str_replace('/', '', $title);
$this->assertEqual("public://node/{$title}/{$title}.txt", $node->{$field_name}[$langcode][0]['uri']);
}
/**
* Test a file usage of a basic file upload with File (Field) Paths.
*/
public function testFileUsage() {
// Create a File field with 'node/[node:nid]' as the File path.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
// Get file usage for uploaded file.
$node = node_load($nid, NULL, TRUE);
$items = field_get_items('node', $node, $field_name);
$file = file_load($items[0]['fid']);
$usage = file_usage_list($file);
// Ensure file usage count for new node is correct.
$this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 1, t('File usage count for new node is correct.'));
// Update node.
$this->drupalPost("node/{$nid}/edit", array(), t('Save'));
$usage = file_usage_list($file);
// Ensure file usage count for updated node is correct.
$this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 1, t('File usage count for updated node is correct.'));
// Update node with revision.
$this->drupalPost("node/{$nid}/edit", array('revision' => TRUE), t('Save'));
$usage = file_usage_list($file);
// Ensure file usage count for updated node with revision is correct.
$this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 2, t('File usage count for updated node with revision is correct.'));
}
/**
* Test File (Field) Paths works with read-only stream wrappers.
*/
public function testReadOnly() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$field_settings = array('uri_scheme' => 'ffp');
$instance_settings = array('file_directory' => "fields/{$field_name}");
$this->createFileField($field_name, $this->content_type, $field_settings, $instance_settings);
// Get a test file.
$file = $this->getTestFile('image');
// Prepare the file for the test 'ffp://' read-only stream wrapper.
$file->uri = str_replace('public', 'ffp', $file->uri);
$uri = file_stream_wrapper_uri_normalize($file->uri);
// Create a file object.
$file = new stdClass();
$file->fid = NULL;
$file->uri = $uri;
$file->filename = basename($file->uri);
$file->filemime = file_get_mimetype($file->uri);
$file->uid = $GLOBALS['user']->uid;
$file->status = FILE_STATUS_PERMANENT;
$file->display = TRUE;
file_save($file);
// Attach the file to a node.
$node = array();
$node['type'] = $this->content_type;
$node[$field_name][LANGUAGE_NONE][0] = (array) $file;
$node = $this->drupalCreateNode($node);
// Ensure file has been attached to a node.
$this->assert(isset($node->{$field_name}[LANGUAGE_NONE][0]) && !empty($node->{$field_name}[LANGUAGE_NONE][0]), t('Read-only file is correctly attached to a node.'));
$edit = array();
$edit['instance[settings][filefield_paths][retroactive_update]'] = TRUE;
$edit['instance[settings][filefield_paths][file_path][value]'] = 'node/[node:nid]';
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
// Ensure file is still in original location.
$this->drupalGet("node/{$node->nid}");
$this->assertRaw("{$this->public_files_directory}/{$file->filename}", t('Read-only file not affected by Retroactive updates.'));
}
}

View File

@@ -0,0 +1,90 @@
<?php
/**
* @file
* Tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsTestCase
*/
class FileFieldPathsTestCase extends FileFieldTestCase {
var $content_type = NULL;
var $public_files_directory = NULL;
/**
* @inheritdoc
*/
function setUp() {
// Setup required modules.
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
$modules[] = 'filefield_paths_test';
$modules[] = 'image';
$modules[] = 'token';
parent::setUp($modules);
// Include all optional dependency files.
$dirname = dirname(__FILE__) . "/../modules";
$includes = file_scan_directory($dirname, '/.inc$/');
foreach (array_keys($includes) as $file) {
require_once $file;
}
// Create a content type.
$content_type = $this->drupalCreateContentType();
$this->content_type = $content_type->name;
}
/**
* @inheritdoc
*/
function createFileField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
parent::createFileField($name, $type_name, $field_settings, $instance_settings, $widget_settings);
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$name}", array(), t('Save settings'));
}
/**
* Creates a new image field.
*
* @param $name
* The name of the new field (all lowercase), exclude the "field_" prefix.
* @param $type_name
* The node type that this field will be added to.
* @param $field_settings
* A list of field settings that will be added to the defaults.
* @param $instance_settings
* A list of instance settings that will be added to the instance defaults.
* @param $widget_settings
* A list of widget settings that will be added to the widget defaults.
*/
function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
$field = array(
'field_name' => $name,
'type' => 'image',
'settings' => array(),
'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
);
$field['settings'] = array_merge($field['settings'], $field_settings);
field_create_field($field);
$instance = array(
'field_name' => $name,
'label' => $name,
'entity_type' => 'node',
'bundle' => $type_name,
'required' => !empty($instance_settings['required']),
'settings' => array(),
'widget' => array(
'type' => 'image_image',
'settings' => array(),
),
);
$instance['settings'] = array_merge($instance['settings'], $instance_settings);
$instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings);
field_create_instance($instance);
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$name}", array(), t('Save settings'));
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* @file
* Tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsTextReplaceTestCase
*/
class FileFieldPathsTextReplaceTestCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Text replace functionality',
'description' => 'Tests text replace functionality.',
'group' => 'File (Field) Paths',
);
}
/**
* Generates all variations of the URI for text replacement.
*
* @param $uri
* @param string $type
*
* @return mixed
*/
protected function getPathVariations($uri, $type = 'image') {
// Force clean urls on.
$GLOBALS['conf']['clean_url'] = TRUE;
$variations['uri'] = $uri;
$variations['absolute'] = urldecode(file_create_url($uri));
$variations['relative'] = parse_url($variations['absolute'], PHP_URL_PATH);
if ($type == 'image') {
$variations['image_style'] = urldecode(image_style_url('thumbnail', $uri));
$variations['image_style_relative'] = parse_url($variations['image_style'], PHP_URL_PATH) . '?' . parse_url($variations['image_style'], PHP_URL_QUERY);
}
foreach ($variations as $key => $value) {
$variations["{$key}_urlencode"] = urlencode($value);
$variations["{$key}_drupal_encode_path"] = drupal_encode_path($value);
}
return $variations;
}
/**
* Test text replace with multiple file uploads.
*/
public function testTextReplace() {
$langcode = LANGUAGE_NONE;
// Create a File field with 'node/[node:nid]' as the File path and
// '[node:nid].png as the File name,
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
$instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].png';
$this->createImageField($field_name, $this->content_type, array(), $instance_settings);
// Prepare test files.
$test_files['basic_image'] = $this->getTestFile('image');
$test_files['complex_image'] = $this->getTestFile('image');
file_unmanaged_copy($test_files['complex_image']->uri, 'public://test image.png');
$files = file_scan_directory('public://', '/test image\.png/');
$test_files['complex_image'] = current($files);
// Iterate over each test file.
foreach ($test_files as $type => $test_file) {
// Get the available file paths for the test file.
$uri = str_replace('public://', variable_get('filefield_paths_temp_location', 'public://filefield_paths') . '/', $test_file->uri);
$source_paths = $this->getPathVariations($uri);
// Upload a file and reference the original path(s) to the file in the body
// field.
$edit['title'] = $this->randomName();
$edit["body[{$langcode}][0][value]"] = '';
$edit["files[{$field_name}_{$langcode}_0]"] = drupal_realpath($test_file->uri);
foreach ($source_paths as $key => $value) {
$edit["body[{$langcode}][0][value]"] .= "{$key}: {$value}\n";
}
$this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
// Get created Node ID.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
// Ensure body field has updated file path.
$node = node_load($nid);
$destination_paths = $this->getPathVariations($node->{$field_name}[$langcode][0]['uri']);
foreach ($destination_paths as $key => $value) {
$this->assert($source_paths[$key] !== $destination_paths[$key] && strpos($node->body[$langcode][0]['value'], "{$key}: {$value}") !== FALSE, t('@type %key file path replaced successfully.', array(
'@type' => str_replace('_', ' ', drupal_ucfirst($type)),
'%key' => $key
)));
}
}
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* @file
* Tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsTokensTestCase
*/
class FileFieldPathsTokensTestCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Token functionality',
'description' => 'Tests File (Field) Paths tokens.',
'group' => 'File (Field) Paths',
);
}
/**
* @param $token
* @param $value
* @param $data
*/
public function assertToken($token, $value, $data) {
$result = token_replace($token, $data);
$this->assertEqual($result, $value, t('Token @token equals @value', array(
'@token' => $token,
'@value' => $value
)));
}
/**
* Test token values with a text file.
*/
public function testTokensBasic() {
// Prepare a test text file.
$text_file = $this->getTestFile('text');
file_save($text_file);
// Ensure tokens are processed correctly.
$data = array('file' => $text_file);
$this->assertToken('[file:ffp-name-only]', 'text-0', $data);
$this->assertToken('[file:ffp-name-only-original]', 'text-0', $data);
$this->assertToken('[file:ffp-extension-original]', 'txt', $data);
}
/**
* Test token values with a moved text file.
*/
public function testTokensMoved() {
// Prepare a test text file.
$text_file = $this->getTestFile('text');
file_save($text_file);
// Move the text file.
$moved_file = file_move($text_file, 'public://moved.diff');
// Ensure tokens are processed correctly.
$data = array('file' => $moved_file);
$this->assertToken('[file:ffp-name-only]', 'moved', $data);
$this->assertToken('[file:ffp-name-only-original]', 'text-0', $data);
$this->assertToken('[file:ffp-extension-original]', 'txt', $data);
}
/**
* Test token values with a multi-extension text file.
*/
public function testTokensMultiExtension() {
// Prepare a test text file.
$text_file = $this->getTestFile('text');
file_unmanaged_copy($text_file->uri, 'public://text.multiext.txt');
$files = file_scan_directory('public://', '/text\.multiext\.txt/');
$multiext_file = current($files);
file_save($multiext_file);
// Ensure tokens are processed correctly.
$data = array('file' => $multiext_file);
$this->assertToken('[file:ffp-name-only]', 'text.multiext', $data);
$this->assertToken('[file:ffp-name-only-original]', 'text.multiext', $data);
$this->assertToken('[file:ffp-extension-original]', 'txt', $data);
}
/**
* Test token value with a UTF file.
* @see https://www.drupal.org/node/1292436
*/
public function testTokensUTF() {
// Prepare a test text file.
$text_file = $this->getTestFile('text');
file_unmanaged_copy($text_file->uri, 'public://тест.txt');
$files = file_scan_directory('public://', '/тест\.txt/');
$utf_file = current($files);
file_save($utf_file);
// Ensure tokens are processed correctly.
$data = array('file' => $utf_file);
$this->assertToken('[file:ffp-name-only]', 'тест', $data);
}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* @file
* Tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsUpdatesCase
*/
class FileFieldPathsUpdatesCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Update functionality',
'description' => 'Tests retroactive and active updates functionality.',
'group' => 'File (Field) Paths',
);
}
/**
* Test behaviour of Retroactive updates when no updates are needed.
*/
public function testRetroEmpty() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$this->createFileField($field_name, $this->content_type);
// Trigger retroactive updates.
$edit = array(
'instance[settings][filefield_paths][retroactive_update]' => TRUE
);
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
// Ensure no errors are thrown.
$this->assertNoText('Error', t('No errors were found.'));
}
/**
* Test basic Retroactive updates functionality.
*/
public function testRetroBasic() {
// Create an Image field.
$field_name = drupal_strtolower($this->randomName());
$this->createImageField($field_name, $this->content_type, array());
// Modify instance settings.
$instance = field_info_instance('node', $field_name, $this->content_type);
$instance['display']['default']['settings']['image_style'] = 'thumbnail';
$instance['display']['default']['settings']['image_link'] = 'content';
field_update_instance($instance);
$this->drupalGet("admin/structure/types/manage/{$this->content_type}/display");
$original_instance = field_info_instance('node', $field_name, $this->content_type);
// Create a node with a test file.
$test_file = $this->getTestFile('image');
$nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
// Ensure that the file is in the default path.
$this->drupalGet("node/{$nid}");
$this->assertRaw("{$this->public_files_directory}/styles/thumbnail/public/{$test_file->name}", t('The File is in the default path.'));
// Trigger retroactive updates.
$edit['instance[settings][filefield_paths][retroactive_update]'] = TRUE;
$edit['instance[settings][filefield_paths][file_path][value]'] = 'node/[node:nid]';
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
// Ensure instance display settings haven't changed.
// @see https://www.drupal.org/node/2276435
drupal_static_reset('_field_info_field_cache');
$instance = field_info_instance('node', $field_name, $this->content_type);
$this->assert($original_instance['display'] === $instance['display'], t('Instance settings have not changed.'));
// Ensure that the file path has been retroactively updated.
$this->drupalGet("node/{$nid}");
$this->assertRaw("{$this->public_files_directory}/styles/thumbnail/public/node/{$nid}/{$test_file->name}", t('The File path has been retroactively updated.'));
}
}

View File

@@ -0,0 +1,12 @@
name = File (Field) Paths tests
description = Support module for File (Field) Paths related testing.
package = Testing
dependencies[] = filefield_paths
core = 7.x
hidden = TRUE
; Information added by Drupal.org packaging script on 2018-08-14
version = "7.x-1.1"
core = "7.x"
project = "filefield_paths"
datestamp = "1534256584"

View File

@@ -0,0 +1,16 @@
<?php
/**
* @file
* Core functions for the File (Field) Paths tests module.
*/
/**
* Implements hook_stream_wrappers_alter().
*
* @param $wrappers
*/
function filefield_paths_test_stream_wrappers_alter(&$wrappers) {
$wrappers['ffp'] = $wrappers['public'];
$wrappers['ffp']['type'] = STREAM_WRAPPERS_READ_VISIBLE;
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* @file
* Pathauto module tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsPathautoCase
*/
class FileFieldPathsPathautoCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
function setUp() {
// Setup required modules.
parent::setUp(array('pathauto'));
}
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Pathauto integration',
'description' => 'Tests the Pathauto module integration.',
'group' => 'File (Field) Paths',
);
}
/**
* Test File (Field) Paths Pathauto UI.
*/
public function testUI() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$this->createFileField($field_name, $this->content_type);
// Ensure File (Field) Paths Pathauto settings are present and available.
$this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
foreach (array('path', 'name') as $field) {
$this->assertField("instance[settings][filefield_paths][file_{$field}][options][pathauto]", t('Pathauto checkbox is present in File @field settings.', array('@field' => drupal_ucfirst($field))));
$element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => "instance[settings][filefield_paths][file_{$field}][options][pathauto]"));
$this->assert(empty($element), t('Pathauto checkbox is not disabled in File @field settings.', array('@field' => drupal_ucfirst($field))));
}
}
/**
* Test Pathauto cleanup in File (Field) Paths.
*/
public function testPathauto() {
$langcode = LANGUAGE_NONE;
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
$instance_settings['filefield_paths']['file_path']['options']['pathauto'] = TRUE;
$instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
$instance_settings['filefield_paths']['file_name']['options']['pathauto'] = TRUE;
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$edit['title'] = $this->randomString() . ' ' . $this->randomString();
$edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($test_file->uri);
$this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
// Ensure that file path/name have been processed correctly by Pathauto.
$node = node_load(1);
module_load_include('inc', 'pathauto');
$parts = explode('/', $node->title);
foreach ($parts as &$part) {
$part = pathauto_cleanstring($part);
}
$title = implode('/', $parts);
$this->assertEqual($node->{$field_name}[$langcode][0]['uri'], "public://node/{$title}/{$title}.txt", t('File path/name has been processed correctly by Pathauto'));
}
}

View File

@@ -0,0 +1,90 @@
<?php
/**
* @file
* Redirect module tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsRedirectTestCase
*/
class FileFieldPathsRedirectTestCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
function setUp() {
// Setup required modules.
parent::setUp(array('redirect'));
}
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Redirect module integration',
'description' => 'Test redirect module integration.',
'group' => 'File (Field) Paths',
);
}
/**
* Test File (Field) Paths Redirect UI.
*/
public function testUI() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$this->createFileField($field_name, $this->content_type);
// Ensure File (Field) Paths Pathauto settings are present and available.
$this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
$this->assertField('instance[settings][filefield_paths][redirect]', t('Redirect checkbox is present in File (Field) Path settings.'));
$element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => 'instance[settings][filefield_paths][redirect]'));
$this->assert(empty($element), t('Redirect checkbox is not disabled.'));
}
/**
* Test File (Field) Paths Redirect functionality.
*/
public function testRedirect() {
global $base_path;
$langcode = LANGUAGE_NONE;
// Create a File field with a random File path.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = $this->randomName();
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
// Get processed source file uri.
$node = node_load($nid, NULL, TRUE);
$source = $node->{$field_name}[$langcode][0]['uri'];
// Update file path and create redirect.
$edit = array(
'instance[settings][filefield_paths][file_path][value]' => $this->randomName(),
'instance[settings][filefield_paths][redirect]' => TRUE,
'instance[settings][filefield_paths][retroactive_update]' => TRUE,
);
$this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
// Get processed destination file uri.
$node = node_load($nid, NULL, TRUE);
$destination = $node->{$field_name}[$langcode][0]['uri'];
// Ensure that the source uri redirects to the destination uri.
$parsed_source = parse_url(file_create_url($source), PHP_URL_PATH);
$redirect_source = drupal_substr(urldecode($parsed_source), drupal_strlen($base_path));
$parsed_destination = parse_url(file_create_url($destination), PHP_URL_PATH);
$redirect_destination = drupal_substr(urldecode($parsed_destination), drupal_strlen($base_path));
$redirect = redirect_load_by_source($redirect_source);
$this->assert(is_object($redirect) && $redirect->redirect == $redirect_destination, t('Redirect created for relocated file.'));
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* @file
* Transliteration module tests for the File (Field) Paths module.
*/
/**
* Class FileFieldPathsTransliterationCase
*/
class FileFieldPathsTransliterationCase extends FileFieldPathsTestCase {
/**
* @inheritdoc
*/
function setUp() {
// Setup required modules.
parent::setUp(array('transliteration'));
}
/**
* @inheritdoc
*/
public static function getInfo() {
return array(
'name' => 'Transliteration integration',
'description' => 'Tests the Transliteration module integration.',
'group' => 'File (Field) Paths',
);
}
/**
* Test File (Field) Paths Transliteration UI.
*/
public function testUI() {
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$this->createFileField($field_name, $this->content_type);
// Ensure File (Field) Paths Transliteration settings are present and available.
$this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
foreach (array('path', 'name') as $field) {
$this->assertField("instance[settings][filefield_paths][file_{$field}][options][transliterate]", t('Transliteration checkbox is present in File @field settings.', array('@field' => drupal_ucfirst($field))));
$element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => "instance[settings][filefield_paths][file_{$field}][options][transliterate]"));
$this->assert(empty($element), t('Transliteration checkbox is not disabled in File @field settings.', array('@field' => drupal_ucfirst($field))));
}
}
/**
* Test Transliteration cleanup in File (Field) Paths.
*/
public function testTransliteration() {
$langcode = LANGUAGE_NONE;
// Create a File field.
$field_name = drupal_strtolower($this->randomName());
$instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
$instance_settings['filefield_paths']['file_path']['options']['transliterate'] = TRUE;
$instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
$instance_settings['filefield_paths']['file_name']['options']['transliterate'] = TRUE;
$this->createFileField($field_name, $this->content_type, array(), $instance_settings);
// Create a node with a test file.
$test_file = $this->getTestFile('text');
$edit['title'] = 'тест';
$edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($test_file->uri);
$this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
// Get created Node ID.
$matches = array();
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
// Ensure that file path/name have been processed correctly by
// Transliteration.
$node = node_load($nid);
$this->assertEqual($node->{$field_name}[$langcode][0]['uri'], "public://node/test/test.txt", t('File path/name has been processed correctly by Transliteration'));
}
}