diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-08-22 13:52:59 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-08-22 13:52:59 +0000 |
commit | 4a7bb638fb3243a35dd2ce82a4cafc78d2f6b9d2 (patch) | |
tree | 3e17684510b739dafb359a17a1d26027fe168ec6 /modules/file | |
parent | b36d4959ef2244298fd28d02575c88b0259555b4 (diff) | |
download | brdo-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.inc | 104 | ||||
-rw-r--r-- | modules/file/file.module | 90 | ||||
-rw-r--r-- | modules/file/tests/file.test | 6 |
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'); |