Categories
Contact Doug!
Learn About Doug!
View Doug Boude's online resume
updated 11/18/2009

View Doug Boude's profile on LinkedIn
Link to me!

Follow Doug Boude on Twitter
Follow me!

Be Doug's friend on Facebook
Befriend me!
(I promise not to follow you home)
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...
Web Hosting

<< May, 2007 >>
SMTWTFS
12345
6789101112
13141516171819
20212223242526
2728293031
Search Blog

Recent Comments
Re: Disappearing IE Popup Window During Save/Open Dialog (by LZ at 4/20 7:58 AM)
Re: Create Dynamic WHERE Clauses in PHP (by pooja at 3/20 7:29 AM)
Re: Just What IS a 'Service Layer', Anyway? (by EugenK at 3/07 7:56 PM)
Re: Using Google as your CF Mail Server (by 5starwebteam.com at 2/25 1:27 AM)
Re: Why Provide for Service layer objects in CFWheels? (by Steven Benjamin at 1/25 11:43 AM)
Re: What is an 'Advanced' Coldfusion Developer? (by ColdFusion Developer at 12/24 5:14 AM)
Re: Equivalent of SQL "TOP X" in Oracle (by Ashenafi Desalegn at 12/06 5:29 AM)
Re: PHP Export to Excel Snippet (by serene at 12/05 1:44 AM)
Re: Just What Is 'Application Logic', Anyway? (by Arif at 11/13 8:06 AM)
Re: Hosts File Changes Not Acknowledged on Vista 64 (by Aaron at 10/22 2:31 PM)
Re: PHP Export to Excel Snippet (by Jafar Shah at 10/10 4:28 AM)
Re: Viewing Option Text (in IE7) that's Wider than the Select List (by Chenelle S at 10/04 12:53 PM)
Re: PHP Export to Excel Snippet (by Kilo at 9/26 5:20 PM)
Re: Porting Coldfusion Code to Mura (by tariq at 9/03 9:51 AM)
Re: Just What IS a 'Service Layer', Anyway? (by James at 8/27 4:06 PM)
Re: Calculating Business Hours (by helen at 8/14 2:54 AM)
Re: What IS 'Business Logic', Anyway? (by dougboude at 8/06 11:30 AM)
Re: What IS 'Business Logic', Anyway? (by Adrianne at 8/06 10:29 AM)
Re: Family Law: The Weapon of Choice for Woman Scorned (by dougboude at 8/04 4:39 PM)
Re: Family Law: The Weapon of Choice for Woman Scorned (by Lola LB at 8/04 7:43 AM)
Archives
Photo Albums
Funnies (5)
Family (3)
RSS

Powered by
BlogCFM v1.11

31 May 2007
My Grandpa

My mind swam as I drove the thirty minutes to the hospital, my thoughts wandering back and forth between the cares of my day and my love and concern for my grandpa. I had just walked in from a pleasant lunch with one of my fellow Masons when the front desk lady flagged me down and handed me a scribbled note that read “grandpa – hospital – emergency – call mom”. Sometimes I really despise the way I always analyze things. Rather than allowing the naturally occurring emotions of such a surprise scenario to run their course, I immediately and instinctively subdued them, opting rather to convince myself that there was no cause for alarm or concern at this point since I had no real information upon which to base a judgment. But c’mon…with keywords such as those scrawled on that yellow piece of paper, how many conclusions could there be that don’t end in a situation where emotions are absolutely appropriate? I do believe that it’s more from fear than strength that I do that to myself…that I throw logic at myself in order to postpone the inevitable. Others look at me and see me as the strong one, the reasonable one, the one who is really able to think clearly and rationally. In reality, I am the one most afraid, and only do it as a self-protective measure. I tend to equate crying with vomiting…both are natural and healing reactions that our humanity thrust upon us when necessary, yet I find myself going to the greatest of lengths to utterly avoid them at all costs. I believe it’s because both of them are involuntary, and nothing frightens me more than not being in control of my situation. Well there, I’ve done it. I’ve just auto-analyzed my own psychology in a public forum. But I don’t care. I’m only writing about this in order to provide some sort of relief for myself, a vent for the anguish I kept bottled up as I helped my grandpa…no, suffered with my grandpa, through the stroke he had had that very morning.

 

I love that man, so very, very much. One of my greatest regrets is that I never put forth the effort to get to know him better in my younger years. He was always traveling here and there with my grandma, living what I envisioned as a very exciting and lavish life. Their home base was Texas, mine was Missouri. I married right out of high school and immediately had my life swept up with responsibilities I was trying to grow into. Our paths crossed only on occasion over the course of thirty years, and even when it was that I eventually ended up living in the same city as he and grandma, I still never seemed to find time in my schedule to invest in our relationship. How sad. What a rich and meaningful relationship I robbed myself and my children of by not being more determined in that.

 

