summaryrefslogtreecommitdiff
path: root/modules/file
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-08-22 13:52:59 +0000
committerDries Buytaert <dries@buytaert.net>2010-08-22 13:52:59 +0000
commit4a7bb638fb3243a35dd2ce82a4cafc78d2f6b9d2 (patch)
tree3e17684510b739dafb359a17a1d26027fe168ec6 /modules/file
parentb36d4959ef2244298fd28d02575c88b0259555b4 (diff)
downloadbrdo-4a7bb638fb3243a35dd2ce82a4cafc78d2f6b9d2.tar.gz
brdo-4a7bb638fb3243a35dd2ce82a4cafc78d2f6b9d2.tar.bz2
- Patch #353458 by quicksketch, drewish, jpetso, sun, noahb, aaron, chx, mikey_p, dhthwy: hook_file_references() was not designed for a highly flexible field storage.
Diffstat (limited to 'modules/file')
-rw-r--r--modules/file/file.field.inc104
-rw-r--r--modules/file/file.module90
-rw-r--r--modules/file/tests/file.test6
3 files changed, 81 insertions, 119 deletions
diff --git a/modules/file/file.field.inc b/modules/file/file.field.inc
index 69b872de7..403f94f66 100644
--- a/modules/file/file.field.inc
+++ b/modules/file/file.field.inc
@@ -266,37 +266,65 @@ function file_field_presave($entity_type, $entity, $field, $instance, $langcode,
}
/**
+ * Implements hook_field_insert().
+ */
+function file_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+ // Add a new usage of each uploaded file.
+ foreach ($items as $item) {
+ $file = (object) $item;
+ file_usage_add($file, 'file', $entity_type, $id);
+ }
+}
+
+/**
* Implements hook_field_update().
*
- * Check for files that have been removed from the object.
+ * Checks for files that have been removed from the object.
*/
function file_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
- // On new revisions, old files are always maintained in the previous revision.
+ list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+ // On new revisions, all files are considered to be a new usage and no
+ // deletion of previous file usages are necessary.
if (!empty($entity->revision)) {
+ foreach ($items as $item) {
+ $file = (object) $item;
+ file_usage_add($file, 'file', $entity_type, $id);
+ }
return;
}
// Build a display of the current FIDs.
- $fids = array();
+ $current_fids = array();
foreach ($items as $item) {
- $fids[] = $item['fid'];
+ $current_fids[] = $item['fid'];
}
- // Get the current values in the entity, and delete files for removed items.
- list($id) = entity_extract_ids($entity_type, $entity);
- $original = clone $entity;
+ // Create a bare-bones entity so that we can load its previous values.
+ $original = entity_create_stub_entity($entity_type, array($id, $vid, $bundle));
field_attach_load($entity_type, array($id => $original), FIELD_LOAD_CURRENT, array('field_id' => $field['id']));
+ // Compare the original field values with the ones that are being saved.
+ $original_fids = array();
if (!empty($original->{$field['field_name']}[$langcode])) {
foreach ($original->{$field['field_name']}[$langcode] as $original_item) {
- if (isset($original_item['fid']) && !in_array($original_item['fid'], $fids)) {
- // For hook_file_references, remember that this is being deleted.
- $original_item['file_field_name'] = $field['field_name'];
- // Delete the file if possible.
- file_field_delete_file($original_item, $field);
+ $original_fids[] = $original_item['fid'];
+ if (isset($original_item['fid']) && !in_array($original_item['fid'], $current_fids)) {
+ // Decrement the file usage count by 1 and delete the file if possible.
+ file_field_delete_file($original_item, $field, $entity_type, $id);
}
}
}
+
+ // Add new usage entries for newly added files.
+ foreach ($items as $item) {
+ if (!in_array($item['fid'], $original_fids)) {
+ $file = (object) $item;
+ file_usage_add($file, 'file', $entity_type, $id);
+ }
+ }
}
/**
@@ -304,14 +332,10 @@ function file_field_update($entity_type, $entity, $field, $instance, $langcode,
*/
function file_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+ // Delete all file usages within this entity.
foreach ($items as $delta => $item) {
- // For hook_file_references(), remember that this is being deleted.
- $item['file_field_name'] = $field['field_name'];
- // Pass in the ID of the object that is being removed so all references can
- // be counted in hook_file_references().
- $item['file_field_type'] = $entity_type;
- $item['file_field_id'] = $id;
- file_field_delete_file($item, $field);
+ file_field_delete_file($item, $field, $entity_type, $id, 0);
}
}
@@ -319,32 +343,46 @@ function file_field_delete($entity_type, $entity, $field, $instance, $langcode,
* Implements hook_field_delete_revision().
*/
function file_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
foreach ($items as $delta => $item) {
- // For hook_file_references, remember that this file is being deleted.
- $item['file_field_name'] = $field['field_name'];
- if (file_field_delete_file($item, $field)) {
+ // Decrement the file usage count by 1 and delete the file if possible.
+ if (file_field_delete_file($item, $field, $entity_type, $id)) {
$items[$delta] = NULL;
}
}
}
/**
- * Check that File controls a file before attempting to delete it.
+ * Decrements a file usage count and attempts to delete it.
+ *
+ * This function only has an effect if the file being deleted is used only by
+ * File module.
+ *
+ * @param $item
+ * The field item that contains a file array.
+ * @param $field
+ * The field structure for the operation.
+ * @param $entity_type
+ * The type of $entity.
+ * @param $id
+ * The entity ID which contains the file being deleted.
+ * @param $count
+ * (optional) The number of references to decrement from the object
+ * containing the file. Defaults to 1.
+ *
+ * @return
+ * Boolean TRUE if the file was deleted, or an array of remaining references
+ * if the file is still in use by other modules. Boolean FALSE if an error
+ * was encountered.
*/
-function file_field_delete_file($item, $field) {
- // Remove the file_field_name and file_field_id properties so that references
- // can be counted including the files to be deleted.
- $field_name = isset($item['file_field_name']) ? $item['file_field_name'] : NULL;
- $field_id = isset($item['file_field_id']) ? $item['file_field_id'] : NULL;
- unset($item['file_field_name'], $item['file_field_id']);
-
+function file_field_delete_file($item, $field, $entity_type, $id, $count = 1) {
// To prevent the file field from deleting files it doesn't know about, check
// the file reference count. Temporary files can be deleted because they
// are not yet associated with any content at all.
$file = (object) $item;
- if ($file->status == 0 || file_get_file_reference_count($file, $field) > 0) {
- $file->file_field_name = $field_name;
- $file->file_field_id = $field_id;
+ $file_usage = file_usage_list($file);
+ if ($file->status == 0 || !empty($file_usage['file'])) {
+ file_usage_delete($file, 'file', $entity_type, $id, $count);
return file_delete($file);
}
diff --git a/modules/file/file.module b/modules/file/file.module
index 445dc624d..a69a21dca 100644
--- a/modules/file/file.module
+++ b/modules/file/file.module
@@ -328,14 +328,6 @@ function file_progress_implementation() {
}
/**
- * Implements hook_file_references().
- */
-function file_file_references($file) {
- $count = file_get_file_reference_count($file, NULL, 'file');
- return $count ? array('file' => $count) : NULL;
-}
-
-/**
* Implements hook_file_delete().
*/
function file_file_delete($file) {
@@ -527,12 +519,9 @@ function file_managed_file_validate(&$element, &$form_state) {
if ($clicked_button != 'remove_button' && !empty($element['fid']['#value'])) {
if ($file = file_load($element['fid']['#value'])) {
if ($file->status == FILE_STATUS_PERMANENT) {
- $reference_count = 0;
- foreach (module_invoke_all('file_references', $file) as $module => $references) {
- $reference_count += $references;
- }
- if ($reference_count == 0) {
- form_error($element, t('Referencing to the file used in the !name field is not allowed.', array('!name' => $element['#title'])));
+ $references = file_usage_list($file);
+ if (empty($references)) {
+ form_error($element, t('The file used in the !name field may not be referenced.', array('!name' => $element['#title'])));
}
}
}
@@ -942,73 +931,7 @@ function file_icon_map($file) {
*/
/**
- * Count the number of times the file is referenced.
- *
- * @param $file
- * A file object.
- * @param $field
- * (optional) A CCK field array or field name as a string. If provided,
- * limits the reference check to the given field.
- * @param $field_type
- * (optional) The name of a field type. If provided, limits the reference
- * check to fields of the given type.
- * @return
- * An integer value.
- */
-function file_get_file_reference_count($file, $field = NULL, $field_type = NULL) {
- // Determine the collection of fields to check.
- if (isset($field)) {
- // Support $field as 'field name'.
- if (is_string($field)) {
- $field = field_info_field($field);
- }
- $fields = array($field['field_name'] => $field);
- }
- else {
- $fields = field_info_fields();
- }
-
- $types = entity_get_info();
- $reference_count = 0;
-
- foreach ($fields as $field) {
- if (empty($field_type) || $field['type'] == $field_type) {
- // TODO: Use a more efficient mechanism rather than actually retrieving
- // all the references themselves, such as using a COUNT() query.
- $references = file_get_file_references($file, $field, FIELD_LOAD_REVISION, $field_type);
- foreach ($references as $entity_type => $type_references) {
- $reference_count += count($type_references);
- }
-
- // If a field_name is present in the file object, the file is being deleted
- // from this field.
- if (isset($file->file_field_name) && $field['field_name'] == $file->file_field_name) {
- // If deleting the entire piece of content, decrement references.
- if (isset($file->file_field_type) && isset($file->file_field_id)) {
- if ($file->file_field_type == $entity_type) {
- $info = entity_get_info($entity_type);
- $id = $types[$entity_type]['entity keys']['id'];
- foreach ($type_references as $reference) {
- if ($file->file_field_id == $reference->$id) {
- $reference_count--;
- }
- }
- }
- }
- // Otherwise we're just deleting a single reference in this field.
- else {
- $reference_count--;
- }
- }
- }
- }
-
- return $reference_count;
-}
-
-
-/**
- * Get a list of references to a file.
+ * Gets a list of references to a file.
*
* @param $file
* A file object.
@@ -1020,8 +943,9 @@ function file_get_file_reference_count($file, $field = NULL, $field_type = NULL)
* FIELD_LOAD_REVISION to retrieve all references within all revisions or
* FIELD_LOAD_CURRENT to retrieve references only in the current revisions.
* @param $field_type
- * Optional. The name of a field type. If given, limits the reference check to
- * fields of the given type.
+ * (optional) The name of a field type. If given, limits the reference check
+ * to fields of the given type.
+ *
* @return
* An integer value.
*/
diff --git a/modules/file/tests/file.test b/modules/file/tests/file.test
index 2bf5b7f86..cc275e202 100644
--- a/modules/file/tests/file.test
+++ b/modules/file/tests/file.test
@@ -169,7 +169,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
* Assert that a file exists in the database.
*/
function assertFileEntryExists($file, $message = NULL) {
- drupal_static_reset('file_load_multiple');
+ entity_get_controller('file')->resetCache();
$db_file = file_load($file->fid);
$message = isset($message) ? $message : t('File %file exists in database at the correct path.', array('%file' => $file->uri));
$this->assertEqual($db_file->uri, $file->uri, $message);
@@ -187,7 +187,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
* Assert that a file does not exist in the database.
*/
function assertFileEntryNotExists($file, $message) {
- drupal_static_reset('file_load_multiple');
+ entity_get_controller('file')->resetCache();
$message = isset($message) ? $message : t('File %file exists in database at the correct path.', array('%file' => $file->uri));
$this->assertFalse(file_load($file->fid), $message);
}
@@ -391,7 +391,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Attach the second file to a user.
$user = $this->drupalCreateUser();
- $edit = array();
+ $edit = (array) $user;
$edit[$field_name][LANGUAGE_NONE][0] = (array) $node_file_r3;
user_save($user, $edit);
$this->drupalGet('user/' . $user->uid . '/edit');