Attachments v0.7

Add support for file uploads to your model with the hasAttachment() function. Also provides attachmentImageTag() and attachmentLinkTo() view helpers.

Automatically resize uploaded images to a set of "styles" that you define. (For example, you could automatically resize for thumbnail, small, medium, large, etc.)

Overrides fileField() to work better with <cffile> and nested properties.

Dependencies

You must also install the JSON Properties plugin for the Attachments plugin to work.

Usage

Model Configuration

Call the included hasAttachment() from a model's init() method to bind one or more properties to handle uploaded files.

The plugin stores data about the uploaded files as serialized JSON data in your model, so you should set the configured property's corresponding database column to a type of TEXT or similar.

hasAttachment() Arguments

Argument Type Required Default Description
property string true Name of property on the model to store JSON data related to the attached file.
url string false /files/attachments/:model/
:property/:id/:style/:filename
Format in which to reference the file as a URL. Use placeholders for :model, :property, :id, :style, and :filename.
path string false /files/attachments/:model/
:property/:id/:style/:filename
Format in which to store the file in storage. Use placeholders for :model, :property, :id, :style, and :filename.
styles string false [empty string] You may pass in multiple styles. The syntax is nameOfStyle:widthxheight>. An actual example would be small:150x150>,medium:300x300>. The greater than sign at the end means that the attchments plugin should keep the aspect ratio of the photo uploaded. Styles will only be run on images that your ColdFusion server can do processing on.
storage string false filesystem Other options include s3 and filesystem,s3
blockExtensions string false cfm,cfml,cfc,dbm,jsp,asp,
aspx,exe,php,cgi,shtml
List of file extensions to not allow. This is the default behavior unless overridden by allowExtensions. If allowExtensions is set, this argument is then ignored.
allowExtensions string false [empty string] List of file extensions to allow. If this is set, the blockExtensions argument is ignored.

Callbacks

This plugin adds its own callbacks to the model's callback chain.

Most of the time, this will not matter to you, but if you want for the model to do additional processing on the data after the plugin has done its job, you will want to add your own callback chains using afterCreate and afterUpdate.

Examples

Example 1: Simple configuration

In its most simple form, let's pretend that you want to save files to a property in the comment model called attachment:

<--- models/Comment.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<!--- The `attachment` column should be of type `TEXT` --->
		<cfset hasAttachment("attachment")>
	</cffunction>
</cfcomponent>

In your form, you can use the fileField() helper to allow users to upload the attachment, and the plugin will take care of the rest.

<cfoutput>
	#startFormTag(action="create")#
		#fileField(label="Upload an Attachment" objectName="comment", property="attachment")#
		#submitTag(value="Upload")#
	#endFormTag()#
</cfoutput>

On your application's file system, the file will be saved to /files/attachments/comment/attachment/197/my_spreadsheet.xlsx (assuming that the record gets assigned an id of 197 and that the file uploaded by the user is named my_spreadsheet.xlsx). You will then be able to reference data about the uploaded file in the attachment property.

<--- controllers/Comments.cfc --->
<cfcomponent extends="Controller">
	<cffunction name="view">
		<cfset comment = model("comment").findByKey(197)>
	</cffunction>
</cfcomponent>

<--- views/comments/view.cfm --->
<cfoutput>
	<p><a href="#comment.attachment.url#">Download the File</a></p>
</cfoutput>
Example 2: Saving to a different location

If you want to store the file in a different location on the server, you can specify the path using the :path argument and the placeholders for :model, :property, :id, :style (more on this later), and :filename. Note that the :style part of the path is only used if you define image styles using the styles argument.

<--- models/Comment.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<!--- The `attachment` column should be of type `TEXT` --->
		<cfset hasAttachment(property="attachment", path="/files/uploads/:model/:property/:id/:style/:filename")>
	</cffunction>
</cfcomponent>

If your server is configured to serve files from different URL than the default, you can also specify that with the url argument.

<--- models/Comment.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<cfset hasAttachment(property="attachment", path="/files/uploads/:model/:property/:id/:style/:filename", url="http://media.example.com/:model/:property/:id/:style/:filename")>
	</cffunction>
</cfcomponent>
Example 3: Styles for images

The attachments plugin will also handle the creation of "styles" for image files uploaded to your model. If you choose, you can create any named style that you would like (for example, thumbnail).

Let's say that we want to create 2 image styles: a thumbnail style at 50 x 50 pixels and a medium style at 250 x 250 pixels. You would use the styles argument like so:

<--- models/Profile.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<cfset hasAttachment(property="avatar", styles="medium:250x250,thumbnail:50x50")>
	</cffunction>
</cfcomponent>

Now when the user uploads an image file supported by your CFML engine and your model passes validation, the Attachments plugin will resize the image into those dimensions (and crop off any excess).

If you'd rather keep an image's aspect ratio the same and define a set of boundaries for the image, you can add a > character to the end of any of the styles.

