Gossamer Forum
Home : Products : DBMan : Customization :

Order forms, cookies and record updates

(Page 1 of 2)
> >
Quote Reply
Order forms, cookies and record updates
Hi, everyone!

I have a series of order forms that gather purchase requests from the user via checkboxes and radio buttons. I am using cookies to save the pieces of each order request in the classic shopping cart fashion. Once the user has finished and is ready to order, I wish to gather the pieces of the request from the various cookies and manually update the database, thus bypassing any &html_record_form.

In taking a look at the Perl code for the add_record routine my confidence is not high that I would not break the routine. There must be a simple way to manually update the record fields as in %rec{'FieldName'} = "value", but I do not not see it. Any suggestions? Much thanks in advance.

Thanks for your time!

P.S. If you wish to to see the forms, they are at http://www.fastcecredits.com, => Login with test0/test0

------------------
TMTS Web Site Design Services
http://www.tmtsaz.com
Quote Reply
Re: Order forms, cookies and record updates In reply to
The big thing for you to realize is that sub add_record uses an array named %in, which is usually gathered directly from a form. You can, however, pull the data from anywhere, like from cookies.

Does this help?

(I promise I'll be of more help later on. I just stopped in for a bit right now.)


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol: Thanks for responding!

I see what you are saying in the code very clearly as in:

print DB &join_encode(%in);

I guess my question is how do I assign a particular value retrieved from a cookie to a particular field in the database?

Much thanks in advance!



------------------
TMTS Web Site Design Services
http://www.tmtsaz.com
Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

The cookie side is very much like that of a hash we find on the database side: value-delimiter-value-delimiter, so if "|" is our delimiter, an example would be

cookie=value 1|value 2|value 3

Likewise, cookies are manipulated in a manner much like dbman => read the cookie as a hash => convert the hashed values to an array => manipulate the indexed array. In fact, here is the JavaScript code that does just that:

var Packages = new Cookie("Packages") // a "Packages" cookie = name1|value1|quantity1|price1|name2|value2|...
var PackagesData = Packages.get() // PackagesData is the hash assigned by the get method
if (PackagesData != "") { // we have data here
var PackagesArray = PackagesData.split("|") // assign hashed values to PackagesArray
numPackages = parseInt(PackagesArray.length/4,10) // each "Package" contains 4 elements: name, value, quantity and price

In essence, all I need to know is how to assign a value (wherever it came from) to a particular field in the database. So, after the cookie values are now parked in an indexed array (using the above example where each "Package" is composed of four elemnts), I want to be able to do something like the following pseudocode:

for (i=0; i<PackagesArray.length; i+=4) {
open (DB, ">>$db_file_name") or &cgierr("error in add_record. unable to open database: $db_file_name.\nReason: $!");
print DB PackagesArray -> $rec{'FieldName1'};
print DB PackagesArray[i+1] -> $rec{'FieldName2'};
print DB PackagesArray[i+2] -> $rec{'FieldName3'};
print DB PackagesArray[i+3] -> $rec{'FieldName4'};
close DB;
}


Thanks for your help!

Jim




------------------
TMTS Web Site Design Services
http://www.tmtsaz.com
Quote Reply
Re: Order forms, cookies and record updates In reply to
Okay. I think I got it. The values are in an array -- @PackagesArray -- that is in the same order as the fields are listed in your .cfg file. Right?

I'm not sure whether you want to work with adding a record or modifying. But I think it would be the same either way.

The easiest thing (although possibly not the most efficient) would be to assign the contents of the @PackagesArray to the %in hash and then let DBMan do its thing on its own.

To add a record from cookie info, add the following to db.cgi, sub add_record, just after

my ($output, $status, $counter);

Code:
$i = 0;
foreach $column (@db_cols) {
$in{$column} = $PackagesArray[$i];
++$i;
}

You can do the same in sub modify_record, just after

my ($status, $line, @lines, @data, $output, $found, $restricted);

(This is all assuming I understand what you want to do. Smile )

If you have other things in your cookie array, especially at the beginning of the array, that aren't part of the database, change the initialization value of $i appropriately, remembering that counting starts at 0.

Please let me know if this works. I'm really curious.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
I don't know cookies, unless you're talking about snickerdoodles and chocolate chips. Smile

What is the format of the information you get from the cookie? Can you give me a specific example?


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

I took a look at taking the simple procedure that you have suggested, i.e., straightforward mapping of cookie array to database fields. While very appealing, I do not think it will work in this case due to a couple of complicating factors, most of which can be solved if I can do just a single cookie value => single database field mapping.

================

Complication #1: Variable record fields - I am setting up an "Orders" database that will house all orders taken by the user, but the orders have records of variable length, as in cookie 1 from order form 1 has a value of

cookie1=name1|quantity1|variant1|price1|name2|quantity2|variant2|price2|...

and cookie 2 from order form 2 has a value of

cookie=name|quantity|name|quantity|...

There are 6 order forms, hence 6 html pages, and 6 cookies. To account for the differences in the cookie record lengths, I have set up the orders database with the following configuration:

%db_def = (
UserID => [0, 'alpha', 20, 40, 0, '', ''],
ID => [1, 'alpha', 3, 10, 0, '', ''],
Date => [2, 'alpha', 12, 15, 0, &get_date, ''],
Field1 => [3, 'alpha', 1, 80, 0, '', ''],
Field2 => [4, 'alpha', 1, 80, 0, '', ''],
Field3 => [5, 'alpha', 1, 80, 0, '', ''],
Field4 => [6, 'alpha', 1, 80, 0, '', ''],
Field5 => [7, 'alpha', 1, 80, 0, '', ''],
Field6 => [8, 'alpha', 1, 80, 0, '', '']
);

In so doing, I can simply map the variable length cookie records into a database that has a number of fields to match the maximum number of cookie fields, i.e., cookie 3 may map into just Field1, Field2, and Field3 while cookie5 may use all six.

================

Complication #2: I am setting this up with the psuedo-relational structure you provide in your discussion "JPDeni's discussion on relational databases and DBMan" (Good stuff, by the way!).

I am setting up dbman to work with a number of databases. For our discussion, here is a simplified version:

(1) User Profile - Registration of user, as in user profile information (obviously a static, for ref. only database)

(2) New Orders - User purchase requests that have yet to be processed (the info from cookies)

(3) User Purchase History - a user's history log of purchases (info from New Orders gets moved here, once processed)

I wish to be able to use a typical relational db master-detail representation of the sort where

User Profile: "Joe Smith" --> order 1
order 2
order 3

User Profile: "Tim Howard" --> order 1
order 2
order 3

works as well as

Order 1 --> User Profile customer A
Order 2 --> User Profile customer B
Order 3 --> User Profile customer C

Again, using a universal format for the order form will solve a lot of problems caused by variable length fields in the order form.

================

As I said, doing the straightforward mapping as you first suggested sounded awfully appealing, but the tradeoff here is that I would have to manage 6 orders databases as well has creating a logistical problem for myself when it comes to managing the master-detail relationships that I wish to perform.

Your thoughts?

Jim


------------------
TMTS Web Site Design Services
http://www.tmtsaz.com
Quote Reply
Re: Order forms, cookies and record updates In reply to
I'm still confused. I think I need a concrete example.

Could you give me some real sample data and how it is pulled from the cookie, with the resulting array/hash? And, how do you want the values to be assigned to the DBMan fields?



------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

Let's say our cookie is named "Package", uses the "|" as delimiter, and contains the following hash:

Package=item1|item2|item3

We convert the hash to an array named "PackageArray" so that we have an array that looks like:

PackageArray[0]=item1
PackageArray[1]=item2
PackageArray[2]=item3

Now we want to put the elements of the array into the database. Let's say we have the database defined as I did above, i.e.,

%db_def = (
ID => [0, 'alpha', 3, 12, 0, '', ''],
UserID => [1, 'alpha', 3, 12, 0, '', ''],
Date => [2, 'date', 12, 15, 0, '', ''],
Field1 => [3, 'alpha', 1, 80, 0, '', ''],
Field2 => [4, 'alpha', 1, 80, 0, '', ''],
Field3 => [5, 'alpha', 1, 80, 0, '', ''],
Field4 => [6, 'alpha', 1, 80, 0, '', ''],
Field5 => [7, 'alpha', 1, 80, 0, '', ''],
Field6 => [8, 'alpha', 1, 80, 0, '', '']
);

Is something like the following possible?

$in{$UserID} = $db_uid;
$in{$Date} = &get_date;
$in{$Field1} = PackageArray[0];
$in{$Field2} = PackageArray[1];
$in{$Field3} = PackageArray[2];


Interesting problem, isn't it? Cookie hash => JavaScript array => perl scalar => dbman database

Jim

------------------
TMTS Web Site Design Services
http://www.tmtsaz.com
Quote Reply
Re: Order forms, cookies and record updates In reply to
Sure. That's no problem. But earlier you said that there were varying amounts of data within the cookie.

Will Field1 always be PackageArray[0]? Will Field6 always be PackageArray[5]?

If so, you can use the code I gave you before. Just initialize the $i counter as

Code:
$i=3;

It doesn't matter if there are fewer items in the PackageArray than will fill up your fields.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

Correction to above:

PackageArray[0]="item1"
PackageArray[1]="item2"
PackageArray[2]="item3"

That is to say, cookie hash is just ASCII, typing to string happens in JavaScript code.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

Answer to your question is yes.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
Okay.

There's no problem with setting

$in{$Date} = &get_date;

And the ID would probably come from the default.count file, right?

But are users logged in to the database when they place their orders? Where would you get the $db_uid? (Although you would probably want $db_userid.)


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

Yes, ID comes from default.count. I have dbman set up with

$db_key = 'ID'; and
$db_key_track = 1;

You are also right about my wanting $db_userid versus $db_uid - I want what the user is using for a login name. This is what is being used as the common field between databases (as outlined in your aforementioned "Relational Databases" document).

I am wondering what I am doing wrong at this point. I am using the approach we discussed of

$in{'UserID'} = $db_userid;
$in{'Date'} = &get_date;
$in{'Field1'} = PackageArray[0];
$in{'Field2'} = PackageArray[1];
$in{'Field3'} = PackageArray[2];
&add_record;

but I get script errors.

I question now how in fact how we can assign an element value from a JavaScript array to a Perl scalar? Ideally, I would do the above and call add_record for each line item of the order, as recorded in the cookies.

Scratching my head,

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
So the users are logged in, right? (I'm still trying to imagine what happens when the user first comes to your site. Smile )

Code:
but I get script errors.

What are the errors you get?

Assigning a value to a hash element from an array element shouldn't be a problem. Exactly as you have it should work just fine.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

I know I am making a pest of myself to you by now, but I am still having problems that seem to resolve around the JavaScript array element assignment to a Perl scalar. I can only hope that you are gaining as much educationally as I am (at least that is what I tell myself to ward off the frustration demons!). The following is the entire code in question. Note that I have used the while statement rather than

for ($i=0; $i<$length; $i+=2) {
...
}

since this type of for statement implies a "lexical scope for variables declared with my in the initialization statement" (this according to my "Perl Programmer's Reference Guide").

The user is logged in at this point, BookletsArray is the array containing the values obtained from the cookie. In this particular case, a Booklets order is composed of two elements: name and quantity, so the array looks like

BookletsArray[0]=name1
BookletsArray[1]=quantity1
BookletsArray[2]=name2
BookletsArray[3]=quantity2
...

and so on. The length of the array is assigned by the statement

$length = BookletsArray.length;

The variable numBooklets has been previously assigned the value of (BookletsArray.length/2). We break out of the JavaScript code to (1) change over to the New Orders database, and (2) update the database with the number of new records as determined by (BookletsArray.length/2), hence the $i+=2; increment, after which time we change back to the original User Profile database.

CODE:

print qq|
function ConfirmOrder() {
...
$length = BookletsArray.length;
if (numBooklets > 0) {
|;
&switch_to_neworders;
$i=0;
while ($i < $length) {
$in{'UserID'} = $db_userid;
$in{'Date'} = &get_date;
$in{'Field1'} = BookletsArray[$i];
$in{'Field2'} = BookletsArray[$i+1];
&add_record;
}
continue {
$i+=2;
}
&switch_to_userprofile;
print qq|
}
...
}
|;

The above code results in the following script error:

CGI ERROR
==========================================
Error Message : Error loading required libraries.
Check that they exist, permissions are set correctly and that they compile.
Reason: Can't use subscript on constant item at ./UserProfile/userProfile_html.pl line 2639, near "$i]"
Can't use subscript on constant item at ./UserProfile/userProfile_html.pl line 2640, near "1]"
==========================================


The same thing happens if I use an integer equal to the known array length instead of $length.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
I just saw something that I should have seen a long time ago.

It should be

$BookletsArray[$i]

Give that a try.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

That was one of the first variations I tried after we first linked up. I took the lead from your response of the 24th where you had the following:

$i = 0;
foreach $column (@db_cols) {
$in{$column} = $PackagesArray[$i];
++$i;
}

Since I knew that we were assigning scalars, and that Perl takes scalars as $xxxxx I figured that that was what was needed. So I tried the following:

if (numBooklets > 0) {
|;
&switch_to_neworders;
print qq|
for (i=0; i<BookletsArray.length; i+=2) {
$in{'UserID'} = $db_userid;
$in{'Date'} = &get_date;
$in{'Field1'} = $BookletsArray;
$in{'Field2'} = $BookletsArray[$i+1];
|;
&add_record;
print qq|
}
}

What happens is that there is a run-on of html pages - like it draws this and all subsequent html pages in the script one on top of another. At first it looked to me like I missed a semicolon or comma someplace so I commented all the lines and one by one uncommented them until I found the culprit, it is the line &add_record; and I don't have a clue beyond this.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
I think I should have stayed with what I said from the start -- I don't know anything about cookies except snickerdoodles and chocolate chips. I also don't know Javascript.

Wait a minute.

sub add_record ends up by sending the script to sub html_add_success or sub html_add_failure. You've got it in a loop, so it prints out either the success or the failure page every time it runs into the line

&add_record;

I think you need to move that line.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

That would make sense...the layered html I was referring to looked like the success and failure pages.

Assuming that this is indeed the case (and it does make sense) would it make more sense for me to just embed the print DB statement in the loop? The user could potentially order dozens and dozens of line items so that dozens and dozens of records would need to be added, so the statement would need to stay in the loop where it is. What about constructing a large 2-dimensional array where each row is a line item, converting this to a hash, and then passing this to add_record? Your thoughts? What would you recommend? I believe we are on to something here, Carol.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
I would write to the database each time. Basically you would just want to copy most of sub add_record into this subroutine. It might be a little bit slower (but I don't think so). Even if it is, it's much less confusing than using a multi-dimensional array.

------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

Something like this?

$length = BookletsArray.length;
if (numBooklets > 0) {
|;
&switch_to_neworders;
$i=0;
while ($i < $length) {
$in{'UserID'} = $db_userid;
$in{'Date'} = &get_date;
$in{'Field1'} = $BookletsArray[$i];
$in{'Field2'} = $BookletsArray[$i+1];
open (DB, ">>$db_file_name");
print DB &join_encode(%in);
close DB;
open (ID, ">$db_id_file_name")
print ID $in{$db_key};
close ID;
}
continue {
$i+=2;
}
&switch_to_userprofile;
print qq|
}
Quote Reply
Re: Order forms, cookies and record updates In reply to
The only problem I can see is with the counter. There's nowhere it is incremented.

Code:
$length = BookletsArray.length;
if (numBooklets > 0) {
&switch_to_neworders;
$i=0;
while ($i < $length) {
$in{'UserID'} = $db_userid;
$in{'Date'} = &get_date;
$in{'Field1'} = $BookletsArray[$i];
$in{'Field2'} = $BookletsArray[$i+1];
open (ID, "<$db_id_file_name") or &cgierr("error in get_defaults. unable to open id file: $db_id_file_name.\nReason: $!");
if ($db_use_flock) { flock(ID, 1); }
$in{$db_key} = <ID> + 1; # Get next ID number
close ID;

open (DB, ">>$db_file_name");
print DB &join_encode(%in);
close DB;
open (ID, ">$db_id_file_name")
print ID $in{$db_key};
close ID;
}
continue {
$i+=2;
}
&switch_to_userprofile;
}

I think that should work.


------------------
JPD





Quote Reply
Re: Order forms, cookies and record updates In reply to
Carol:

I believe we are almost there. It seems to be working fine (as in no errors), except that there is no update to the newOrders.db.

I have checked the following:

1) UNIX permissions on newOrders.db are 666.

2) newOrders.cfg is defined as

%db_def = (
ID => [0, 'alpha', 3, 12, 0, '', ''],
UserID => [1, 'alpha', 3, 12, 0, '', ''],
Date => [2, 'alpha', 12, 15, 0, '', ''],
Field1 => [3, 'alpha', 1, 80, 0, '', ''],
Field2 => [4, 'alpha', 1, 80, 0, '', ''],
Field3 => [5, 'alpha', 1, 80, 0, '', ''],
Field4 => [6, 'alpha', 1, 80, 0, '', ''],
Field5 => [7, 'alpha', 1, 80, 0, '', ''],
Field6 => [8, 'alpha', 1, 80, 0, '', '']
);

3) $db_key = 'ID';
$db_key_track = 1;


4) db.cgi has the following defined:

