Thursday, May 27, 2010

Keeping Media Metadata In Sync

When media files are uploaded to Sitecore, a Sitecore item is created. This item represents the media file in Sitecore. When you want to display information about the media file, you are displaying information about the item. When the file is updated, Sitecore ensures that the fields on the item stay in sync with the file.

Well, Sitecore does this for fields it is aware of. This is handled by the Sitecore.Resources.Media.Media class (and the classes that inherit from it). Thanks to the ImageMedia class, when you upload an image file, the height and width are read. Sitecore does not include a class to handle Microsoft Word documents, so metadata from those files is NOT read.

Creating a class to read metadata from Word documents, or any other file, is not hard to do. Sitecore is already set up to allow it. You just need to write the code that can read the metadata from the media file. The Sitecore Experience blog has a post that explains how to do this.

But what if you want a change to go the other direction? What if you want to update the document title in a Word document using Sitecore? This is also possible, but requires a little more work. In this post I'm going to explain how to do this for a docx file.

Triggering code when the Sitecore item is saved
When the Sitecore item is changed, code needs to run that updates the corresponding media file. This is accomplished by hooking into the "item:saved" event in web.config (or other config file).

<events>
<event name="item:saved">
<handler type="Sitecore.Marketing.MediaLibrary.MediaItemSavedHandler, Sitecore.Marketing.MediaLibrary" method="OnItemSaved"/>
</event>
</events>


And the MediaItemSavedHandler class must be defined. The rest of the code in this post goes inside this class.

public class MediaItemSavedHandler
{
protected void OnItemSaved(object sender, EventArgs args)
{
}
}



Determining if the item represents a media file
Since this event handler applies to all items, it is important to determine if the item that was saved represents a media file. This can be accomplished by checking the item's template ID.

Item item = Event.ExtractParameter(args, 0) as Item;
bool isDocx = item.TemplateID.ToString().Equals("{7BB0411F-50CD-4C21-AD8F-1FCDE7C3AFFE}");
if (!isDocx)
{
return;
}


Determining if the title has actually changed
Just because the item saved event is triggered doesn't mean it was triggered by a change to the title. The EventArgs parameter will indicate if the title has changed:

ItemChanges changes = Event.ExtractParameter(args, 1) as ItemChanges;
Field titleField = item.Fields["Title"];
bool hasTitleChanged = (changes.HasFieldsChanged && titleField != null && changes.IsFieldModified(titleField));
if (!hasTitleChanged)
{
return;
}
MediaItem media = new MediaItem(item);



Updating the media file
Next you need to update the media file in Sitecore. Access to Sitecore media files is available through the WebDAV interface, but communicating with the WebDAV server is a topic for a separate post. I'm going to take the easy way out here: I'm going to read the current file to a temp file, update the temp file, then replace the file in Sitecore.

Additionally, I'm not going to include all of the code needed update the docx file. I'll show you how to read a file from the media library and how to write a file to the media library.

If you're familiar with how .NET handled I/O, there's not much to accessing the media file. Here is an example of how to read and write Sitecore media files.

protected string CreateTempFile(MediaItem media)
{
string fileName = Path.GetTempFileName();
using (FileStream file = new FileStream(fileName, FileMode.Open))
{
Stream stream = media.GetMediaStream();
byte[] buffer = new byte[1024];
int count = stream.Read(buffer, 0, 1024);
while (count > 0)
{
file.Write(buffer, 0, count);
count = stream.Read(buffer, 0, count);
}
}
return fileName;
}

protected void ReplaceFileInSitecore(string fileName, MediaItem mediaItem)
{
Media media = MediaManager.GetMedia(mediaItem);
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
media.SetStream(stream, "docx");
}
}



Want to learn more?

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.