Merge pull request #1161 from chillu/pulls/uploadfield-replacefile

NEW Upload->replaceFile setting
This commit is contained in:
Ingo Schommer 2013-02-27 01:24:27 -08:00
commit af52de97e9
5 changed files with 124 additions and 24 deletions

6
_config/config.yml Normal file
View File

@ -0,0 +1,6 @@
---
Name: coreconfig
---
Upload:
# Replace an existing file rather than renaming the new one.
replaceFile: false

View File

@ -219,6 +219,13 @@ editform, or 'fileEditValidator' to determine the validator (eg RequiredFields).
(of a method on File to provide a actions) for the EditForm (Example: 'getCMSActions')
- `fileEditValidator`: (string) Validator (eg RequiredFields) or string $name
(of a method on File to provide a Validator) for the EditForm (Example: 'getCMSValidator')
You can also configure the underlying `[api:Upload]` class, by using the YAML config system.
:::yaml
Upload:
# Globally disables automatic renaming of files
replaceFile: true
## TODO: Using the UploadField in a frontend form

View File

@ -45,6 +45,12 @@ class Upload extends Controller {
* @var array
*/
protected $tmpFile;
/**
* Replace an existing file rather than renaming the new one.
* @var Boolean
*/
protected $replaceFile;
/**
* Processing errors that can be evaluated,
@ -61,10 +67,11 @@ class Upload extends Controller {
* @var string
*/
public static $uploads_folder = "Uploads";
public function __construct() {
parent::__construct();
$this->validator = new Upload_Validator();
$this->replaceFile = $this->config()->get('replaceFile');
}
/**
@ -100,11 +107,6 @@ class Upload extends Controller {
if(!$folderPath) $folderPath = self::$uploads_folder;
if(!$this->file) {
$fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION));
$this->file = new $fileClass();
}
if(!is_array($tmpFile)) {
user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype",
E_USER_ERROR);
@ -137,25 +139,40 @@ class Upload extends Controller {
$fileName = basename($file);
$relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/$fileName";
// Create a new file record (or try to retrieve an existing one)
if(!$this->file) {
$fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION));
if($this->replaceFile) {
$this->file = File::get()
->filter(array(
'Name' => $fileName,
'ParentID' => $parentFolder ? $parentFolder->ID : 0
))->First();
}
if(!$this->file) $this->file = new $fileClass();
}
// if filename already exists, version the filename (e.g. test.gif to test1.gif)
while(file_exists("$base/$relativeFilePath")) {
$i = isset($i) ? ($i+1) : 2;
$oldFilePath = $relativeFilePath;
// make sure archives retain valid extensions
if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' ||
substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') {
$relativeFilePath = preg_replace('/[0-9]*(\.tar\.[^.]+$)/', $i . '\\1', $relativeFilePath);
} else if (strpos($relativeFilePath, '.') !== false) {
$relativeFilePath = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $relativeFilePath);
} else if (strpos($relativeFilePath, '_') !== false) {
$relativeFilePath = preg_replace('/_([^_]+$)/', '_'.$i, $relativeFilePath);
} else {
$relativeFilePath .= '_'.$i;
}
if($oldFilePath == $relativeFilePath && $i > 2) {
user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR);
}
if(!$this->replaceFile) {
while(file_exists("$base/$relativeFilePath")) {
$i = isset($i) ? ($i+1) : 2;
$oldFilePath = $relativeFilePath;
// make sure archives retain valid extensions
if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' ||
substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') {
$relativeFilePath = preg_replace('/[0-9]*(\.tar\.[^.]+$)/', $i . '\\1', $relativeFilePath);
} else if (strpos($relativeFilePath, '.') !== false) {
$relativeFilePath = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $relativeFilePath);
} else if (strpos($relativeFilePath, '_') !== false) {
$relativeFilePath = preg_replace('/_([^_]+$)/', '_'.$i, $relativeFilePath);
} else {
$relativeFilePath .= '_'.$i;
}
if($oldFilePath == $relativeFilePath && $i > 2) {
user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR);
}
}
}
if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "$base/$relativeFilePath")) {
@ -181,6 +198,20 @@ class Upload extends Controller {
$this->file = $file;
return $this->load($tmpFile, $folderPath);
}
/**
* @return Boolean
*/
public function setReplaceFile($bool) {
$this->replaceFile = $bool;
}
/**
* @return Boolean
*/
public function getReplaceFile() {
return $this->replaceFile;
}
/**
* Container for all validation on the file

View File

@ -78,7 +78,7 @@ class FileField extends FormField {
* @param int $value The value of the field.
*/
public function __construct($name, $title = null, $value = null) {
$this->upload = new Upload();
$this->upload = Upload::create();
parent::__construct($name, $title, $value);
}

View File

@ -316,6 +316,62 @@ class UploadTest extends SapphireTest {
$file2->delete();
}
public function testReplaceFile() {
// create tmp file
$tmpFileName = 'UploadTest-testUpload';
$tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName;
$tmpFileContent = '';
for($i=0; $i<10000; $i++) $tmpFileContent .= '0';
file_put_contents($tmpFilePath, $tmpFileContent);
// emulates the $_FILES array
$tmpFile = array(
'name' => $tmpFileName,
'type' => 'text/plaintext',
'size' => filesize($tmpFilePath),
'tmp_name' => $tmpFilePath,
'extension' => 'txt',
'error' => UPLOAD_ERR_OK,
);
// Make sure there are none here, otherwise they get renamed incorrectly for the test.
$this->deleteTestUploadFiles("/UploadTest-testUpload.*/");
$v = new UploadTest_Validator();
$v->setAllowedExtensions(array(''));
// test upload into default folder
$u = new Upload();
$u->setValidator($v);
$u->load($tmpFile);
$file = $u->getFile();
$this->assertEquals(
'UploadTest-testUpload',
$file->Name,
'File is uploaded without extension'
);
$u = new Upload();
$u->setValidator($v);
$u->setReplaceFile(true);
$u->load($tmpFile);
$file2 = $u->getFile();
$this->assertEquals(
'UploadTest-testUpload',
$file2->Name,
'File does not receive new name'
);
$this->assertEquals(
$file->ID,
$file2->ID,
'File database record is the same'
);
$file->delete();
$file2->delete();
}
}
class UploadTest_Validator extends Upload_Validator implements TestOnly {