coldfusion cfinsert fails, how to submit a query with optional fields - sql

I have this insert tag:
<cfquery name="aoi_results" datasource="buyerhero" >
INSERT INTO polygons(tract, user, name, type, center, radius, north, south, east, west, verticies)
VALUES('#url.tract#', '#url.user#', '#url.name#', '#url.type#','#url.center#', '#url.radius#', '#url.north#', '#url.south#', '#url.east#', '#url.west#', '#url.verticies#');
</cfquery>
for this query, not all fields are used. some records have center and radius, others have north, south, east, and west, and others have verticies. any field not used is null.
How do I write the statement so each field after type is optional?
Thanks

You can use cfparam to default your url params to blank if they're not passed in. Then, in your query you can use the null attribute of cfqueryparam. The null attribute is a boolean, if true, it will pass in null.
<cfparam name="URL.tract" default="" />
<cfparam name="URL.user" default="" />
<cfparam name="URL.name" default="" />
<cfparam name="URL.type" default="" />
<cfparam name="URL.center" default="" />
<cfparam name="URL.radius" default="" />
<cfparam name="URL.north" default="" />
<cfparam name="URL.south" default="" />
<cfparam name="URL.east" default="" />
<cfparam name="URL.west" default="" />
<cfparam name="URL.verticies" default="" />
<cfquery name="aoi_results" datasource="buyerhero" >
INSERT INTO polygons(tract, user, name, type, center, radius, north, south, east, west, verticies)
VALUES(
<cfqueryparam value="#URL.tract#" cfsqltype="cf_sql_integer" />
,<cfqueryparam value="#URL.user#" cfsqltype="cf_sql_varchar" />
,<cfqueryparam value="#URL.name#" cfsqltype="cf_sql_varchar" />
,<cfqueryparam value="#URL.type#" cfsqltype="cf_sql_integer" />
,<cfqueryparam value="#URL.center#" cfsqltype="cf_sql_float" null="#len(URL.center) EQ 0#" />
,<cfqueryparam value="#URL.radius#" cfsqltype="cf_sql_float" null="#len(URL.radius) EQ 0#" />
,<cfqueryparam value="#URL.north#" cfsqltype="cf_sql_float" null="#len(URL.north) EQ 0#" />
,<cfqueryparam value="#URL.south#" cfsqltype="cf_sql_float" null="#len(URL.south) EQ 0#" />
,<cfqueryparam value="#URL.east#" cfsqltype="cf_sql_float" null="#len(URL.east) EQ 0#" />
,<cfqueryparam value="#URL.west#" cfsqltype="cf_sql_float" null="#len(URL.west) EQ 0#" />
,<cfqueryparam value="#URL.verticies#" cfsqltype="cf_sql_float" null="#len(URL.verticies) EQ 0#" />
);
</cfquery>
I guessed on the cfsqltype, you'll have to verify those yourself. The null attribute will set the column to null if the len() is 0, and all URL parameters are defaulted to blank using cfparam
Most importantly, you should always use cfqueryparam. Passing URL variables into a query is just asking to be hacked with a SQL injection attack. Read the query param section on learncfinaweek for some more information on this.

Related

azure-ad-b2c - How to check if email and phone number match an existing user

Before allowing the user to change their password, I'm trying to validate if their email and phone match an existing one in Azure B2C. If I remove the phone # and validate the email only it's all good, but if I try to validate the phone number with the email, I get the "specified credential could not be found" error.
I was wondering if someone could help me.
Here are my custom policies to verify it:
<TechnicalProfile Id="AAD-UserReadUsingEmailAddressAndPhoneNo">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
<InputClaim ClaimTypeReferenceId="signInNames.phoneNumber" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="accountEnabled" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<ClaimType Id="signInNames.phoneNumber">
<DisplayName>+1XXX</DisplayName>
<DataType>phoneNumber</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OpenIdConnect" PartnerClaimType="phone_number" />
</DefaultPartnerClaimTypes>
<UserHelpText>Phone Number that can be used to contact you.</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress_Custom">
<DisplayName>Reset password using email address</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddressAndPhoneNo" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
You might want to verify that the phone number is being stored as signInNames.phoneNumber, instead of one of the other phone number types (like strongAuthenticationPhoneNumber). I know it sounds obvious, but sometimes it happens.
It might also help to break the check up into multiple parts. First check the email address and get the users phone number using UserReadUsingEmailAddress (or some variation of it), then use a second VTP to assert that the phone number you pulled from the account and the phone number the user typed in match.

