one to many non mutual - orm

I've got a problem with a many-to-one / one-to-many relationship with menu.cfc and menuItem.cfc. Both of them extends node.cfc (declarations of these at the end).
index.cfm
<cfset oMenu = entityNew( "menu" )>
<cfset oMenu.setTitle( "Main menu" )>
<cfset entitySave( oMenu )>
<cfset ORMFlush()>
<cfset oMenuItem = entityNew( "menuItem" )>
<cfset oMenuItem.setTitle( "First main menu item" )>
<cfset oMenuItem.setMenu( oMenu )>
<cfset entitySave( oMenuItem )>
<cfset ORMFlush()>
<cfdump var="#oMenu.getMenuItems()#">
<!--- array[empty] --->
<!--- WHY ?--->
In the DB, my menu_item.menu_id is correct.
I also tried
<cfset oMenu = entityNew( "menu" )>
<cfset oMenu.setTitle( "Main menu" )>
<cfset entitySave( oMenu )>
<cfset ORMFlush()>
<cfset oMenuItem = entityNew( "menuItem" )>
<cfset oMenuItem.setTitle( "First main menu item" )>
<cfset entitySave( oMenuItem )>
<cfset ORMFlush()>
<cfset oMenu.addMenuItem( oMenuItem )>
<cfdump var="#oMenu.getMenuItems()#">
<!--- array[empty] --->
In the DB, my menu_item.menu_id is null!
If you have an idea of what I did wrong, It will be nice.
Thanks!
node.cfc
<cfcomponent entityname="node" output="false" persistent="true" table="nodes" discriminatorcolumn="type">
<cfproperty name="id" fieldtype="id" generator="identity" default="0" unsavedvalue="0">
<cfproperty name="type" insert="false" update="false">
<cfproperty name="title" ormtype="string" notnull="true" default="" loadInForm="true" required="true">
<cfproperty name="systemName" column="system_name" ormtype="string" notnull="true" default="" loadInForm="true" uniquekey="system_name_lang">
<cfproperty name="parents" singularname="parent" fieldtype="one-to-many" cfc="nodeHierarchy" inverse="true" weight="weight" clearBeforeSave="true">
<cfproperty name="children" singularname="child" fieldtype="one-to-many" cfc="nodeHierarchy" inverse="true" orderby="weight asc">
<cfproperty name="node" fieldtype="many-to-one" cfc="node" fkcolumn="nid">
<cfproperty name="created" ormtype="timestamp" sqltype="timestamp">
<cfproperty name="updated" ormtype="timestamp" sqltype="timestamp">
</cfcomponent>
menu.cfc
<cfcomponent entityname="menu" output="false" persistent="true" table="menus" extends="node" joincolumn="node_id" discriminatorvalue="menu">
<cfproperty name="menuItems" singularname="menuItem" fieldtype="one-to-many" cfc="menuItem" inverse="true">
</cfcomponent>
menuItem.cfc
<cfcomponent entityname="menuItem" output="false" persistent="true" table="menus_items" extends="node" joincolumn="node_id" discriminatorvalue="menu_item">
<cfproperty name="menu" fieldtype="many-to-one" cfc="menu" fkcolumn="menu_id">
<cfproperty name="parentMenuItem" fieldtype="many-to-one" cfc="menuItem" fkcolumn="menu_item_id">
<cfproperty name="childMenuItems" fieldtype="one-to-many" cfc="menuItem" fkcolumn="menu_item_id">
<cfproperty name="node" fieldtype="one-to-one" cfc="com.cfc.app.models.node" fkcolumn="nid">
</cfcomponent>

I solved the problem by doing this <cfset oMenuItem.setMenu( oMenu )> AND <cfset oMenu.addMenuItem( oMenuItem )>.
It seems working now.
index.cfm
<cfset oMenu = entityNew( "menu" )>
<cfset oMenu.setTitle( "Main menu" )>
<cfset entitySave( oMenu )>
<cfset ORMFlush()>
<cfset oMenuItem = entityNew( "menuItem" )>
<cfset oMenuItem.setTitle( "First main menu item" )>
<cfset oMenuItem.setMenu( oMenu )>
<cfset entitySave( oMenuItem )>
<cfset ORMFlush()>
<cfset oMenu.addMenuItem( oMenuItem )>
<cfset entitySave( oMenu)>
<cfset ORMFlush()>
<cfdump var="#oMenu.getMenuItems()#">

