Let's finish this up with Part 3. We only have two things to look at yet, and that's our Rule and webskin.
The Rule
<cfcomponent displayname="Mass Mailer Rule" extends="farcry.core.packages.rules.rules" hint="Allows you to select a list for user to sign up for">
<cfproperty ftSeq="1" ftFieldSet="List" name="intro" type="longchar" hint="Introduction HTML for list." ftLabel="Intro" ftType="longchar" />
<cfproperty ftSeq="2" ftFieldSet="List" name="ListID" type="UUID" hint="ID of the List to be displayed" ftLabel="List" ftType="UUID" ftJoin="massMailerList" />
<cfproperty ftseq="3" ftFieldset="List" name="displayMethod" type="string" hint="Display method to render." required="yes" default="display" fttype="webskin" ftprefix="displayList" ftTypename="massMailerList" ftlabel="Content Template" />
<cffunction name="execute" hint="Displays the text rule on the page." output="true" returntype="void" access="public">
<cfargument name="objectID" required="Yes" type="uuid" default="">
<cfset var stObj = getData(arguments.objectid) />
<cfset var oList = createObject("component","farcry.plugins.massMailer.packages.types.massMailerList") />
<cfset var stData = oList.getData(stObj.ListID) />
<cfset var stInvoke = structNew() />
<cfscript>
if (len(stobj.intro))
arrayAppend(request.aInvocations,stobj.intro);
stInvoke.objectID = stData.ObjectID;
stInvoke.typename = application.types.massMailerList.typepath;
stInvoke.method = stObj.displayMethod;
arrayAppend(request.aInvocations,stInvoke);
</cfscript>
</cffunction>
</cfcomponent>
Not too complicated, and once again, formtools comes to our rescue! To get a real breadth of what can be done with rules, you really should take a look at the existing core and farcrycms rules. Some of them have much more functionality than what was required for this rule.
Basically, if you want to have something displayed on the screen, you need to make a cfproperty for it. The usual formtools ideas apply. The items I required were the ID of the list, and the name of the webskin to display it. Formtools can grab this list of webskins for you with the fttype="webskin".
The real magic is in the execute fucntion. It will create our stObj (which the webskin will use), and also invoke the webskin to be used. To be frank, I've not dug into the internals much within rules. This one will get the job done, but I don't have the greatest of knowledge of this piece of FarCry.
The webskin
The essence of the skin is to display two form fields, name and address, and submit this information as a aObjectID into the massMailerList. The nifty drag-n-drop display does this for us, so I simply "borrowed" those pieces to pull this of.
<cfsetting enablecfoutputonly="true">
<!--- @@displayname: Display Mass Mailer Signup Form --->
<!--- @@author: Matthew Williams --->
<cfif isdefined('form.FARCRYFORMSUBMITBUTTON')>
<cfimport taglib="/farcry/core/tags/formtools/" prefix="ft" >
<cfinclude template="/farcry/core/admin/includes/utilityFunctions.cfm">
<cfparam name="form.primaryObjectID" default="">
<cfparam name="form.primaryTypeName" default="">
<cfparam name="form.primaryFieldName" default="">
<cfparam name="form.primaryFormFieldName" default="">
<cfparam name="form.ftJoin" default="">
<cfparam name="form.wizardID" default="">
<cfparam name="form.LibraryType" default="array">
<cfparam name="form.ftLibraryAddNewWebskin" default="libraryAdd"><!--- Method to Add New Object --->
<cfparam name="form.ftLibraryPickWebskin" default="libraryPick"><!--- Method to Pick Existing Objects --->
<cfparam name="form.ftLibraryPickListClass" default="thumbNailsWrap">
<cfparam name="form.ftLibraryPickListStyle" default="">
<cfparam name="form.ftLibrarySelectedWebskin" default="librarySelected"><!--- Method to Pick Existing Objects --->
<cfparam name="form.ftLibrarySelectedListClass" default="thumbNailsWrap">
<cfparam name="form.ftLibrarySelectedListStyle" default="">
<cfparam name="form.ftAllowLibraryAddNew" default=""><!--- Method to Add New Object --->
<cfparam name="form.ftAllowLibraryEdit" default=""><!--- Method to Edit Object --->
<cfparam name="form.PackageType" default="types"><!--- Could be types or rules.. --->
<cfparam name="form.currentpage" default="1">
<cfif form.PackageType EQ "rules">
<cfset PrimaryPackage = application.rules[form.primaryTypeName] />
<cfset PrimaryPackagePath = application.rules[form.primaryTypeName].rulepath />
<cfelse>
<cfset PrimaryPackage = application.types[form.primaryTypeName] />
<cfset PrimaryPackagePath = application.types[form.primaryTypeName].typepath />
</cfif>
<!--- TODO: dynamically determine the typename to join. --->
<cfset request.ftJoin = listFirst(form.ftJoin) />
<cfif NOT listContainsNoCase(PrimaryPackage.stProps[form.primaryFieldname].metadata.ftJoin,request.ftJoin)>
<cfset request.ftJoin = listFirst(PrimaryPackage.stProps[form.primaryFieldname].metadata.ftJoin) />
</cfif>
<ft:processForm action="Attach,Attach & Add Another">
<ft:processFormObjects typename="#request.ftJoin#" /><!--- Returns variables.lSavedObjectIDs --->
<cfset oPrimary = createObject("component",PrimaryPackagePath)>
<cfset oData = createObject("component",application.types[request.ftJoin].typepath)>
<cfloop list="#lSavedObjectIDs#" index="DataObjectID">
<cfif len(form.wizardID)>
<cfset owizard = createObject("component",application.types['dmWizard'].typepath)>
<cfset stwizard = owizard.Read(wizardID=form.wizardID)>
<cfif form.LibraryType EQ "UUID">
<cfset stwizard.Data[form.PrimaryObjectID][form.PrimaryFieldname] = DataObjectID>
<cfelse><!--- Array --->
<cfset arrayAppend(stwizard.Data[form.PrimaryObjectID][form.PrimaryFieldname],DataObjectID)>
<cfset variables.tableMetadata = createobject('component','farcry.core.packages.fourq.TableMetadata').init() />
<cfset tableMetadata.parseMetadata(md=getMetadata(oPrimary)) />
<cfset stFields = variables.tableMetadata.getTableDefinition() />
<cfset o = createObject("component","farcry.core.packages.fourq.gateway.dbGateway").init(dsn=application.dsn,dbowner="")>
<cfset aProps = o.createArrayTableData(tableName=form.PrimaryTypename & "_" & form.PrimaryFieldName,objectid=form.PrimaryObjectID,tabledef=stFields[PrimaryFieldName].Fields,aprops=stwizard.Data[PrimaryObjectID][form.PrimaryFieldname])>
<cfset stwizard.Data[form.PrimaryObjectID][form.PrimaryFieldname] = aProps>
</cfif>
<cfset stwizard = owizard.Write(ObjectID=form.wizardID,Data=stwizard.Data)>
<cfset st = stwizard.Data[form.PrimaryObjectID]>
<cfelse>
<cfset stPrimary = oPrimary.getData(objectid=form.PrimaryObjectID)>
<cfif form.LibraryType EQ "UUID">
<cfset stPrimary[form.PrimaryFieldname] = DataObjectID>
<cfelse><!--- Array --->
<cfset arrayAppend(stPrimary[form.PrimaryFieldname],DataObjectID)>
</cfif>
<cfparam name="session.dmSec.authentication.userlogin" default="anonymous" />
<cfset oPrimary.setData(objectID=stPrimary.ObjectID,stProperties="#stPrimary#",user="#session.dmSec.authentication.userlogin#")>
</cfif>
</cfloop>
</ft:processForm>
</cfif>
<cfscript>
formObj.primaryHash = stObj.objectid;
formObj.primaryNoHash = replace(formObj.primaryHash,'-','','all');
formObj.userObjHash = createuuid();
formObj.userObjNoHash = replace(formObj.userObjHash,'-','','all');
</cfscript>
<cfoutput>
<cfif isdefined('form.FARCRYFORMSUBMITBUTTON')>
<p>Your email address has been added to the list!</p>
</cfif>
<form action="" method="post" id="farcryForm936443538" name="farcryForm936443538" target="" enctype="multipart/form-data" onsubmit="" class="formtool" style=""><input type="hidden" name="phpMyAdmin" value="6ffe8b831e4bded08a42997de2b6eeaa" />
<p>Name: <input type="Text" name="#formObj.userObjHash#Title" id="#formObj.userObjHash#Title" value="" class="" style="" /></p>
<p>Email:<input type="Text" name="#formObj.userObjHash#Email" id="#formObj.userObjHash#Email" value="" class="" style="" /></p>
<input type="hidden" name="#formObj.userObjHash#DateAddedinclude" id="#formObj.userObjHash#DateAddedinclude" value="1">
<input type="hidden" name="#formObj.userObjHash#DateAdded" id="#formObj.userObjHash#DateAdded" value="#now()#" style="" /></p>
<input type="hidden" name="#formObj.userObjHash#ObjectID" value="#formObj.userObjHash#">
<input type="hidden" name="#formObj.userObjHash#Typename" value="massMailerUser">
<input type="submit" name="FarcryFormSubmitButton" value="Attach" onclick=";$('FarcryFormSubmitButtonClickedfarcryForm936443538').value = 'Attach';;return realeasyvalidation.validate();" class="formButton " style="" />
<input type="hidden" name="FarcryFormPrefixes" id="FarcryFormPrefixes" value="#formObj.userObjHash#" />
<input type="hidden" name="FarcryFormSubmitButton" id="FarcryFormSubmitButton" value="" />
<input type="hidden" name="FarcryFormSubmitButtonClickedfarcryForm936443538" id="FarcryFormSubmitButtonClickedfarcryForm936443538" value="" />
<input type="hidden" name="FarcryFormSubmitted" id="FarcryFormSubmitted" value="farcryForm936443538" />
<input type="hidden" name="SelectedObjectID" id="SelectedObjectIDfarcryForm936443538" value="" />
<input type="hidden" name="PRIMARYFORMFIELDNAME" value="#formObj.primaryNoHash#aObjectIDs" />
<input type="hidden" name="FTALLOWLIBRARYADDNEW" value="massMailerUser" />
<input type="hidden" name="CURRENTPAGE" value="1" />
<input type="hidden" name="FTLIBRARYPICKLISTSTYLE" value="" />
<input type="hidden" name="FTLIBRARYSELECTEDLISTCLASS" value="arrayDetail" />
<input type="hidden" name="FTLIBRARYADDNEWWEBSKIN" value="libraryAdd" />
<input type="hidden" name="FTLIBRARYPICKWEBSKIN" value="libraryPick" />
<input type="hidden" name="FTLIBRARYSELECTEDWEBSKIN" value="LibrarySelected" />
<input type="hidden" name="PACKAGETYPE" value="types" />
<input type="hidden" name="PRIMARYOBJECTID" value="#formObj.primaryHash#" />
<input type="hidden" name="FTALLOWLIBRARYEDIT" value="massMailerUser" />
<input type="hidden" name="WIZARDID" value="" />
<input type="hidden" name="LIBRARYTYPE" value="array" />
<input type="hidden" name="PRIMARYTYPENAME" value="massMailerList" />
<input type="hidden" name="FTLIBRARYPICKLISTCLASS" value="thumbNailsWrap" />
<input type="hidden" name="PRIMARYFIELDNAME" value="aObjectIDs" />
<input type="hidden" name="FTJOIN" value="massMailerUser" />
<input type="hidden" name="FTLIBRARYSELECTEDLISTSTYLE" value="" />
<input type="hidden" name="librarySection" value="addnew" />
</form>
<script type="text/javascript">
var realeasyvalidation = new Validation('farcryForm936443538', {onSubmit:false});
</script>
</cfoutput>
<cfsetting enablecfoutputonly="false">
What we have is a call to formtools, supplied with our main object (massMailerList) and our attachment (massMailerUser). This code was wrought from within library.cfm. If you haven't already looked, it would be a great place to learn more about how the open library function works. I don't have any validation for the email field, yet. That's comming down the line.
Hopefully this makes this a little bit clearer. Or, at the very least, steers someone in the right direction.