In the past year, I had finally made up my mind to turn over a new leaf in that department, and I embarked upon an endeavor that gave grandpa and I some common ground: Masonry. I didn’t do it just for him, but I was glad that we now had something to ensure we would spend time together. Entering into Masonry necessarily involves the requirement of spending one on one time with other more experienced Masons, and whenever possible, I chose my grandpa. In what Masons refer to as esoteric work, I began to finally get to know who my grandpa was. How smart he was, how even tempered; his wit, his sincere care for his wife, myself, and family (even those of the feline persuasion). He wears his 84 years as though he were just barely entering retirement age, always smiling, laughing, helping with something.

When I finally completed my brisk walk of the hospital’s length (I parked at the wrong end of the facility…fancy that) and entered the room where they were still examining him, it was a completely foreign way to be seeing my grandpa. Whereas he was always the active one, the one helping somebody else, now it was his turn to receive the attention and assistance. And oh, how it grieved him so! I saw my beloved, strong grandpa weep multiple times that day. Not out of self-pity, but for the worry that others had over him and the time they were taking out of their own schedules for his sake. When he cried, I would be strong for him, put my hand on his shoulder, smile at him so he could see that I was there to fill in for whatever strength the stroke had temporarily taken away. My mind was set, and I told him so, that we would all overcome this together and press on as the happy loving family that we were no matter what it might require of us all. I was so glad for my own youth and strength and health so that I could lend it to him, that my abundance could be supply for his lack at that time, as his has been for me in past situations.

 

My grandma…she who is always so beautiful and elegant and graceful in every way; she really rose to the occasion as well, impressing me mightily. The love I always knew was there between them was more evident now than ever, as she tirelessly held his hand from her wheelchair, looked at him so lovingly and dear, smiled at him, and kept him energized by her amazing love for him. He reciprocated, and though few words were spoken between them, the air between their mutual gazes was alive. Her stamina, which normally is quite short due to her progressing Parkinsons, was as good or better than my own; her speech, which is normally not more than a whisper (again, due to her Parkinsons) was quite audible and clear. Though my grandpa may not see it right now, his unfortunate illness has brought out so much good and strength in everyone around him…his weakness, his lacking, has given those around him who love him so such a blessed opportunity to give back…there honestly can be so much beauty in tragedy, such that the tragic event itself is paled in comparison and appears as nothing more than an insignificant thing that should soon be forgotten.

 

This is the second day since my grandpa realized he was having a stroke when he couldn’t lift his spoon of cereal to his mouth, but the sadness that plagued him yesterday has been set aside, and he even walked a couple hundred feet today down the hall of the hospital wing. Tomorrow my mom and Aunt will arrive to see their father and perform the happy duty of a child to their aging parents, and I am excited to see them as well. I was my mother’s eyes, ears, voice, and arms while she couldn’t be here, and I feel very privileged to have fulfilled that role for her. I’m glad I was here when my grandpa got sick, and I will continue to offer myself to them all for the love I have for them, most especially grandpa.

 

There is nothing more beautiful, satisfying, nor purposeful than to give yourself for the sake of another. May I encourage everyone who reads this to consider those who are nearest and dearest to them, and even those who aren’t but should be, and take advantage of the precious moments you have so that when all is said and done (and it will eventually be), you will have no regrets.

Posted by dougboude at 1:29 AM | PRINT THIS POST! | Link | 2 comments



25 May 2007
Custom Validation with Generic Commit: a Model-Glue Case Study
Someone recently asked about how to specifically ensure that a submitted email address is unique when using a model-glue generic commit, so I thought I'd share an example since I recently had to do that very thing.

I'm assuming for the remainder of this post that the reader is already familiar with Model-Glue in a practical sense, and at least knows of the existence of Reactor's automagic validation. Still, I'll try not to leave out too many relevant details.

Okay, the scenario:

I have a secured app, and I want to give new users the opportunity to sign up for an account. I'm using email address as the user name since in theory it should always be unique to an individual. (note: I opted NOT to set up my user table so that the email address field has a unique index on it) So, the user clicks "Sign me up!", I present them with a form to fill out, one field being their email address. They submit the form, and here's where we dive down under the waves to see what's happening...


