diff --git a/includes/media.filter.inc b/includes/media.filter.inc index aacd189..d4b2cf7 100644 --- a/includes/media.filter.inc +++ b/includes/media.filter.inc @@ -7,6 +7,9 @@ * @TODO: Rename this file? */ +define('MEDIA_TOKEN_REGEX', '/\[\[.*?\]\]/s'); +define('MEDIA_TOKEN_REGEX_ALT', '/%7B.*?%7D/s'); + /** * Implements hook_wysiwyg_include_directory(). */ @@ -26,12 +29,171 @@ function media_wysiwyg_include_directory($type) { */ function media_filter($text) { $text = ' ' . $text . ' '; - $text = preg_replace_callback("/\[\[.*?\]\]/s", 'media_token_to_markup', $text); + $text = preg_replace_callback(MEDIA_TOKEN_REGEX, 'media_token_to_markup', $text); return $text; } /** + * Implements hook_field_attach_insert(). + * + * Track file usage for media files included in formatted text. Note that this + * is heavy-handed, and should be replaced when Drupal's filter system is + * context-aware. + */ +function media_field_attach_insert($entity_type, $entity) { + _media_filter_add_file_usage_from_fields($entity_type, $entity); +} + +/** + * Implements hook_field_attach_update(). + * + * @see media_field_attach_insert(). + */ +function media_field_attach_update($entity_type, $entity) { + _media_filter_add_file_usage_from_fields($entity_type, $entity); +} + +/** + * Add file usage from file references in an entity's text fields. + */ +function _media_filter_add_file_usage_from_fields($entity_type, $entity) { + // Track the total usage for files from all fields combined. + $entity_files = array(); + foreach (media_filter_parse_from_fields($entity_type, $entity) as $file_reference) { + if (empty($entity_files[$file_reference['fid']])) { + $entity_files[$file_reference['fid']] = 1; + } + else { + $entity_files[$file_reference['fid']]++; + } + } + + list($entity_id, $entity_vid) = entity_extract_ids($entity_type, $entity); + + // When the current revision of this entity is the only revision of this entity + // and files have been removed from this entity the file_usage entry for this + // entity can be removed. The code following this will add the files back correctly. + if ($entity_id == $entity_vid) { + db_delete('file_usage') + ->condition('module', 'media') + ->condition('type', $entity_type) + ->condition('id', $entity_id) + ->execute(); + } + + // Each entity revision counts for file usage. If versions are not enabled + // the file_usage table will have no entries for this because of the delete + // query above. + foreach ($entity_files as $fid => $entity_count) { + $file = file_load($fid); + file_usage_add($file, 'media', $entity_type, $entity_id, $entity_count); + } + +} + +/** + * Parse file references from an entity's text fields and return them as an array. + */ +function media_filter_parse_from_fields($entity_type, $entity) { + $file_references = array(); + + foreach (_media_filter_fields_with_text_filtering($entity_type, $entity) as $field_name) { + if ($field_items = field_get_items($entity_type, $entity, $field_name)) { + foreach ($field_items as $field_item) { + preg_match_all(MEDIA_TOKEN_REGEX, $field_item['value'], $matches); + foreach ($matches[0] as $tag) { + $tag = str_replace(array('[[', ']]'), '', $tag); + $tag_info = drupal_json_decode($tag); + if (isset($tag_info['fid']) && $tag_info['type'] == 'media') { + $file_references[] = $tag_info; + } + } + + preg_match_all(MEDIA_TOKEN_REGEX_ALT, $field_item['value'], $matches_alt); + foreach ($matches_alt[0] as $tag) { + $tag = urldecode($tag); + $tag_info = drupal_json_decode($tag); + if (isset($tag_info['fid']) && $tag_info['type'] == 'media') { + $file_references[] = $tag_info; + } + } + } + } + } + + return $file_references; +} + +/** + * Returns an array containing the names of all fields that perform text filtering. + */ +function _media_filter_fields_with_text_filtering($entity_type, $entity) { + list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity); + $fields = field_info_instances($entity_type, $bundle); + + // Get all of the fields on this entity that allow text filtering. + $fields_with_text_filtering = array(); + foreach ($fields as $field_name => $field) { + if (!empty($field['settings']['text_processing'])) { + $fields_with_text_filtering[] = $field_name; + } + } + + return $fields_with_text_filtering; +} + +/** + * Utility function to get the file count in this entity + * + * @param type $entity + * @param type $entity_type + * @return int + */ +function media_entity_field_count_files($entity_type, $entity) { + $entity_files = array(); + foreach (media_filter_parse_from_fields($entity_type, $entity) as $file_reference) { + if (empty($entity_files[$file_reference['fid']])) { + $entity_files[$file_reference['fid']] = 1; + } + else { + $entity_files[$file_reference['fid']]++; + } + } + return $entity_files; +} + + +/** + * Implements hook_entity_delete(). + */ +function media_entity_delete($entity, $type) { + list($entity_id) = entity_extract_ids($type, $entity); + + db_delete('file_usage') + ->condition('module', 'media') + ->condition('type', $type) + ->condition('id', $entity_id) + ->execute(); +} + +/** + * Implements hook_field_attach_delete_revision(). + * + * @param type $entity_type + * @param type $entity + */ +function media_field_attach_delete_revision($entity_type, $entity) { + list($entity_id) = entity_extract_ids($type, $entity); + $files = media_entity_field_count_files($entity_type, $entity); + foreach ($files as $fid => $count) { + if ($file = file_load($fid)) { + file_usage_delete($file, 'media', $entity_type , $entity_id, $count); + } + } +} + +/** * Parses the contents of a CSS declaration block and returns a keyed array of property names and values. * * @param $declarations