Reactor Case Sensitive Gotcha

Word Count: 111

I was getting an error today and I could not figure out why it was happing. First I'll share the error then explain why it was happening.

<cfset session.creditcard = application.reactor.createRecord("creditCard").load(userId=session.advisor.getUserId())>

Message An error occured while Transforming an XML document. Detail Empty expression!

I know others have posted about this but I just want to let others out there know about it. When you are creating your records and gateways make sure you are aware that it is case sensitive so creditCard and CreditCard is the difference between working and an error being thrown!

Reactor field tag

Word Count: 446

I have noticed that not a lot of people either disregard or do not really know what the field tag is used for. Most of the information below is from the live docs so be sure to review the documentation by clicking on the link below. The field tag is used inside of an &ls;object> definition and is used to define the details of a specific field in your database object. The field tag has three attributes name, alias, and sequence. The name attribute is required and it is the name of the field in the database. The field tag is used to assign an alias to a field, if it is not provided the name of the database field is used. Finally the sequence attribute is not required. On a database that uses sequences instead of identity or auto increment columns the field tag can also be used to specify the sequence to get new value from when writing records into the database. Let’s go ahead and look at an example of where we would use the field tag. First is the sql script that generates the database table.

CREATE TABLE [dbo].[struser] (
   [userId] [int] NOT NULL ,
   [str_first_name] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [str_last_name] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [str_username] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [str_password] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

Now let’s look at why we use the field tag. You will notice that this table we are working with has some hard to work with column names. If you want throughout your code you could use your getters and setters typing those names every time but their really is an easier way to do it. Would you rather type getStr_first_name() or getFirstName(). The latter looks a lot easier to me, how about you? This is where the almighty alias attribute comes into play.

<object name="struser" alias="user">
         <field name="str_first_name" alias="FirstName"/>
         <field name="str_last_name" alias="LastName"/>
         <field name="str_username" alias="Username"/>
         <field name="str_password" alias="Password"/>
</object>

Reactor livedocs

Reactor save() & transaction gotcha

Word Count: 311

So today I came across a problem that the fine folks on the reactor list server help me solve. I wanted to run a transaction on multiple object so that if any of them failed I could back out. Here is a quick example of what I was trying to do.

<cftransaction action="BEGIN">

   <cfset contactRecord = application.reactor.createRecord("contact")/>
   <cfset contactRecord.setContactId(form.contactId)>
   <cfset contactRecord.setFname(form.fname)>
   <cfset contactRecord.setLname(form.lname)>
   
   <cfset contactRecord.validate() />
   <cfset errorCollection = contactRecord._getErrorCollection() />
   <cfset contactRecord.save()>
   
   <cfset userRecord = application.reactor.createRecord("user")/>
   <cfset userRecord.setuserId(form.userId)>
   <cfset userRecord.setUsername(form.username)>
   <cfset userRecord.setPassword(form.password)>
   
   <cfset userRecord.validate() />
   <cfset errorCollection = userRecord._getErrorCollection() />
   <cfset contactRecord.save()>
   
   <cfif ErrorCollection.hasErrors()>
      <cftransaction action="ROLLBACK"/>
   <cfelse>   
      <cfset contactRecord.save()>
      <cftransaction action="COMMIT"/>
      <cflocation URL="contacts.cfm" addtoken="false"/>
   </cfif>
   
</cftransaction>

The problem with this code is that it was throwing a transaction nested exception error. You can not place cftransaction tags inside themselves. I couldnt figure out why that was until I dug into the abstractRecord.cfc and found this.

<cffunction name="save" access="public" hint="I save the record." output="false" returntype="void">
      <cfargument name="useTransaction" hint="I indicate if this save should be executed within a transaction." required="no" type="boolean" default="true" />
      
      <cfif arguments.useTransaction>
         <cfset saveInTransaction() />
      <cfelse>
         <cfset executeSave() />
      </cfif>
      
   </cffunction>   
   
   <!--- saveInTransaction --->
   <cffunction name="saveInTransaction" access="private" hint="I save the record in a transaction." output="false" returntype="void">
      <cftransaction>
         <cfset executeSave() />
      </cftransaction>
   </cffunction>

It now made perfect sense why this was happening. If you would like to tell reactor not to execute a save in a transaction simply pass false when calling the save method, the default value for this is true.

<cfset contactRecord.save(false)>

Reactor Validation Part III

Word Count: 89

In the final installment of our mini series we are getting down and dirty with custom validation. We learned in part II how basic validation is done. If you were to launch our application, go to add contact, and submit the form without entering any data you should see the following errors.

  • The fname field is required but was not provided
  • The lname field is required but was not provided
  • The emailaddress field is required but was not provided

[More]

Reactor Validation Part II

Word Count: 90

In our last tutorial in this series we setup our ReactorValidation application. In part II we will dig deeper and begin to learn how reactor validation works. We are going to add the following code to the top of our editContact.cfm file. This piece of code will handle form submission, validate, and redirect if save is successful. First view the entire code and then we will break it down further. You can download the updated files by clicking the download link below.

<cfif structKeyExists(form,"submit")>

   <cfset contactRecord = application.reactor.createRecord("contact")/>
   <cfset contactRecord.setContactId(form.contactId)>

   <cfset contactRecord.setFname(form.fname)>
   <cfset contactRecord.setLname(form.lname)>
   <cfset contactRecord.setAddress(form.address)>
   <cfset contactRecord.setCity(form.city)>
   <cfset contactRecord.setState(form.state)>
   <cfset contactRecord.setZip(form.zip)>
   <cfset contactRecord.setPhone(form.phone)>
   <cfset contactRecord.setFax(form.fax)>
   <cfset contactRecord.setEmailAddress(form.emailaddress)>
   <cfset contactRecord.setWebsite(form.website)>
   
   <!--- validate the contact --->
   <cfset contactRecord.validate() />
   <cfset errorCollection = contactRecord._getErrorCollection() />
   
   <cfif NOT ErrorCollection.hasErrors()>
      <!--- save the contact and redirect to their view --->
      <cfset contactRecord.save()>
      <cflocation URL="index.cfm" addtoken="false"/>
   </cfif>

</cfif>

[More]

Reactor Validation Part I

Word Count: 492

This mini series of a tutorial is intended to help you understand Reactor Validation a little better. This tutorial also expects you to already have some basic knowledge of Reactor and to have it up and running. One of the first major problems I ran into using reactor was validation. I am going to walk you through how you can validate data when creating or updating an object record. I will also walk you through what happens during validation process, in other words how does it actually work. Finally we will walk through how to create your own custom validation methods by extending the base validation object. After the tutorial is over you can download all of the example code as well as a SQL server script (sorry, that is all I have for now). I know some of you may not agree with some of coding methods here but I am throwing this together fast so please forgive me, or leave me a comment and yell at me, haha!

The first thing we are going to do is setup our example application; I am giving it an application name of ReactorValidation, but you can name it whatever. I am also go to set create the reactorFactory object and set it in the application scope. Our example application is going to be a basic contact manager and I am going to provide a list view, add, and edit methods for a contact. Please make sure the admi api or rds password is set below if you do not have a mapping setup. Ok, so onto the code, below is our Application.cfc file.

<cfcomponent name="Application">

   <cfscript>
      this.name = "ReactorValidation";
      this.applicationTimeout = createTimeSpan(0,2,0,0);
      this.loginStorage = "session";
      this.sessionManagement = "true";
      this.sessionTimeout = createTimeSpan(0,0,30,0);
   </cfscript>

   <cffunction name="onApplicationStart" returntype="boolean" access="public">
   <cftry>   
      <cfset application.reactor = createObject("component","reactor.reactorFactory").init(expandPath("reactor.xml"))>
      <cfcatch type="reactor.Invalidmapping">
      <cfdirectory action="create" directory="#expandPath('.')#\rvdata">
         
         <cfscript>
         // Login is always required.          adminObj = createObject("component","cfide.adminapi.administrator");
         adminObj.login("password");
         
         extensionsObj = createObject("component","cfide.adminapi.extensions");
         extensionsObj.setMapping("/rvdata","#expandPath('.')#\rvdata");
         </cfscript>
      </cfcatch>
   </cftry>   
   <cfreturn true>
   </cffunction>

   <cffunction name="onApplicationEnd" returnType="void" output="false">
      <cfargument name="applicationScope" required="true">
   </cffunction>

   <cffunction name="onRequestStart" returntype="boolean" access="public">
      <cfif NOT structKeyExists(application,"reactor") OR structKeyExists(url,"reinit")>
         <cfset onApplicationStart()>
      </cfif>
      <cfreturn true>
   </cffunction>
   
   <cffunction name="onRequest" returnType="void">
      <cfargument name="thePage" type="string" required="true">
      <cfinclude template="#arguments.thePage#">      
   </cffunction>

   <cffunction name="onRequestEnd" returnType="void" output="false">
      <cfargument name="thePage" type="string" required="true">
   </cffunction>
   
   <cffunction name="onSessionStart" returntype="void" output="false">
   
   </cffunction>
   
   <cffunction name="onSessionEnd" returnType="void" output="false">
      <cfargument name="sessionScope" type="struct" required="true">
      <cfargument name="appScope" type="struct" required="false">
   </cffunction>
   
</cfcomponent>

[More]

Copyright © 2007 Dan Vega | BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.