Extract multiple date strings from a single varchar(MAX) column SQL Server

I've inherited a report spec subsystem that needs to be tweaked. The mission is to add a date column to the tReports table, and populate it with the CreateDate that is (supposed to be) contained in the XML Code Spec. The problem is that some of the older reports don't have the CREATEDATE attribute, or as in one example below, the XML is valid but poorly formed, and the CREATEDATE cannot be retrieved using the xQuery that works for most of the other reports. Since I don't have an explicit creation date included in the spec, I'm using interpolation to estimate a reasonable date. One factor of the interpolation is to look at the date strings contained in the report spec--some will be useful, others not.
There are too many reports (over 1,200) to visually skim each report spec for date strings. These date strings can appear in any location in the report spec, and there are a very large number of combinations of elements and attributes that can contain a date string.
The ideal solution would be a listing of the reportID's and the date string ready to use in an UPDATE, but because date format varies (m/d/yy, mm/dd/yy, m/dd/yy ...) I'd be grateful to get a vew spurious characters surrounding the date string that I could clean up later.
All the date strings will be from 2000 or later, so the search string I'v been using is '/20' which has provided good results.
I've looked at many sites that discuss this kind of issue, and found only one solution by Mikael Eriksson that is something like what I'm describing, but I can't make it work after several hours of playing with it. How to extract multiple strings from single rows in SQL Server
Is there a way, without using a cursor nor WHILE loop, to extract these embedded dates?
-- Some representative data: (I'm using SQL Server 2008 R2)
CREATE TABLE #ReportSpecs (ReportID INT, ReportSpec VARCHAR(MAX))
INSERT INTO #ReportSpecs
( ReportID, ReportSpec )
VALUES
(136,
'<ReportID>136</ReportID>
<EmpIDCreator>23816</EmpIDCreator>
<EmpName>Blanc, Melvin J</EmpName>
<ReportType>0</ReportType>
<ReportName>PSST Sys Spec</ReportName>
<ReportData>
<REPORT>
<COLUMNS>
<Column Name="JobNumber" Position="1" />
<Column Name="TaskType" Position="2" />
<Column Name="Assignees" Position="3" />
<Column NAME="JobDueDate" Position="4" />
<Column Name="ReferenceNumber" Position="5" />
<Column Name="Deliverable" Position="6" />
<Column Name="Priority" Position="7" />
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="To_Me" />
<FILTER NAME="Status" VALUE="All" />
<FILTER NAME="DateOptions" VALUE="DateRange" From="8/16/2002" To="8/23/2002" />
<FILTER NAME="FromDate" VALUE="8/16/2002" />
<FILTER NAME="ToDate" VALUE="8/23/2002" />
<FILTER NAME="Role" VALUE="All" />
</FILTERS>
<parameters>
<PARAMETER NAME="#Cascading" TYPE="integer" VALUE="0" />
<PARAMETER NAME="#EmpID" SYSTEM="true" TYPE="integer" VALUE="#Request.EmployeeIDAlias#" />
<PARAMETER NAME="#FromOrgs" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#ToOrgs" TYPE="varchar(250)" VALUE="" />
</parameters>
<NAME>PSST Sys Spec</NAME>
<OWNER>
<ID>23816</ID>
</OWNER>
<source id="8" useinternalid="True" />
</REPORT>
</ReportData>'),
(311,
'<ReportID>311</ReportID>
<EmpIDCreator>7162</EmpIDCreator>
<EmpName>Potter, Harry J</EmpName>
<ReportType>0</ReportType>
<ReportName>CPVC Synch Test</ReportName>
<ReportData>
<REPORT>
<COLUMNS>
<Column Name="JobNumber" Position="1" />
<Column Name="TaskType" Position="2" />
<Column Name="Subject" Position="3" />
<Column Name="CurrentAssignee" Position="4" />
<Column NAME="JobDueDate" Position="5" />
<Column Name="Deliverable" Position="6" />
<Column Name="Category" Position="7" />
<Column Name="Priority" Position="8" />
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="By_Orgs_6098,By_Orgs_6123" />
<FILTER NAME="Status" VALUE="Open" />
<FILTER NAME="DateOptions" VALUE="DateRange" From="3/25/2002" To="4/4/2002" />
<FILTER NAME="ReviewFromDate" VALUE="3/25/2002" />
<FILTER NAME="ReviewToDate" VALUE="4/4/2002" />
<FILTER NAME="Role" VALUE="All" />
</FILTERS>
<parameters>
<PARAMETER NAME="#Act" TYPE="integer" VALUE="0" />
<PARAMETER NAME="#MgrID" SYSTEM="true" TYPE="integer" VALUE="#Request.EmployeeIDAlias#" />
<PARAMETER NAME="#MgrIDActing" TYPE="integer" VALUE="" />
<PARAMETER NAME="#FromDept" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#FromEmp" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#ToDept" TYPE="varchar(250)" VALUE="" />
</parameters>
<NAME>CPVC Synch Test</NAME>
<OWNER>
<ID>7162</ID>
</OWNER>
<source id="17" useinternalid="True" />
</REPORT>
</ReportData>'),
(1131,
'<ReportID>1131</ReportID>
<EmpIDCreator>13185</EmpIDCreator>
<EmpName>Reed, Alan</EmpName>
<ReportType>0</ReportType>
<ReportName>
''"><script>alert(''hello'')</script>
</ReportName>
<ReportData>
<Report NAME="''">
<script>alert(''hello'')</script>" CREATEDATE="12/7/2009">
<DESCRIPTION>sfasf</DESCRIPTION>
<OWNER ID="13185"/>
<SOURCE ID="1" USEINTERNALID="TRUE"/>
<COLUMNS>
<COLUMN NAME="JobNumber" POSITION="1" SORTORDER="asc"/>
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="By_Me,To_Me" />
<FILTER NAME="ASGSTATUS" VALUE="Open" />
<FILTER NAME="DATEOPTIONS" VALUE="All" />
<FILTER NAME="STATUS" VALUE="Open" />
<FILTER NAME="ASGDATEOPTIONS" VALUE="All" />
<FILTER NAME="ROLE" VALUE="All" />
</FILTERS>
<PARAMETERS>
<PARAMETER NAME="#Me" TYPE="integer" VALUE="3" />
<PARAMETER NAME="#FromCost" TYPE="varchar(250)" VALUE=""/>
<PARAMETER NAME="#ToCost" TYPE="varchar(250)" VALUE="" />
</PARAMETERS>
<ADVANCEDSORT SortByA="JobNumber" SortOrderA="asc" SortByB="" SortOrderB="" SortByC="" SortOrderC="" />
</Report>
</ReportData>');
/*
Desired Output (A DISTINCT list would be better, but just getting this output would be GREAT.)
ReportID DateString
-------- ----------
136 8/16/2002
136 8/23/2002
136 8/16/2002
136 8/23/2002
311 3/25/2002
311 4/4/2002
311 3/25/2002
311 4/4/2002
1131 12/7/2009
*/
DROP TABLE #ReportSpecs
Thanks for your time.
select R.ReportID,
D.V as DateString
from #ReportSpecs as R
cross apply (select cast(R.ReportSpec as xml)) as X(R)
cross apply X.R.nodes('//#*, //*/text()') as T(X)
cross apply (select T.X.value('.', 'varchar(max)')) as D(V)
where charindex('/20', D.V) > 0
Result:
ReportID DateString
----------- --------------------------
136 8/16/2002
136 8/23/2002
136 8/16/2002
136 8/23/2002
311 3/25/2002
311 4/4/2002
311 3/25/2002
311 4/4/2002
1131 " CREATEDATE="12/7/2009">

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>