Related

Is ORM supported by ColdFusion 11?

Mapping Two cfc objects via ORM, on execution a Dump shows the data for only one parent cfc object for table=products while the array of cfc table=department is coming back as (empty string) in output .
<cfcomponent persistent="true" table="products" >
<cfproperty name="productID" column="id" fieldtype="id" type="numeric" generator="increment">
<cfproperty name="name">
<cfproperty name="price">
<cfproperty name="description">
<cfproperty name="imageurl">
<cfproperty name="departmt" fieldtype="many-to-one" cfc="departmt" fkcolumn="dept_id" lazy="true">
<cfcomponent persistent="true" table="department">
<cfproperty name="id" column="dept_id" fieldtype="id" type="numeric" generator="increment">
<cfproperty name="name" column="dept_name">
<cfproperty name="location" >
</cfcomponent>

Coldfusion: The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256

I'm getting signature version error
Response : InvalidRequestThe authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.5BD2DFA1B0ECAA01HBXUWHbeNnB8Lfp+YNgiCxQyPInN+YlIfJtsmScVY6abqNtKYdhqCFU4xPnoTRZkqaKZLnAOqlY=
Here is the code
Written by Joe Danziger (joe#ajaxcf.com) with much help from
dorioo on the Amazon S3 Forums. See the readme for more
details on usage and methods.
Thanks to Steve Hicks for the bucket ACL updates.
Thanks to Carlos Gallupa for the EU storage location updates.
Thanks to Joel Greutman for the fix on the getObject link.
Thanks to Jerad Sloan for the Cache Control headers.
Version 1.8 - Released: July 27, 2010
Version 1.9 - Released: January 6, 2011
--->
<cfset variables.accessKeyId = "">
<cfset variables.secretAccessKey = "">
<cffunction name="init" access="public" returnType="s3" output="false"
hint="Returns an instance of the CFC initialized.">
<cfargument name="accessKeyId" type="string" required="true" hint="Amazon S3 Access Key ID.">
<cfargument name="secretAccessKey" type="string" required="true" hint="Amazon S3 Secret Access Key.">
<cfset variables.accessKeyId = arguments.accessKeyId>
<cfset variables.secretAccessKey = arguments.secretAccessKey>
<cfreturn this>
</cffunction>
<cffunction name="HMAC_SHA1" returntype="binary" access="private" output="false" hint="NSA SHA-1 Algorithm">
<cfargument name="signKey" type="string" required="true" />
<cfargument name="signMessage" type="string" required="true" />
<cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1") />
<cfset var jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1") />
<cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") />
<cfset var mac = createObject("java","javax.crypto.Mac") />
<cfset key = key.init(jKey,"HmacSHA1") />
<cfset mac = mac.getInstance(key.getAlgorithm()) />
<cfset mac.init(key) />
<cfset mac.update(jMsg) />
<cfreturn mac.doFinal() />
</cffunction>
<cffunction name="createSignature" returntype="string" access="public" output="false">
<cfargument name="stringIn" type="string" required="true" />
<!--- Replace "\n" with "chr(10) to get a correct digest --->
<cfset var fixedData = replace(arguments.stringIn,"\n","#chr(10)#","all")>
<!--- Calculate the hash of the information --->
<!---<cfset var digest = HMAC_SHA1(variables.secretAccessKey,fixedData)>--->
<cfset var digest = HMAC( fixedData, variables.secretAccessKey, 'HmacSHA256' )>
<!--- fix the returned data to be a proper signature --->
<cfset var signature = ToBase64("#digest#")>
<cfreturn signature>
</cffunction>
<cffunction name="getBuckets" access="public" output="false" returntype="array"
description="List all available buckets.">
<cfset var data = "">
<cfset var bucket = "">
<cfset var buckets = "">
<cfset var thisBucket = "">
<cfset var allBuckets = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send --->
<cfset var cs = "GET\n\n\n#dateTimeString#\n/">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- get all buckets via REST --->
<cfhttp method="GET" url="http://s3.amazonaws.com">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfset data = xmlParse(cfhttp.FileContent)>
<cfset buckets = xmlSearch(data, "//:Bucket")>
<!--- create array and insert values from XML --->
<cfset allBuckets = arrayNew(1)>
<cfloop index="x" from="1" to="#arrayLen(buckets)#">
<cfset bucket = buckets[x]>
<cfset thisBucket = structNew()>
<cfset thisBucket.Name = bucket.Name.xmlText>
<cfset thisBucket.CreationDate = bucket.CreationDate.xmlText>
<cfset arrayAppend(allBuckets, thisBucket)>
</cfloop>
<cfreturn allBuckets>
</cffunction>
<cffunction name="putBucket" access="public" output="false" returntype="boolean"
description="Creates a bucket.">
<cfargument name="bucketName" type="string" required="true">
<cfargument name="acl" type="string" required="false" default="public-read">
<cfargument name="storageLocation" type="string" required="false" default="">
<cfset var strXML = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send based on operation requested --->
<cfset var cs = "PUT\n\ntext/html\n#dateTimeString#\nx-amz-acl:#arguments.acl#\n/#arguments.bucketName#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<cfif compare(arguments.storageLocation,'')>
<cfsavecontent variable="strXML">
<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LocationConstraint>#arguments.storageLocation#</LocationConstraint></CreateBucketConfiguration>
</cfsavecontent>
<cfelse>
<cfset strXML = "">
</cfif>
<!--- put the bucket via REST --->
<cfhttp method="PUT" url="http://s3.amazonaws.com/#arguments.bucketName#" charset="utf-8">
<cfhttpparam type="header" name="Content-Type" value="text/html">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="x-amz-acl" value="#arguments.acl#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
<cfhttpparam type="body" value="#trim(strXML)#">
</cfhttp>
<cfreturn true>
</cffunction>
<cffunction name="getBucket" access="public" output="false" returntype="array"
description="Creates a bucket.">
<cfargument name="bucketName" type="string" required="yes">
<cfargument name="prefix" type="string" required="false" default="">
<cfargument name="marker" type="string" required="false" default="">
<cfargument name="maxKeys" type="string" required="false" default="">
<cfargument name="showVersions" type="boolean" required="false" default="false">
<cfset var cs = "">
<cfset var data = "">
<cfset var content = "">
<cfset var contents = "">
<cfset var version = "">
<cfset var versions = "">
<cfset var signature = "">
<cfset var versioning = "">
<cfset var prefixString = "">
<cfset var markerString = "">
<cfset var maxKeysString = "">
<cfset var thisContent = "">
<cfset var allContents = "">
<cfset var thisVersion = "">
<cfset var allVersions = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- add proper versioning call if requested --->
<cfif arguments.showVersions>
<cfset versioning = "?versions">
</cfif>
<!--- Create a canonical string to send --->
<cfset cs = "GET\n\n\n#dateTimeString#\n/#arguments.bucketName##versioning#">
<!--- Create a proper signature --->
<cfset signature = createSignature(cs)>
<!--- get the bucket via REST --->
<cfif arguments.showVersions>
<cfif compare(arguments.prefix,'')>
<cfset prefixString = "&prefix=#arguments.prefix#">
</cfif>
<cfif compare(arguments.marker,'')>
<cfset markerString = "&marker=#arguments.marker#">
</cfif>
<cfif isNumeric(arguments.maxKeys)>
<cfset maxKeysString = "&max-keys=#arguments.maxKeys#">
</cfif>
<cfhttp method="GET" url="http://s3.amazonaws.com/#arguments.bucketName#?versions#prefixString##markerString##maxKeysString#">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfelse>
<cfhttp method="GET" url="http://s3.amazonaws.com/#arguments.bucketName#">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
<cfif compare(arguments.prefix,'')>
<cfhttpparam type="URL" name="prefix" value="#arguments.prefix#">
</cfif>
<cfif compare(arguments.marker,'')>
<cfhttpparam type="URL" name="marker" value="#arguments.marker#">
</cfif>
<cfif isNumeric(arguments.maxKeys)>
<cfhttpparam type="URL" name="max-keys" value="#arguments.maxKeys#">
</cfif>
</cfhttp>
</cfif>
<cfset data = xmlParse(cfhttp.FileContent)>
<cfif arguments.showVersions>
<cfset versions = xmlSearch(data, "//:Version")>
<!--- create array and insert values from XML --->
<cfset allVersions = arrayNew(1)>
<cfloop index="x" from="1" to="#arrayLen(versions)#">
<cfset version = versions[x]>
<cfset thisVersion = structNew()>
<cfset thisVersion.Key = version.Key.xmlText>
<cfset thisVersion.VersionID = version.VersionID.xmlText>
<cfset thisVersion.isLatest = version.IsLatest.xmlText>
<cfset thisVersion.LastModified = version.LastModified.xmlText>
<cfset thisVersion.Size = version.Size.xmlText>
<cfset thisVersion.StorageClass = version.StorageClass.xmlText>
<cfset arrayAppend(allVersions, thisVersion)>
</cfloop>
<cfreturn allVersions>
<cfelse>
<cfset contents = xmlSearch(data, "//:Contents")>
<!--- create array and insert values from XML --->
<cfset allContents = arrayNew(1)>
<cfloop index="x" from="1" to="#arrayLen(contents)#">
<cfset content = contents[x]>
<cfset thisContent = structNew()>
<cfset thisContent.Key = content.Key.xmlText>
<cfset thisContent.LastModified = content.LastModified.xmlText>
<cfset thisContent.Size = content.Size.xmlText>
<cfset thisContent.StorageClass = content.StorageClass.xmlText>
<cfset arrayAppend(allContents, thisContent)>
</cfloop>
<cfreturn allContents>
</cfif>
</cffunction>
<cffunction name="deleteBucket" access="public" output="false" returntype="boolean"
description="Deletes a bucket.">
<cfargument name="bucketName" type="string" required="yes">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send based on operation requested --->
<cfset var cs = "DELETE\n\n\n#dateTimeString#\n/#arguments.bucketName#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- delete the bucket via REST --->
<cfhttp method="DELETE" url="http://s3.amazonaws.com/#arguments.bucketName#" charset="utf-8">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfreturn true>
</cffunction>
<cffunction name="putObject" access="public" output="false" returntype="string"
description="Puts an object into a bucket.">
<cfargument name="bucketName" type="string" required="yes">
<cfargument name="fileKey" type="string" required="yes">
<cfargument name="contentType" type="string" required="yes">
<cfargument name="HTTPtimeout" type="numeric" required="no" default="300">
<cfargument name="cacheControl" type="boolean" required="false" default="true">
<cfargument name="cacheDays" type="numeric" required="false" default="30">
<cfargument name="acl" type="string" required="no" default="public-read">
<cfargument name="storageClass" type="string" required="no" default="STANDARD">
<cfargument name="keyName" type="string" required="no" default="#arguments.fileKey#">
<cfargument name="uploadDir" type="string" required="no" default="#ExpandPath('./')#">
<cfset var versionID = "">
<cfset var binaryFileData = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<cfset var cs = "">
<cfset var signature = "">
<!--- if keyName submitted blank, use fileKey --->
<cfif not compare(arguments.keyName,'')>
<cfset arguments.keyName = arguments.fileKey>
</cfif>
<!--- Create a canonical string to send --->
<cfset cs = "PUT\n\n#arguments.contentType#\n#dateTimeString#\nx-amz-acl:#arguments.acl#\nx-amz-storage-class:#arguments.storageClass#\n/#arguments.bucketName#/#arguments.keyName#">
<!--- Create a proper signature --->
<cfset signature = createSignature(cs)>
<!--- Read the image data into a variable --->
<cffile action="readBinary" file="#arguments.uploadDir##arguments.fileKey#" variable="binaryFileData">
<!--- Send the file to amazon. The "X-amz-acl" controls the access properties of the file --->
<cfhttp method="PUT" url="https://cinetimes.s3.amazonaws.com/#arguments.bucketName#/#arguments.keyName#" timeout="#arguments.HTTPtimeout#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
<cfhttpparam type="header" name="Content-Type" value="#arguments.contentType#">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="x-amz-acl" value="#arguments.acl#">
<cfhttpparam type="header" name="x-amz-storage-class" value="#arguments.storageClass#">
<cfhttpparam type="body" value="#binaryFileData#">
<cfif arguments.cacheControl>
<cfhttpparam type="header" name="Cache-Control" value="max-age=2592000">
<cfhttpparam type="header" name="Expires" value="#DateFormat(now()+arguments.cacheDays,'ddd, dd mmm yyyy')# #TimeFormat(now(),'H:MM:SS')# GMT">
</cfif>
</cfhttp>
<cfdump var="https://cinetimes.s3.amazonaws.com/#arguments.bucketName#/#arguments.keyName#">
<cfdump var="#signature#">
<cfdump var="#cfhttp#"><cfabort>
<cftry>
<cfset versionID = cfhttp.responseHeader['x-amz-version-id']>
<cfcatch></cfcatch>
</cftry>
<cfreturn versionID>
</cffunction>
<cffunction name="getObject" access="public" output="false" returntype="string"
description="Returns a link to an object.">
<cfargument name="bucketName" type="string" required="yes">
<cfargument name="fileKey" type="string" required="yes">
<cfargument name="minutesValid" type="string" required="false" default="60">
<cfset var timedAmazonLink = "">
<cfset var epochTime = DateDiff("s", DateConvert("utc2Local", "January 1 1970 00:00"), now()) + (arguments.minutesValid * 60)>
<!--- Create a canonical string to send --->
<cfset var cs = "GET\n\n\n#epochTime#\n/#arguments.bucketName#/#arguments.fileKey#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- Create the timed link for the image --->
<cfset timedAmazonLink = "http://s3.amazonaws.com/#arguments.bucketName#/#arguments.fileKey#?AWSAccessKeyId=#URLEncodedFormat(variables.accessKeyId)#&Expires=#epochTime#&Signature=#URLEncodedFormat(signature)#">
<cfreturn timedAmazonLink>
</cffunction>
<cffunction name="deleteObject" access="public" output="false" returntype="boolean"
description="Deletes an object.">
<cfargument name="bucketName" type="string" required="yes">
<cfargument name="fileKey" type="string" required="yes">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send based on operation requested --->
<cfset var cs = "DELETE\n\n\n#dateTimeString#\n/#arguments.bucketName#/#arguments.fileKey#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- delete the object via REST --->
<cfhttp method="DELETE" url="http://s3.amazonaws.com/#arguments.bucketName#/#arguments.fileKey#">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfreturn true>
</cffunction>
<cffunction name="copyObject" access="public" output="false" returntype="boolean"
description="Copies an object.">
<cfargument name="oldBucketName" type="string" required="yes">
<cfargument name="oldFileKey" type="string" required="yes">
<cfargument name="newBucketName" type="string" required="yes">
<cfargument name="newFileKey" type="string" required="yes">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send based on operation requested --->
<cfset var cs = "PUT\n\napplication/octet-stream\n#dateTimeString#\nx-amz-copy-source:/#arguments.oldBucketName#/#arguments.oldFileKey#\n/#arguments.newBucketName#/#arguments.newFileKey#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<cfif compare(arguments.oldBucketName,arguments.newBucketName) or compare(arguments.oldFileKey,arguments.newFileKey)>
<!--- delete the object via REST --->
<cfhttp method="PUT" url="http://s3.amazonaws.com/#arguments.newBucketName#/#arguments.newFileKey#">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="x-amz-copy-source" value="/#arguments.oldBucketName#/#arguments.oldFileKey#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfreturn true>
<cfelse>
<cfreturn false>
</cfif>
</cffunction>
<cffunction name="renameObject" access="public" output="false" returntype="boolean"
description="Renames an object by copying then deleting original.">
<cfargument name="oldBucketName" type="string" required="yes">
<cfargument name="oldFileKey" type="string" required="yes">
<cfargument name="newBucketName" type="string" required="yes">
<cfargument name="newFileKey" type="string" required="yes">
<cfif compare(arguments.oldBucketName,arguments.newBucketName) or compare(arguments.oldFileKey,arguments.newFileKey)>
<cfset copyObject(arguments.oldBucketName,arguments.oldFileKey,arguments.newBucketName,arguments.newFileKey)>
<cfset deleteObject(arguments.oldBucketName,arguments.oldFileKey)>
<cfreturn true>
<cfelse>
<cfreturn false>
</cfif>
</cffunction>
<cffunction name="objectExists" access="public" output="false" returntype="boolean"
description="Tests if object exists in bucket.">
<cfargument name="bucketName" type="string" required="yes">
<cfargument name="fileKey" type="string" required="yes">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<cfset var result = "">
<cfset var found = 0>
<!--- Create a canonical string to send --->
<cfset cs = "HEAD\n\n\n#dateTimeString#\n/#arguments.bucketName#/#arguments.fileKey#">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- HEAD the object via REST --->
<cfhttp method="HEAD" url="http://s3.amazonaws.com/#arguments.bucketName#/#arguments.fileKey#" result="result">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfswitch expression="#Left(result.statusCode,3)#">
<cfcase value="200">
<cfset found = 1>
</cfcase>
<cfcase value="404">
<cfset found = 0>
</cfcase>
</cfswitch>
<cfreturn found>
</cffunction>
<cffunction name="getBucketVersioning" access="public" output="false" returntype="string"
description="Determines versioning setting for a bucket.">
<cfargument name="bucketName" type="string" required="yes">
<cfset var data = "">
<cfset var result = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send --->
<cfset var cs = "GET\n\n\n#dateTimeString#\n/#arguments.bucketName#?versioning">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<!--- get the bucket via REST --->
<cfhttp method="GET" url="http://s3.amazonaws.com/#arguments.bucketName#?versioning">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
</cfhttp>
<cfset data = xmlParse(cfhttp.FileContent)>
<cftry>
<cfset result = data.VersioningConfiguration.Status.xmlText>
<cfcatch><cfset result = "Disabled"></cfcatch>
</cftry>
<cfreturn result>
</cffunction>
<cffunction name="setBucketVersioning" access="public" output="false" returntype="boolean"
description="Sets versioning on a bucket.">
<cfargument name="bucketName" type="string" required="true">
<cfargument name="versioning" type="string" required="false" default="Enabled">
<cfset var strXML = "">
<cfset var dateTimeString = GetHTTPTimeString(Now())>
<!--- Create a canonical string to send based on operation requested --->
<cfset var cs = "PUT\n\ntext/html\n#dateTimeString#\n/#arguments.bucketName#?versioning">
<!--- Create a proper signature --->
<cfset var signature = createSignature(cs)>
<cfsavecontent variable="strXML">
<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status><cfoutput>#arguments.versioning#</cfoutput></Status></VersioningConfiguration>
</cfsavecontent>
<!--- put the bucket via REST --->
<cfhttp method="PUT" url="http://s3.amazonaws.com/#arguments.bucketName#?versioning" charset="utf-8">
<cfhttpparam type="header" name="Content-Type" value="text/html">
<cfhttpparam type="header" name="Date" value="#dateTimeString#">
<cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
<cfhttpparam type="body" value="#trim(strXML)#">
</cfhttp>
<cfreturn true>
</cffunction>
You are using the old HMAC_SHA1 hashing algoritm. It doesn't work on a newer AWS deployments like Frankfurt or Ireland as they require HMAC-SHA256.
I would suggest to use the AWS SDK for Java instead of reverse engineering it in CFML - it plays quite nicely with Coldfusion: https://aws.amazon.com/sdk-for-java/
Creating an S3 client is as straightforward as:
variables.aws.s3Client = createObject( "java", "com.amazonaws.services.s3.AmazonS3Client" ).init(
createObject("java", "com.amazonaws.auth.BasicAWSCredentials" ).init(
javaCast("string", variables.aws.keyId ),
javaCast("string", variables.aws.secretKey)
)
);

How do I get at join table properties when using ColdFusion ORM?

I have two objects, Person and Family. I use a join table called "join_person_family" to track this many-to-many relationship. The join table has another property called "IS_PRIMARY" that I want to get at and filter when instantiating the person objects with EntityLoadByExample(), but I don't know how to do this with CF ORM. I could do this easily through SQL, but I'm trying to use ORM as much as possible. There may also be another way to track this property, but I can't think of anything. Thanks in advance for any help.
Here is the Family.cfc:
<cfcomponent hint="I am a Family" output="false" persistent="true" extends="_Proxy">
<cfproperty name="FAMILY_ID" hint="FAMILY_ID" type="numeric" ormtype="int" length="11" fieldtype="id" generator="identity" required="true"/>
<cfproperty name="PERSON" hint="PERSON" fieldtype="many-to-many" cfc="person" linktable="join_family_person" FKColumn="FAMILY_ID" inversejoincolumn="PERSON_ID" lazy="true"/>
<cfproperty name="STATUS" type="string" ormtype="string" length="45"/>
<cfproperty name="COMMENT" hint="COMMENT" type="string" length="255"/>
<cffunction name="init" hint="constructor" access="public" returntype="family" output="false">
<cfscript>
return this;
</cfscript>
</cffunction>
</cfcomponent>
Here is the Person.cfc:
<cfcomponent hint="I am a Person" output="false" persistent="true" extends="_Proxy">
<cfproperty name="FAMILY" hint="FAMILY" fieldtype="many-to-many" cfc="family" linktable="join_family_person" FKColumn="PERSON_ID" inversejoincolumn="FAMILY_ID" lazy="true"/>
<cfproperty name="PERSON_ID" hint="PERSON_ID" type="numeric" ormtype="int" length="11" fieldtype="id" generator="identity" required="true"/>
<cfproperty name="USER" hint="USER" fieldtype="one-to-one" cfc="mend_user" FKColumn="USER_ID" lazy="true"/>
<cfproperty name="FIRST_NAME" hint="FIRST_NAME" type="string" length="45"/>
<cfproperty name="LAST_NAME" hint="LAST_NAME" type="string" length="45"/>
<cfproperty name="STATUS" hint="STATUS" type="numeric" ormtype="int"/>
<cffunction name="init" hint="constructor" access="public" returntype="person" output="false">
<cfscript>
return this;
</cfscript>
</cffunction>
Found this response, https://groups.google.com/forum/?hl=en&fromgroups=#!topic/cf-orm-dev/6Fox77MAcbs. After reading that I think that approach is actually superior anyway.
A intermediate entity with many-to-one relationships with the joining objects would allow me to use EntityLoadByExample() to get the relevant person objects filtered by "IS_PRIMARY". Then I could filter the person objects if need be.

Is there any benefit to returning a value from function as opposed to returning void?

I work primarily in ColdFusion, a non-compiled language, but this is a general question for all languages.
I'm creating objects with getters/setters as well as CRUD methods. Here's a sample:
<cffunction name="getPeriodStartDate" output="false" returntype="Numeric">
<cfreturn VARIABLES.PeriodStartDate />
</cffunction>
<cffunction name="setPeriodStartDate" output="false" returntype="Void">
<cfargument name="PeriodStartDate" type="Numeric" required="true" />
<cfset VARIABLES.PeriodStartDate = ARGUMENTS.PeriodStartDate />
</cffunction>
<cffunction name="getDollarAmount" output="false" returntype="Numeric">
<cfreturn VARIABLES.DollarAmount />
</cffunction>
<cffunction name="setDollarAmount" output="false" returntype="Void">
<cfargument name="DollarAmount" type="Numeric" required="true" />
<cfset VARIABLES.DollarAmount = ARGUMENTS.DollarAmount />
</cffunction>
<cffunction name="read" output="false" returntype="Query">
<!---
READ QUERY
--->
<cfreturn _qData />
</cffunction>
<cffunction name="create" output="false" returntype="Void">
<!---
INSERT QUERY
--->
</cffunction>
<cffunction name="update" output="false" returntype="Void">
<!---
UPDATE QUERY
--->
</cffunction>
<cffunction name="delete" output="false" returntype="Void">
<!---
DELETE QUERY
--->
</cffunction>
Obviously the get methods and the read() methods will return a value.
But, is there any benefit to have the other methods return a value - perhaps a Boolean?
I've worked in Flex/ActionScript and remember that in most cases, I needed to return some value from a method and set a variable to that result in order to prevent the next line of code from processing:
function myFunc() {
x = getSomething();
y = getSomethingElse(x);
}
If you return this on your setters, you can chain the setters. I think CF10 accessors return thisto enable chaining by default.
I read that returning void would be more efficient a while back, but I'm not sure if it is true anymore. I doubt the difference would be noticeable.

How to override methods in Coldfusion (adding and changing arguments etc.)?

I have two almost identical Beans.
Bean "Item" contains a unique identifier (primary key), a name and an array that contains structs with data for different Users that are related to the "Item".
Bean "User" contains a unique identifier (primary key), a firstname, a lastname and an array that contains structs with data of different Items that are related to the "User".
Both components contain two methods that write new data to the structs in the array or delete array elements and the setters and getters for the arguments.
The components deviate from each other only through theire argument names, the number of arguments each init method takes and the number of getters and setters.
So i want to create an "Abstract" Bean from which "Item" and "User" inherit. I can do so by using extends in the Beans to get the abstract methods, but how do i override the argument names and variable names. I.e. the argument name ArrayOfData in the AbstractBean does not really tell someone anything. I would like to have ItemHasMaterialsArray and UserHasItemsArray as names in the Item and User beans.
AbstractBean
<cfcomponent name="AbstractBean" output="false">
<cffunction name="init" access="public" hint="constructor" returntype="AbtractBean">
<cfargument name="Identifier" required="false" type="Numeric" default="0">
<cfargument name="Name" required="false" type="String" default="">
<cfargument name="ArrayOfData" required="false" type="Array" default="#arrayNew(1)#">
<cfset variables.instance = structNew() />
<cfset setIdentifier(arguments.identifier) />
<cfset setName(arguments.name) />
<cfset setArrayOfData(arguments.ArrayOfData) />
<cfreturn this />
</cffunction>
<cffunction name="updateArrayOfData" access="public" output="true" returntype="boolean">
<cfargument name="blank" type="Struct" required="true">
<cfset var i = 0 />
<cfset var form = arguments.blank />
<cfset var ArrayOfData = arrayNew(1) />
<cfset ArrayOfData = this.getArrayOfData() />
<cfloop index="i" from="#arrayLen(ArrayOfData)#" to="1" step="-1">
<cfif ArrayOfData[i].Amount neq structFind(form,ArrayOfData[i].Id) and LsIsNumeric(structFind(form,ArrayOfData[i].Id))>
<cfset ArrayOfData[i].Amount = structFind(form,ArrayOfData[i].Id) />
<cfelse>
<cfset arrayDeleteAt(ArrayOfData,i) />
</cfif>
</cfloop>
<cfset setArrayOfData(ArrayOfData) />
<cfreturn true />
</cffunction>
<cffunction name="deleteArrayOfDataElement" access="public" output="false" returntype="boolean">
<cfargument name="blank" type="Struct" required="true">
<cfset var i = 0 />
<cfset var form = arguments.blank />
<cfset var ArrayOfData = arrayNew(1) />
<cfset ArrayOfData = this.getArrayOfData() />
<cfloop index="i" from="#arrayLen(ArrayOfData)#" to="1" step="-1">
<cfif not listFind(form.del,ArrayOfData[i].UserId,',')>
<cfset arrayDeleteAt(ArrayOfData,i) />
</cfif>
</cfloop>
<cfset setArrayOfData(ArrayOfData) />
<cfreturn true />
</cffunction>
<cffunction name="setIdentifier" hint="setter" access="private" output="false" returntype="Void">
<cfargument name="identifier" required="true" type="Numeric" hint="Primary Key, really" />
<cfset variables.instance.Identifier = arguments.Identifier />
</cffunction>
<cffunction name="getIdentifier" hint="getter" access="public" output="false" returntype="Numeric">
<cfreturn variables.instance.identifier />
</cffunction>
<cffunction name="setName" access="private" output="false" returntype="Void">
<cfargument name="name" required="true" type="String" />
<cfset variables.instance.Name = arguments.Name />
</cffunction>
<cffunction name="getName" access="public" output="false" returntype="String">
<cfreturn variables.instance.Name />
</cffunction>
<cffunction name="setArrayOfData" access="private" output="false" returntype="Void">
<cfargument name="ArrayOfData" required="true" type="Array" />
<cfset variables.instance.ArrayOfData = arguments.ArrayOfData />
</cffunction>
<cffunction name="getArrayOfData" access="public" output="false" returntype="Array">
<cfreturn variables.instance.ArrayOfData />
</cffunction>
</cfcomponent>
In my User bean i would like the init method to also take firstname as an argument and override the variable names in my methods. With telling names my other code, i.e. calling the getters, would be much cleaner. User.getUserHasMaterials() reads much better than User.getArrayOfData(), imo. is this even possible? If not than i guess i will have to sacrifice variables readability to avoid duplication.
I think if you're trying to avoid duplication, it might make more sense to use composition rather than inheritance.
It looks like ArrayOfData could be be its own CFC, with methods like update(), delete(), and toArray(). Then you could pass an instance of ArrayOfData to either your User or Item object.
Your User CFC might look something like this:
<cfcomponent name="User">
<cffunction name="init" access="public" hint="constructor" returntype="User">
...
<cfargument
name="materials"
required="false"
type="ArrayOfData"
default="#arrayNew(1)#"
>
...
<cfset variables.materials = createObject("component", "ArrayOfData")>
<cfset setMaterials(arguments.materials)/>
<cfreturn this />
</cffunction>
<cffunction name="setMaterials">
<cfargument name="value" type="Array">
<cfset variables.materials.update(arguments.value)>
</cffunction>
<cffunction name="getMaterials">
<cfreturn variables.materials.toArray()>
</cffunction>
<cffunction name="deleteMaterials">
<cfargument name="blank">
<cfset variables.materials.delete(arguments.blank)>
</cffunction>