sub switch_to_userprofile {
#-----------------------------------------------------
# Relational Database routine to change db to userProfile
@db_cols = qw(UserID FirstName LastName Address1 Address2 City State Zip HomePhone WorkPhone eMail LicenseNum Specialty Date);
$db_file_name = $db_script_path . "/UserProfile/userProfile.db";
$db_key_pos = 0;
}

sub switch_to_neworders {
#-----------------------------------------------------
# Relational Database routine to change db to newOrders
@db_cols = qw(ID UserID Date Field1 Field2 Field3 Field4 Field5 Field6);
$db_file_name = $db_script_path . "/NewOrders/newOrders.db";
$db_sort{'Date'} = 'date';
}

============================

I must be missing something simple here, I'm sure.

Jim
Quote Reply
Re: Order forms, cookies and record updates In reply to
In your

sub switch_to_neworders

you're also going to need to include

Code:
$db_key = 'ID';
$db_key_track = 1;

(I didn't mention that in my tutorial on relational databases because I didn't think it would be necessary. I hadn't anticipated a setup like yours.)

I'm not sure why you had

&switch_to_userprofile;

at the end of the routine. (I left it in because I didn't know if you had a reason for it.) I don't see any purpose in it.

I'm also curious about

Code:
continue {
$i+=2;
}

I hadn't looked at it closely before, but shouldn't you be incrementing the counter variable within the "while" loop? Of course, I've never used the "continue" command, so it might be something that I don't understand. Seems to me, though, that, unless you increment $i within the "while" loop, you're going to have a forever loop.

None of these things would stop records from being added to the .db file, though.

Debugging something like this is very difficult, especially because it is complicated by things I don't understand. I'm not sure where to start.


------------------
JPD





> >