Merge branch 'MDL-33587-delete-alias' of git://github.com/mudrd8mz/moodle

This commit is contained in:
Dan Poltawski
2012-06-08 11:40:56 +08:00
2 changed files with 126 additions and 23 deletions
+40 -23
View File
@@ -142,8 +142,10 @@ class stored_file {
}
}
if ($field == 'referencefileid' or $field == 'referencelastsync' or $field == 'referencelifetime') {
$value = clean_param($value, PARAM_INT);
if ($field === 'referencefileid' or $field === 'referencelastsync' or $field === 'referencelifetime') {
if (!is_null($value) and !is_number($value)) {
throw new file_exception('storedfileproblem', 'Invalid reference info');
}
}
// adding the field
@@ -196,36 +198,46 @@ class stored_file {
}
/**
* Delete file reference
* Unlink the stored file from the referenced file
*
* This methods destroys the link to the record in files_reference table. This effectively
* turns the stored file from being an alias to a plain copy. However, the caller has
* to make sure that the actual file's content has beed synced prior to calling this method.
*/
public function delete_reference() {
global $DB;
// Remove repository info.
$this->repository = null;
if (!$this->is_external_file()) {
throw new coding_exception('An attempt to unlink a non-reference file.');
}
$transaction = $DB->start_delegated_transaction();
// Remove reference info from DB.
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
// Are we the only one referring to the original file? If so, delete the
// referenced file record. Note we do not use file_storage::search_references_count()
// here because we want to count draft files too and we are at a bit lower access level here.
$countlinks = $DB->count_records('files',
array('referencefileid' => $this->file_record->referencefileid));
if ($countlinks == 1) {
$DB->delete_records('files_reference', array('id' => $this->file_record->referencefileid));
}
// Must refresh $this->file_record form DB
$filerecord = $DB->get_record('files', array('id'=>$this->get_id()));
// Update DB
$filerecord->referencelastsync = null;
$filerecord->referencelifetime = null;
$filerecord->referencefileid = null;
$this->update($filerecord);
// Update the underlying record in the database.
$update = new stdClass();
$update->referencefileid = null;
$update->referencelastsync = null;
$update->referencelifetime = null;
$this->update($update);
$transaction->allow_commit();
// unset object variable
unset($this->file_record->repositoryid);
unset($this->file_record->reference);
unset($this->file_record->referencelastsync);
unset($this->file_record->referencelifetime);
unset($this->file_record->referencefileid);
// Update our properties and the record in the memory.
$this->repository = null;
$this->file_record->repositoryid = null;
$this->file_record->reference = null;
$this->file_record->referencefileid = null;
$this->file_record->referencelastsync = null;
$this->file_record->referencelifetime = null;
}
/**
@@ -254,15 +266,20 @@ class stored_file {
$transaction = $DB->start_delegated_transaction();
// If other files referring to this file, we need convert them
// If there are other files referring to this file, convert them to copies.
if ($files = $this->fs->get_references_by_storedfile($this)) {
foreach ($files as $file) {
$this->fs->import_external_file($file);
}
}
// Now delete file records in DB
// If this file is a reference (alias) to another file, unlink it first.
if ($this->is_external_file()) {
$this->delete_reference();
}
// Now delete the file record.
$DB->delete_records('files', array('id'=>$this->file_record->id));
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
$transaction->allow_commit();
@@ -1212,4 +1212,90 @@ class filestoragelib_testcase extends advanced_testcase {
$this->setExpectedException('stored_file_creation_exception');
$file2 = $fs->create_file_from_pathname($filerecord, $path);
}
/**
* Calling stored_file::delete_reference() on a non-reference file throws coding_exception
*/
public function test_delete_reference_on_nonreference() {
$this->resetAfterTest(true);
$user = $this->setup_three_private_files();
$fs = get_file_storage();
$repos = repository::get_instances(array('type'=>'user'));
$repo = reset($repos);
$file = null;
foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
if (!$areafile->is_directory()) {
$file = $areafile;
break;
}
}
$this->assertInstanceOf('stored_file', $file);
$this->assertFalse($file->is_external_file());
$this->setExpectedException('coding_exception');
$file->delete_reference();
}
/**
* Calling stored_file::delete_reference() on a reference file does not affect other
* symlinks to the same original
*/
public function test_delete_reference_one_symlink_does_not_rule_them_all() {
$this->resetAfterTest(true);
$user = $this->setup_three_private_files();
$fs = get_file_storage();
$repos = repository::get_instances(array('type'=>'user'));
$repo = reset($repos);
// create two aliases linking the same original
$originalfile = null;
foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
if (!$areafile->is_directory()) {
$originalfile = $areafile;
break;
}
}
$this->assertInstanceOf('stored_file', $originalfile);
// calling delete_reference() on a non-reference file
$originalrecord = array(
'contextid' => $originalfile->get_contextid(),
'component' => $originalfile->get_component(),
'filearea' => $originalfile->get_filearea(),
'itemid' => $originalfile->get_itemid(),
'filepath' => $originalfile->get_filepath(),
'filename' => $originalfile->get_filename(),
);
$aliasrecord = $this->generate_file_record();
$aliasrecord->filepath = '/A/';
$aliasrecord->filename = 'symlink.txt';
$ref = $fs->pack_reference($originalrecord);
$aliasfile1 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
$aliasrecord->filepath = '/B/';
$aliasrecord->filename = 'symlink.txt';
$ref = $fs->pack_reference($originalrecord);
$aliasfile2 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
// refetch A/symlink.txt
$symlink1 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
$aliasrecord->filearea, $aliasrecord->itemid, '/A/', 'symlink.txt');
$this->assertTrue($symlink1->is_external_file());
// unlink the A/symlink.txt
$symlink1->delete_reference();
$this->assertFalse($symlink1->is_external_file());
// make sure that B/symlink.txt has not been affected
$symlink2 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
$aliasrecord->filearea, $aliasrecord->itemid, '/B/', 'symlink.txt');
$this->assertTrue($symlink2->is_external_file());
}
}