Now that we have set up our database tables and triggers, the next step is to create a 4D Method to handle processing the survey results. So: create a new a Project Method and call it "WebSurveyHandler." Copy-and-paste the following into the method:
Code Listing for Project Method: WebSurveyHandler
ARRAY TEXT($atValues;0)
ARRAY TEXT($atNames;0)
GET WEB FORM VARIABLES($atNames;$atValues)
C_LONGINT($iPos)
C_TEXT($tFormName;$tPersonName)
$iPos:=Find in array($atNames;"form_name")
If ($iPos>0)
$tFormName:=$atNames{$iPos}
DELETE ELEMENT($atNames;$iPos)
DELETE ELEMENT($atValues;$iPos)
Else
$tFormName:="FORM1"
End if
$iPos:=Find in array($atNames;"WEBF_Name")
If ($iPos>0)
$tPersonName:=$atValues{$iPos}
DELETE ELEMENT($atNames;$iPos)
DELETE ELEMENT($atValues;$iPos)
Else
$tPersonName:="John Doe"
End if
QUERY([Surveys];[Surveys]Form_Name=$tFormName;*)
QUERY([Surveys]; & ;[Surveys]Respondent_Name=$tPersonName)
If (Records in selection([Surveys])=0)
CREATE RECORD([Surveys])
[Surveys]Form_Name:=$tFormName
[Surveys]Respondent_Name:=$tPersonName
SAVE RECORD([Surveys])
End if
C_LONGINT($iItemIndex)
C_TEXT($tQuestion;$tAnswer)
For ($iItemIndex;1;Size of array($atNames))
$tQuestion:=$atNames{$iItemIndex}
$tAnswer:=$atValues{$iItemIndex}
QUERY([Answers];[Answers]ID_Survey=[Surveys]ID;*)
QUERY([Answers]; & ;[Answers]Question=$tQuestion)
If (Records in selection([Answers])=0)
CREATE RECORD([Answers])
[Answers]ID_Survey:=[Surveys]ID
[Answers]Question:=$tQuestion
End if
[Answers]Answer:=$tAnswer
SAVE RECORD([Answers])
End for
QUERY([Answers];[Answers]ID_Survey=[Surveys]ID)
SEND HTML FILE("answers.html")
Go to the Method menu and choose Method Properties, then select the Available through 4DACTION option in the properties dialog.
This WebSurveyHandler method is nice in that it will handle an unlimited number of surveys from an unlimited number of respondents. Indeed, if we were handling just one survey, we wouldn't even need the Surveys table at all, since we would assume that all the Answers were for whatever the one survey was.
Since this method is somewhat long, we'll examine it in close detail, so you can see what's going on. It also uses a good number of 4D commands and constructs, so it will be worthwhile examining it. Before we begin, though, it is helpful to understand how this method will be used. It will be set as the "action" for an HTML form, e.g.:
<form name = "TestForm" method = "POST" action ="/4DACTION/WebSurveyHandler">
So with that in mind...
The first thing that we do is declare some arrays to hold the data submitted by the HTML form:
ARRAY TEXT ($atValues;0)
ARRAY TEXT ($atNames;0)
These two lines set up some arrays to hold the data submitted via the HTML form. Each HTML form field has a name, and a value (what the user types into it). The next line of the method copies the data from the HTML form to the arrays:
GET WEB FORM VARIABLES ($atNames;$atValues)
Now we have all the data from the HTML form in two easy-to-use 4th Dimension arrays. The next steps involve finding the survey/form name and the user who submitted it. We will set up a few local variables to help us with that task:
C_LONGINT ($iPos)
C_TEXT ($tFormName;$tPersonName)
Next, we will look to see if we can find the name of the survey (form) that was submitted:
$iPos:= Find in array ($atNames;"form_name")
If ($iPos>0)
$tFormName:=$atNames{$iPos}
DELETE ELEMENT ($atNames;$iPos)
DELETE ELEMENT ($atValues;$iPos)
Else
$tFormName:="FORM1"
End if
First we look in the "names" array for a value matching "form_name" using 4D's Find in array function. "form_name" isn't a "magic" keyword, it should have been entered as a "hidden" input field on the HTML form. If we don't see a form item with this name, we assign a default name of "FORM1". If we do find the item names form_name, we delete it from the $atNames array, and also delete its value from the $atValues array.
Next we will look to see if we can find the name of the respondent:
$iPos:= Find in array ($atNames;"WEBF_Name")
If ($iPos>0)
$tPersonName:=$atValues{$iPos}
DELETE ELEMENT ($atNames;$iPos)
DELETE ELEMENT ($atValues;$iPos)
Else
$tPersonName:="John Doe"
End if
This is virtually the same process as we used to find the survey/form name. If we don't find the "WEBF_Name" item in the $atNames array, we assume a respondent name of "John Doe." In a real production environment, we would probably want to raise an error at this point and handle it better.
Now we are going to query the database to see if the respondent has answered this survey before.
QUERY ([Surveys];[Surveys]Form_Name=$tFormName;*)
QUERY ([Surveys]; & ;[Surveys]Respondent_Name=$tPersonName)
If the Survey database record for this form from this respondent does not exist, we will need to create it:
If ( Records in selection ([Surveys])=0)
CREATE RECORD ([Surveys])
[Surveys]Form_Name:=$tFormName
[Surveys]Respondent_Name:=$tPersonName
SAVE RECORD ([Surveys])
End if
So now we have a new [Surveys] record, or we have located the original record from the respondent. Next, we will be saving the respondent's answers to the [Answers] table. First things first, though. To begin, we'll create a few more local variables:
C_LONGINT ($iItemIndex)
C_TEXT ($tQuestion;$tAnswer)
Next, we will loop through the form items. The first step in the loop is to copy data from the arrays to the $tQuestion and $tAnswer local variables. This is done to enhance readability of the code - it isn't a required step.
For ($iItemIndex;1; Size of array ($atNames))
$tQuestion:=$atNames{$iItemIndex}
$tAnswer:=$atValues{$iItemIndex}
QUERY ([Answers];[Answers]ID_Survey=[Surveys]ID;*)
QUERY ([Answers]; & ;[Answers]Question=$tQuestion)
If ( Records in selection ([Answers])=0)
CREATE RECORD ([Answers])
[Answers]ID_Survey:=[Surveys]ID
[Answers]Question:=$tQuestion
End if
[Answers]Answer:=$tAnswer
SAVE RECORD ([Answers])
End for
You see that each time through the loop, a query is performed to see if there is already an [Answers] record for the question for the Survey. If there is no answer yet to the question, a new record is created.
The method ends by querying the [Answers] table for all records belonging to the survey, creating a new current selection for the [Answers] table. The concept of a "selection" of records in 4th Dimension is very important, so you really should read up on that in the documentation.
QUERY ([Answers];[Answers]ID_Survey=[Surveys]ID)
The last step in this method is to send out the response page:
SEND HTML FILE ("answers.html")