The form submits to the event "inspector.create", which in the modelglue.xml file reads as follows:
<event-handler name="inspector.create">
    <broadcasts>
        <message name="ModelGlue.genericCommit">
            <argument name="recordName" value="UserRecord" />
            <argument name="criteria" value="" />
            <argument name="object" value="User" />
            <argument name="validationName" value="UserValidation" />
        </message>
    </broadcasts>
    <views></views>
    <results>
        <result name="commit" do="inspector.newuser" redirect="true" append="email" preserveState="false" />
        <result name="validationError" do="inspector.signup" redirect="false" append="" preserveState="true" />
    </results>
</event-handler>

Notice we're using a generic commit to handle this, which works because all of the needed data resides within form fields that are named exactly as their database field counterparts (eg; in my table there's a field called 'email', in my form there's a form field named 'email', etc.).
Now, the fact that we have specified an argument named "validationName" in our generic commit means that before the form data is committed to the database, Reactor is going to invoke the aid of one of the CFCs it auto-generated for us in order to "validate" the info submitted. By default, validation consists of checks that were created based on your table's metadata (unique indexes, datatypes, null not allowed, etc.), but Reactor was kind enough to provide us a convenient place to extend and customize that default validation if we so desire. In my scenario, since I did NOT choose to put a rule in place specifying that my email field should be unique, I added a custom method to perform that check.

To locate the CFC for adding custom validation, look in \model\data\reactor\Validator\, and find the cfc named after your target table. In my case, it's UserValidator.cfc

By default, the guts of the Validator CFCs you'll be working with look similar to the following:

<cfcomponent hint="I am the validator object for the Section object.  I am generated, but not overwritten if I exist.  You are safe to edit me."
    extends="reactor.project.myprojectname.Validator.SectionValidator">
    <!--- Place custom code here, it will not be overwritten --->
</cfcomponent>

I decided to add two more methods of validation to my user object:
  1. make sure they typed their password in twice the same way,
  2. and make sure their email isn't already used in the system
Ah, but when you look at the content of my CFC, you'll see there are THREE methods present, and NOT just two. Take a gander:

<cfcomponent hint="I am the validator object for the User object.  I am generated, but not overwritten if I exist.  You are safe to edit me."
    extends="reactor.project.myprojectname.Validator.UserValidator">

    <CFFUNCTION name="validate" access="public" hint="I validate an  record" output="false" returntype="any" _returntype="reactor.util.ErrorCollection">
        <cfargument name="UserRecord" hint="I am the Record to validate." required="no" type="any" _type="reactor.project.housefacks.Record.UserRecord" />
        <cfargument name="ErrorCollection" hint="I am the error collection to populate. If not provided a new collection is created." required="no" type="any" _type="reactor.util.ErrorCollection" default="#createErrorCollection(arguments.UserRecord._getDictionary())#" />
        <CFSET validatePasswordVals(arguments.UserRecord, arguments.ErrorCollection) />
        <CFSET validateEmail(arguments.UserRecord, arguments.ErrorCollection) />
        <CFSET super.validate(arguments.UserRecord, arguments.ErrorCollection) />
        <CFRETURN arguments.ErrorCollection />
    </CFFUNCTION>
   
    <CFFUNCTION name="validatePasswordVals" access="public"  output="false" returntype="reactor.util.ErrorCollection">
        <CFARGUMENT name="UserRecord" hint="I am the Record to validate." required="no" type="reactor.project.myprojectname.Record.UserRecord" />
        <CFARGUMENT name="ErrorCollection" hint="I am the error collection to populate. If not provided a new collection is created." required="no" type="reactor.util.ErrorCollection" default="#createErrorCollection(arguments.UserRecord._getDictionary())#" />
        <!--Blue is only allowed as a selection for Sky for people  whose weathercode = 5-->
        <CFIF  arguments.UserRecord.getPassword() is not arguments.UserRecord.getConfirmPassword() >
            <CFSET arguments.ErrorCollection.addError("user.password.notconfirmed") />
        </CFIF>
        <CFRETURN arguments.ErrorCollection />
    </CFFUNCTION>
   
    <CFFUNCTION name="validateEmail" access="public"  output="false" returntype="reactor.util.ErrorCollection">
        <CFARGUMENT name="UserRecord" hint="I am the Record to validate." required="no" type="reactor.project.myprojectname.Record.UserRecord" />
        <CFARGUMENT name="ErrorCollection" hint="I am the error collection to populate. If not provided a new collection is created." required="no" type="reactor.util.ErrorCollection" default="#createErrorCollection(arguments.UserRecord._getDictionary())#" />
        <cfset var userGateway = "" />
        <CFIF  arguments.UserRecord.getEmail() is not "" >
            <cfset userGateway = reactorfactory.createGateway("user").getByFields(email=arguments.UserRecord.getEmail()) />
            <cfif userGateway.recordcount IS NOT 0>
                <CFSET arguments.ErrorCollection.addError("user.email.alreadyexists") />
            </cfif>
        </CFIF>
        <CFRETURN arguments.ErrorCollection />
    </CFFUNCTION>
