diff --git a/file_entity.api.php b/file_entity.api.php index 9fb7457..d90d3ad 100644 --- a/file_entity.api.php +++ b/file_entity.api.php @@ -367,3 +367,11 @@ function hook_file_type_alter(&$types, $file) { // Choose a specific, non-first, file type. $types = array($types[4]); } + +function hook_file_metadata_info() { + +} + +function hook_file_metadata_info_alter() { + +} diff --git a/file_entity.file.inc b/file_entity.file.inc index a0a7f11..80d7ca3 100644 --- a/file_entity.file.inc +++ b/file_entity.file.inc @@ -31,6 +31,9 @@ function file_entity_file_presave($file) { } field_attach_presave('file', $file); + + // Fetch image dimensions. + file_entity_metadata_fetch_image_dimensions($file); } /** @@ -54,13 +57,23 @@ function file_entity_file_insert($file) { // Ensure field data is saved since file_save() does not in Drupal 7. field_attach_insert('file', $file); + // Save file metadata. + if (!empty($file->metadata)) { + foreach ($file->metadata as $name => $value) { + db_insert('file_metadata') + ->fields(array( + 'value' => serialize($value), + )) + ->key(array( + 'fid' => $file->fid, + 'name' => $name, + )) + ->execute(); + } + } + // Clear any related field caches. file_entity_invalidate_field_caches($file); - - // Get and store image dimensions. - // @todo We should fetch image dimensions in file_entity_file_presave and - // then save them in this hook. - file_entity_image_dimensions($file, TRUE); } /** @@ -70,15 +83,23 @@ function file_entity_file_update($file) { // Ensure field data is saved since file_save() does not in Drupal 7. field_attach_update('file', $file); - // Clear any related field caches. - file_entity_invalidate_field_caches($file); + // Save file metadata. + db_delete('file_metadata')->condition('fid', $file->fid); + if (!empty($file->metadata)) { + foreach ($file->metadata as $name => $value) { + db_insert('file_metadata') + ->fields(array( + 'value' => serialize($value), + )) + ->key(array( + 'fid' => $file->fid, + 'name' => $name, + )) + ->execute(); + } + } - // Reset the image dimensions for a file. - // @todo We should fetch image dimensions in file_entity_file_presave and - // then save them in this hook. - file_entity_image_dimensions($file, TRUE); - - if ($file->type == 'image' && module_exists('image')) { + if (file_entity_file_get_mimetype_type($file) == 'image' && module_exists('image')) { // If the image dimensions have changed, update any image field references // to this file and flush image style derivatives. if ($file->image_dimensions != $file->original->image_dimensions) { @@ -88,6 +109,9 @@ function file_entity_file_update($file) { // Flush image style derivatives whenever an image is updated. image_path_flush($file->uri); } + + // Clear any related field caches. + file_entity_invalidate_field_caches($file); } /** @@ -100,8 +124,8 @@ function file_entity_file_delete($file) { // not yet been deleted. file_entity_invalidate_field_caches($file); - // Delete image dimensions from the {image_dimensions} table - db_query('DELETE FROM {image_dimensions} WHERE fid = :fid', array(':fid' => $file->fid)); + // Remove file metadata. + db_delete('file_metadata')->condition('fid', $file->fid)->execute(); // Remove this file from the search index if needed. // This code is implemented in file entity module rather than in search module, @@ -151,17 +175,14 @@ function file_entity_file_mimetype_mapping_alter(&$mapping) { * Implements hook_file_load(). */ function file_entity_file_load($files) { - // Load images dimensions already in the {image_dimensions} table. - $result = db_query('SELECT * FROM {image_dimensions} id WHERE id.fid IN (:fids)', array(':fids' => array_keys($files))); - foreach ($result as $record) { - $files[$record->fid]->image_dimensions = array( - 'width' => $record->width, - 'height' => $record->height, - ); - } - // Retrieve any missing images dimensions. foreach ($files as $file) { - file_entity_image_dimensions($file, FALSE); + $file->metadata = array(); + } + + // Load and unserialize metadata. + $metadata = db_query("SELECT * FROM {file_metadata} WHERE fid IN (:fids)", array(':fids' => array_keys($fids))); + foreach ($result as $record) { + $files[$record->fid]->metadata[$record->name] = unserialize($record->value); } } @@ -182,7 +203,7 @@ function file_entity_file_load($files) { * image dimensions cannot be read, the 'width' and 'height' properties will * be NULL. If $file is either empty or not an image file, FALSE is returned. */ -function file_entity_image_dimensions($file, $force = FALSE) { +function file_entity_metadata_fetch_image_dimensions($file) { // Prevent PHP notices when trying to read empty files. // @see http://drupal.org/node/681042 if (!$file->filesize) { @@ -190,36 +211,17 @@ function file_entity_image_dimensions($file, $force = FALSE) { } // Do not bother proceeding if this file does not have an image mime type. - if (strpos($file->filemime, 'image/') !== 0) { + if (file_entity_file_get_mimetype_type($file) != 'image') { return; } - // Return the existing $file->image_dimensions unless a reload is forced. - if (!$force && isset($file->image_dimensions)) { - return $file->image_dimensions; - } - // We have a non-empty image file. $image_info = image_get_info($file->uri); if ($image_info) { - $file->image_dimensions = array( - 'width' => $image_info['width'], - 'height' => $image_info['height'], - ); - db_merge('image_dimensions') - ->key(array('fid' => $file->fid)) - ->fields(array( - 'width' => $file->image_dimensions['width'], - 'height' => $file->image_dimensions['height'], - )) - ->execute(); + $file->metadata += array_intersect_key($image_info, drupal_map_assoc(array('width', 'height'))); } else { - // Fallback to NULL values. - $file->image_dimensions = array( - 'width' => NULL, - 'height' => NULL, - ); + $file->metadata = array_diff_key($image_info, drupal_map_assoc(array('width', 'height'))); } } @@ -232,6 +234,11 @@ function file_entity_image_dimensions($file, $force = FALSE) { * @see http://drupal.org/node/1448124 */ function _file_entity_update_image_field_dimensions($file) { + // Do not bother proceeding if this file does not have an image mime type. + if (file_entity_file_get_mimetype_type($file) != 'image') { + return; + } + // Find all image field enabled on the site. $image_fields = array(); foreach (field_info_fields() as $field) { @@ -288,3 +295,12 @@ function _file_entity_entity_fields_update($entity_type, $entity) { // Clear the cache for this entity now. entity_get_controller($entity_type)->resetCache(array($id)); } + +/** + * Implements hook_file_metadata_info(). + */ +function file_entity_file_metadata_info() { + $info['width'] = array('label' => t('Width'), 'type' => 'integer'); + $info['height'] = array('label' => t('Height'), 'type' => 'integer'); + return $info; +} diff --git a/file_entity.install b/file_entity.install index a1f86c2..b11e1f1 100644 --- a/file_entity.install +++ b/file_entity.install @@ -131,31 +131,31 @@ function file_entity_schema() { ), ), ); - $schema['image_dimensions'] = array( + + $schema['file_metadata'] = array( 'description' => 'Cache images dimensions.', 'fields' => array( 'fid' => array( - 'description' => 'File ID.', + 'description' => 'The file ID.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), - 'height' => array( - 'description' => 'The height of the image in pixels.', - 'type' => 'int', - 'unsigned' => TRUE, + 'name' => array( + 'description' => "The name of the metadata (e.g. 'width').", + 'type' => 'varchar', + 'length' => '255', 'not null' => TRUE, - 'default' => 0, ), - 'width' => array( - 'description' => 'The width of the image in pixels..', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, + 'value' => array( + 'description' => "The value of the metadata (e.g. '200px').", + 'type' => 'blob', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, ), ), - 'primary key' => array('fid'), + 'primary key' => array('fid', 'name'), 'foreign keys' => array( 'file_managed' => array( 'table' => 'file_managed', @@ -163,6 +163,7 @@ function file_entity_schema() { ), ), ); + return $schema; } @@ -859,3 +860,52 @@ function file_entity_update_7209() { db_drop_table('file_type_streams'); } } + +/** + * Migrate the {image_dimensions} table to {file_metadata}. + */ +function file_entity_update_7210() { + $schema = array( + 'description' => 'Stores file metadata in a key/value store.', + 'fields' => array( + 'fid' => array( + 'description' => 'The file ID.', + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'name' => array( + 'description' => "The name of the metadata (e.g. 'width').", + 'type' => 'varchar', + 'length' => '255', + 'not null' => TRUE, + ), + 'value' => array( + 'description' => "The value of the metadata (e.g. '200px').", + 'type' => 'blob', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, + ), + ), + 'primary key' => array('fid', 'name'), + 'foreign keys' => array( + 'file_managed' => array( + 'table' => 'file_managed', + 'columns' => array('fid' => 'fid'), + ), + ), + ); + db_create_table('file_metadata', $schema); + + if (db_table_exists('image_dimensions')) { + foreach (array('width', 'height') as $name) { + $query = db_select('image_dimensions', 'id'); + $query->addField('id', 'fid'); + $query->addExpression(':name', 'name', array(':name' => $name)); + $query->addExpression("CONCAT('i:', $name, ';')", 'value'); + db_insert('file_metadata')->from($query)->execute(); + } + db_drop_table('image_dimensions'); + } +} diff --git a/file_entity.module b/file_entity.module index afeb63b..a4cd9cf 100644 --- a/file_entity.module +++ b/file_entity.module @@ -1131,7 +1131,7 @@ function file_entity_file_formatter_file_image_view($file, $display, $langcode) } // Do not bother proceeding if this file does not have an image mime type. - if (strpos($file->filemime, 'image/') !== 0) { + if (file_entity_file_get_mimetype_type($file) != 'image') { return; } @@ -2189,3 +2189,8 @@ function file_entity_download_uri($file) { } return $uri; } + +function file_entity_file_get_mimetype_type($file) { + list($type, $subtype) = explode('/', $file->mimetype, 2); + return $type; +}