<--- models/Profile.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<cfset hasAttachment(property="avatar", styles="medium:250x250>,thumbnail:50x50")>
	</cffunction>
</cfcomponent>

With the styles defined above, let's say that the user uploads an image called Vacation-in-Switzerland.jpg that is 400 by 300 pixels. The resulting file structure will look like this after the Attachments plugin does its magic:

Example 4: Whitelisting files

By default, the Attachments plugin will block a list of potentially malicious files (using a default value for the blockExtensions argument). But it is strongly recommended for security reasons that you define a whitelist of what is allowed to be uploaded instead.

Pretending that we only wanted some Microsoft Office formats to be uploaded, we could define something like this using the allowExtensions argument:

<--- models/Comment.cfc --->
<cfcomponent extends="Model">
	<cffunction name="init">
		<cfset hasAttachment(property="attachment", allowExtensions="doc,docx,xls,xlsx,ppt,pptx,mdb")>
	</cffunction>
</cfcomponent>

Note that when the allowExtensions list is provided, the blockExtensions list will be ignored completely.

View Helpers

The plugin also provides helpers—attachmentImageTag() and attachmentLinkTo()—for displaying images and linking to files uploaded via attachments.

Displaying Images via attachmentImageTag()

attachmentImageTag() allows you to display an image uploaded via the Attachments plugin. It optionally allows you to specify any style generated when the attachment was uploaded and handles all of the data references for you.

Argument Type Required Default Description
attachment string/struct false [empty string] Value of attachment property. Accepts both JSON- and struct-formatted data.
attachmentStyle string false [empty string] Name of image style to reference (as configured in hasAttachment()'s styles argument.

Examples

Example 1: Simple image call

Given that there is an attachment property called attachment on the user model:

// In the `init()` method of `models/User.cfc`
hasAttachment(property="attachment", allowExtensions=GetReadableImageFormats());

You can display uploaded images like so:

<cfoutput>
	#attachmentImageTag(attachment=user.attachment)#
</cfoutput>
Example 2: Display stylized image

Given that there is an attachment property called avatar on the profile model with a style called small:

// In the `init()` method of `models/Profile.cfc`
#hasAttachment(property="avatar", styles="small:100x100", allowExtensions=GetReadableImageFormats())#

You can display the stylized image like so:

<cfoutput>
	#attachmentImageTag(attachment=profile.avatar, attachmentStyle="small")#
</cfoutput>

Linking to Files via attachmentLinkTo()

Similar to attachmentImageTag(), attachmentLinkTo() allows you to link to a file uploaded via this plugin, also optionally with image styles.

Argument Type Required Default Description
text string false [empty string] Link text. If left blank, the path to the attachment file is used as the link text.
attachment string/struct false [empty string] Value of attachment property. Accepts both JSON- and struct-formatted data.
attachmentStyle string false [empty string] Name of image style to reference (as configured in hasAttachment()'s styles argument.

Examples

Example 1: Simple link

Given that there is an attachment property called documentation on the equipment model:

// In the `init()` method of `models/Equipment.cfc`
#hasAttachment(property="documentation")#

You can link to the file in your view like this:

<cfoutput>
	#attachmentLinkTo(text="Download the Manual", attachment=equipment.documentation)#
</cfoutput>
Example 2: Link directly to a stylized image

Given that there is an attachment property called photo on the person model with a style of medium:

// In the `init()` method of `models/Person.cfc`
#hasAttachment(property="photo", styles="medium:300x300>,avatar:100x100", allowExtensions=GetReadableImageFormats())#

You can link to the stylized image in your view like so:

<cfoutput>
	#attachmentLinkTo(text="Download Photo", attachment=person.photo, attachmentStyle="medium")#
</cfoutput>

Uninstallation

To uninstall this plugin, simply delete the /plugins/Attachments-0.7.zip file.

Credits

This plugin was created by James Gibson and Chris Peters with support from Liquifusion Studios.

Warnings: The FallbackImage plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The LogUserAction plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The RequiredFields plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The JsonProperties plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The DefaultScope plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The Attachments plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The localerb plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The AssetBundler plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The PluginPackager plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
The inWords plugin may be incompatible with this version of Wheels, please look for a compatible version of the plugin
Application: AlexTasselV3 [Run Tests]
Framework: Wheels 1.1.8
CFML Engine: Adobe ColdFusion 9,0,1,274733
Default Data Source: alextassel
Active Environment: Design
URL Rewriting: On
URL Obfuscation: Off
Plugins: FallbackImage
LogUserAction
RequiredFields
DefaultScope
JsonProperties
simpleProperties
Attachments
AssetBundler
localerb
inWords
PluginPackager
Route: home
Controller: Wheels
Action: wheels
Additional Params: name = attachments
view = plugins
Caching Stats: hits: 0, misses: 0, culls: 0
Execution Time: 16ms (view ~16ms, action ~16ms)