</cfcomponent>


The method present here that you may not have anticipated is called "validate", and is the exact same name as the method you would find in Reactor's core user validation object. So, what have we in effect done, boys and girls? That's right! We have (choose your favorite word, they both mean the same thing) overloaded/overriden the main "validate" method, in order to ensure that not only the original, auto-generated validation methods get called, but also the two new ones we added after the fact.

Let's take a closer look at our version of the "validate" method (this will only take a second, there are a couple of important things to note in there).

First off, you'll note that every validation method requires two arguments: an incoming record whose values are being validated, and the errorcollection where we (dang, this makes too much sense!) collect our errors.
Second, notice that we are FIRST executing our custom validation methods, then afterwards executing the auto-generated "validate" method by calling the object we extended, directly, via a call to "SUPER". Very cool, eh? Even though we initially overloaded our validate method in order to ensure that it got called rather than the core version of it, we were STILL able to call the original version as well. (By the way, that is a little trick I learned from Doug Sims' blog www.evenamonkey.com).

Alright then, we have submitted our form, used generic commit to perform validation, that validation called our extended object, executed the local custom methods first, then the system validate method. If any errors were encountered, our generic commit would have added a result named "ValidationError" to the event bucket (see the modelglue.xml snippet above), thus redirecting us back to the original page (where we have code in place looking for the presence of the error collection). If no errors were encountered, we're directed forward to the next event in the chain, and all is well.


One Mo Thang

Ah, one last thing that is of great importance to be aware of regarding Reactor validation: The Dictionary. The dictionary is an xml file that is specific to a validation object. In our example, since we have a userValidator object, there also exists a \model\data\reactor\Dictionary\userdictionary.xml file. This file is used to look up and translate any errors encountered so that the user is presented with readable text rather than a cryptic message. When you add custom validation methods, you also need to add dictionary entries. Consider the following snippet from my userdictionary.xml file:
<?xml version="1.0" encoding="UTF-8"?>
    <User>
        <email>
            <label>email</label>
            <comment/>
            <maxlength>100</maxlength>
            <scale>0</scale>
            <invalidType>The email field does not contain valid data.  This field must be a string value.</invalidType>
            <invalidLength>The email field is too long.  This field must be no more than 100 bytes long.</invalidLength>
            <notProvided>The email field is required but was not provided.</notProvided>
            <alreadyexists>That email address is already being used. Please select another email address. If you have forgotten your password, return to the main login screen and select "Forgot Password"</alreadyexists>
        </email>
        <password>
            <label>password</label>
            <comment/>
            <maxlength>50</maxlength>
            <scale>0</scale>
            <invalidType>The password field does not contain valid data.  This field must be a string value.</invalidType>
            <invalidLength>The password field is too long.  This field must be no more than 50 bytes long.</invalidLength>
            <notProvided>The password field is required but was not provided.</notProvided>
            <notconfirmed>The password you typed in is not the same as the "confirm password" value.</notconfirmed>
        </password>
    </User>

Look back at the custom method "validateEmail" we added earlier, and notice that if our validation fails, we're adding an error that looks like

<CFSET arguments.ErrorCollection.addError("user.email.alreadyexists") />


The syntax of that message is no coincidence...it's the same syntax you would use to access an item in an XML file. Fancy that! 'user' denotes the user dictionary; 'email' denotes the particular table field; and 'alreadyexists' is a term I just made up, and indicates that Reactor should look for a tag called 'alreadyexists' in order to find the correct translation for this error. Thus, you'll notice the tag

<alreadyexists>That email address is already being used. Please select another email address. If you have forgotten your password, return to the main login screen and select "Forgot Password"</alreadyexists>

in the <email> section of our dictionary file.


To Sum it all up!

Okay, so in a nutshell, if you have a form being submitted and you want to ensure that the email address is unique (AND you haven't put a rule in place within the database itself so specifying this):

  1. add a method to your customizable validator CFC for the target table;
  2. add a 'validate' method to the same CFC in order to overload the system version of the same;
  3. within your custom 'validate' method, execute your custom method first
  4. within the same, execute the system version of validate using "SUPER.Validate()"
  5. edit your dictionary file to add a translation for your new custom error

That's it!

Doug out.
Posted by dougboude at 1:30 AM | PRINT THIS POST! | Link | 9 comments