Document Home

Previous Managing Teams and Players

Samples for this section

Developing A Generic Editing Table Subroutine



The model I chose for this generic subroutine is, of course, the manner in which a given day's schedule was edited in the previous section, with the generated page allowing records to be added, deleted, or modified. In this chapter I will develop the prototype for the subroutine, after which I will use it in the development of a new version of sched_edit(), the subroutine that generates the page used to edit a day's schedule. In following chapters I will apply it to implement team and player management functionality. This process, in which similar functionality is generalized into a format that can be called in different context, is called refactoring. I have done essentially the same thing in previous chapters, but I am going to be a little more formal about the process here.


At a general level, what I did when generating one of those tables in sched_edit() was to loop through a set of existing records, then print a series of lines that could be used to add additional records. Those records, however, were in a unique format, occupying the same position in a series of arrays. This raises an issue that is one of the predominant concerns in this kind of endeavor: the data fed to the subroutine must be in structures sufficiently generic to be readily constructed in a wide range of context, yet must be flexible enough to be able to provide sufficient information to control the generation of the table. Therefore, I took the time to develop a preliminary draft of the structure of the arguments that will be used by the subroutine. This set of arguments is likely to be modified somewhat as I adapt the subroutine to a wider range of contexts, or as I realize that I had forgotten some element that I need <grin>, but I think that this set pretty well covers what I need.

$rows: The name of this argument reflects its role. $rows will be a reference to an array of references to arrays, each of which will hold the values to be displayed in a table row (in general).

$names:The structure referenced by this scalar will hold the identifying and display characteristics of the elements included in the arrays referenced by $rows. The structure will again be an array of references to arrays, with the associated references in the order of the items in the arrays referenced in the array referenced by $rows. The referenced arrays are, at present, envisioned as consisting of three elements. The first will be the display name used in construction of the title row of the table; the second the name for the parameter to be used for that element in whatever manner it is to be printed to the generated page; and the third will define the manner in which the element is to be printed to the generated page. I currently envision this a representing one of three options: select box, text, and hidden.

The relationship between these structures is illustrated graphically to the right. The first element of the @names array points to an array holding the descriptive information for the first element of each of the arrays referenced by the elements in @rows. Therefore, the table header row will print "Home" over the first column of the generated table, the name of that element will be the concantenation of "home_' with whatever is held in $j, and the element will be displayed as a select box. The array referenced by the second element of @names holds the descriptive information for the elements in the second position of the arrays referenced in @rows, and so forth. Note that in the array referenced by $name_ref4, the first element is blank. No table header column, of course, will be printed for an element that will be printed as a hidden field. I will mention here that when I put together this draft of @names I left out an element that will be required to generate the page. The reader is given the opportunity to determine just what that was before I reveal it below.

The remaining arguments that will be passed to the subroutine require relatively little explanation:

$tot_rows: The total number of rows to be displayed. In the context of the table to be drawn to edit a day's schedule, for example, this would represent the value of $max_games.

$delete : This argument will be a flag to signify whether a radio button widget should be drawn for each of the rows populated by $rows to allow the deletion of the record represented by that row. In the context in which the subroutine will be used here that flag will be set, but as I could envision contexts in which it would not be used, I thought it advisable to include that capability.

$r: A reference to the request object.

$params: A reference to the %params hash

$colors: Table background color.



Now that I have specified the interface to the subroutine, I can put it together. As I always do, I put it together bit by bit, testing as I go. My initial focus was to construct the table header row, because that alowed me to work through the basic issues involved with accessing the $names structure before I got into a more complex context.

sub edit_table	{
	
	my ($params,$rows,$names,$tot_rows,$delete,$r)=@_;
	
	
	##table header
	$$r->print("<center><table border='1'><tr>");
	$$r->print("<td>Select</td><td>To Delete</td>") if $delete;
	
	##print the first element of each array referenced the in array referenced by $names
	foreach my $t (@$names)	{
		
		$$r->print("<td>$$t[0]</td>") if $$t[2] !~ /hidden/;
		
	}
	$$r->print("</tr></table>");
}
For the most part, this little bit of code is relatively mundane. After reading the arguments passed to the subroutine, I start a table that is centered on the page and, if the $delete flag is set, print the two cells that serve as a header over the two radio buttons that allow a record to be selected for deletion. The remainder of the cells in the header row are printed by stepping through the elements of the array referenced by $names, printing the first element of the array referenced by the current element of @names.


Once I had put that into place I wanted to test the generation of the table header, so I created a quick test environment in BB_STACKED.

	if ($path=~/team/)	{
		
		my @test=('test1',' ',' ');
		my @testa=('test2',' ',' ');
		my @testb=('test3',' ',' ');
		my @names;
		push @names, (\@test,\@testa,\@testb);
		edit_table($params,' ',\@names,' ',1,$r);
		
	}
(Later versions of this snippet remain in the copy of BB_STACKED included in the current samples file, so restarting apache with these files installed will display this little table when the team options is selected from the league menu.) This simply consists of three arrays with a bit of text in the first position, which is defined as holding the display name for the table header. After pushing references to those arrays onto the @names array, I call the edit_table() subroutine with that array as one of the arguments. I placed this snippet within the league() subroutine in BB_STACKED. Given the target specified for the team option in the text file that creates the league menu, selection of team will now lead to the execution of this snippet, which results in the generation of a page that has a table header that looks like this:


In order to verify that the $delete flag was working as I had intended, I changed the pertinent value in the arguments list passed to the subroutine to 0. After restarting apache-perl, the generated table header looks like this:


Clearly, everything is proceeding according to plan.


At this point I started messing with the body of the table. As suggested by the discussion of the arguments passed to the subroutine earlier in the chapter, this will involve stepping through the @rows array, and for each of the elements in that array stepping through the array referenced by that element to print a line. Obviously, given that this is perl, there is more than one way to do this, but it seemed to me that the most straightforward approach is to use two foreach() commands, one nested within the other. As I must track the position of the current element in the @rows array, I initialized the scalar $j to hold that position. The reason for that will be clear shortly. At this point I started to move through the structure.


The bare bones of the algorithm that moves through the structure, printing one line after another, is this

	foreach my $s (@$rows)	{
		
		$k=0;
		$$r->print("<tr>");
		
		foreach my $s1 (@$s)	{
			
			$$r->print("<td>");
	
			}
			
			$$r->print("</td>");
			$k++;
		}
		$$r->print("</tr>");
		$j++;
	}
	$$r->print("</table>");
Within the foreach() that iterates over the @rows array, I set the scalar $k to 0. As the array referenced by the current element of @rows is traversed, $k will hold the current position in that referenced array. This is key to the appropriate functioning of the subroutine, because the pertinent descriptive information in @names is in the array referenced by the $kth element of @names. Remember, this is simply the way I structured things. In this barebones version of the subroutine, a table cell is printed for each element in the referenced array. At the end of that array the row is closed, the @rows position counter incremented, and the array referenced by the next element of @rows processed. After the last element of @rows is processed, the table is closed.


It was now time to put some logic within that structure. For each element in the array that holds a row (here denoted as @$s, representing the dereferencing of the array held in $s), I have to determine the manner in which it should be displayed and, based on that determination, output the contents of the cell in the appropriate manner. In previous chapters I have implemented such logic with if() - elsif() structures, but here I use the perl switch construct, a frequently-employed convention for representing the same kind of logical structure. These structures acquired the name "switch" because their operation is similar to that of an electro-mechanical switch. In some other languages the same kind of structure is known as a case statement, as in "in this case do this, in that other case, do that, etc.".


The perl switch construct relies on what is called a "bare block", a chunk of code within curly braces but not specifically associated with a subroutine name or a conditional expression. As used here, the bare block is primarily an aid to legibility. It is quite possible to construct a series of if - elsif() statements that would implement what I have here, but from a stylistic perspective many prefer the visual clarity provided by a switch implementation.


Conceptually, the switch strcutre fits into the overall subroutine structure as illustrated here:

	foreach my $s1 (@$s)	{
			
			$$r->print("<td>");
			
			SWITCH: {}
			
			$$r->print("</td>");
			}
The manner in which each table cell is printed is defined by the conditions within the switch{} block. The first condition I am going to implement within that block is that in which I want to print a select box, defined by the presence of the string "select" in the third element of the array referenced by the element of @names that occupies the same position as does the subject element in the arrays referenced by the elements of @rows. That is more confusing to say than it really is. The best way to visualize it may be to look back at the illustration above or to look at the little test struture that I construct in BB_STACKED to send to the subroutine.
	if ($path=~/team/)	{
		
		my @test=('test1',' ','select',$select[6]);
		my @testa=('test2',' ','text','');
		my @testb=('test3',' ','text ','');
		my @names;
		push @names, (\@test,\@testa,\@testb);
		my @line1=('006','goodbye','hello');
		my @line2=('004',' ',' ');
		push my @rows, (\@line1,\@line2);
		edit_table($params,\@rows,\@names,' ',0,$r,$colors);
		
	}
Note that the @test array now contains a fourth element, the missing element to which I earlier referred. I had not previously included a provision for defining the hash that would be used to display values in a select box for the pertinent element, so I tacked that onto the end of the array. In the structure created in this little example, the @test array, referenced by the first element of @names, provides the descriptive information for the first element of each of the arrays referenced by @rows. Here the values to which that array pertains are "006" and "004". As the third element of @test contains the string "select", the first cell of each table row should be generated as a select box. This condition is represented as
				if ($names->[$k][2] =~ /select/)
Although it is possible to recurse through a referenced array of arrays like this, a far more legible solution is to use the array of arrays (AoA) notation used here, which references the third element of the $kth element of the array referenced by $names. The call to sel_box() within the condition can now be defined as
					sel_box($names->[$k][3],$r,$names->[$k][1],'','',$rows->[$j][$k]);
Here $names->[$k][3] refers to the fourth element of the pertinent $names array, in which I stored the reference held in the seventh element of the @select array, $teams. $teams is, of course, the hash that associates team names with their ids. $names->[$k][1] refers to the element defined as representing the name for the generated widget, and the final argument, $rows->[$j][$k], represents the current element in @rows AoA, to be used to flag the selected value in the select box. Following this statement, the conditional block executes with the statement
					last SWITCH;
which directs execution to the last line in the SWITCH block.


The chunk that steps through a row array now looks like this

	foreach my $s1 (@$s)	{
			
			$$r->print("<td>");
			
			SWITCH: {
			
				if ($names->[$k][2] =~ /select/)	{
					
					sel_box($names->[$k][3],$r,$names->[$k][1],'','',$rows->[$j][$k]);
					last SWITCH;
					
				}
			}
			
		} 
This, of course, is only going to print those elements that are specified to be generated as select boxes. Selecting "Team" from the league menu with these versions of the subroutine and BB_STACKED active will now generate


At this point it was easy to extend what was already done to include the generation of text widgets.
				if ($names->[$k][2] =~ /text/)	{
					
					
					$$r->print("<input type='text' name=$names->[$k][1] value=$rows->[$j][$k] >");
					last SWITCH;
					
				}
Inclusion of this code, however, initially printed a blank text box until I realized that I had not stored a value in the pertinent element in the arrays referenced in @names. Therefore I modified the test data I am creating in BB_STACKED to include that element
		my @test=('test1','home ','select',$select[6]);
		my @testa=('test2','away ','text','');
		my @testb=('test3','text','text ','');
and with that change the page generated appropriately:



The final context is a situation in which I want to print the value as a hidden field. Although not as frequently as with text widgets and select boxes, there have been times when I have wanted to output hidden values on the same level of granularity as table entries. Outputting hidden fields, however, is not quite as straightforward as simply changing the line that prints the text widget to output a hidden field. Or rather, it is, but I had to make some modest changes to the structure of the surrounding code to have theings come out in the manner that I intended. As it does not make a whole lot of sense to print a table cell for a hidden item, I have to move the table column open and close (<td> and </td>) tags within the conditions that actually print table elements. As a result, the switch block now looks like this

			SWITCH: {
				
				
				if ($names->[$k][2] =~ /select/)	{
					
					$$r->print("<td>");
					sel_box($names->[$k][3],$r,$names->[$k][1],'','',$rows->[$j][$k]);
					$$r->print("</td>");
					last SWITCH;
					
				}
				
				if ($names->[$k][2] =~ /text/)	{
					
					$$r->print("<td>");
					$$r->print("<input type='text' name=$names->[$k][1] value=$rows->[$j][$k] <");
					$$r->print("</td>");
					last SWITCH;
					
				}
		
				if ($names->[$k][2] =~ /hidden/)	{
					
					
					$$r->print("<input type='hidden' name=$names->[$k][1] value=$rows->[$j][$k] >");
					last SWITCH;
					
				}
				
			}
I changed the last array to
 		my @testb=('test3','text','hidden ','');
and the generated page now looked like


Viewing the source that generated this page revealed this line
<input type='hidden' name=text value=hello >
indicating that the hidden field has been successfully written.


Now that I had a working prototype I could start using it to generate tables using real data. As one might expect, there are a couple of wrinkles involved in using the subroutine in something more serious than the test context employed above, as will shortly be apparent.


As I said earlier, my first use of this subroutine was in an alternative formulation of the generation of the page used to edit schedule records. My initial step in this process was to load the data returned from the selections on a calendar month page into the structure that I defined above for use with edit_table(). For development purposes, I created a parallel subroutine, sched_edit_2(). This allowed the use of sched_edit() as a model, because the basic structure involved with associating parameter array elements into a composite record is essentially the same.


While there are some similarities between the previous version of this subroutine and this one, it is a mistake to allow those similarities to color the way this subroutine is viewed. There are some very important differences. I speak from personal experience. There are times when I am working on this when I am subject to frequent interruptions, and in such circumstances I tend to look for something that I can use to pull myself back into the structure of what I was doing when I return. In this specific context, that led me to apply elements of the previous version more extensively than I should have, and I then had to invest some time in tracking them down and backing them out. I was, however, still well ahead of where I would have been had I coded the new subroutine from scratch.


Recall that the primary purpose of this exercise is to create a generic subroutine that can be used to display relatively well-defined sets of information in a tabular format that facilitates the modification of that information. This is going to substantially ease the process of adding new components to the system. Inherent in the act of generalizing such a structure, however, is the removal of elements unique to the context in which that structure was originally implemented. As a result, the introduction of some new control elements to handle aspects of the page generation that were previously handled in context is required.


The initial part of the subroutine is identical to the previous version, excepting the initialization of the $table scalar. This scalar will play an important role in this version, as will soon be apparent.

	my ($r,$db,$colors,$params,@select)=@_;

	#initialize day counter
	my $j=1;

	#initialize table counter
	my $table=0;
	
	my ($c_day,$max_games);
	
	#start outer table to serve as frame
	$$r->print("<br><center><table width='75%' border='2'><tr><td>");	

	##start the form
	$$r->print("<form action='/bb_app/league/la-store' method='post'>");

To recap, this portion of the subroutine reads in the passed arguments, initializes scalars, and starts both the outer table that frames the page and the html form that accepts user input.


The substantive changes in this version begin within the loop that iterates over the values of the $j day counter.

	##pass the year and month as hidden fields
	$$r->print("<input type='hidden' name='year' value=$$params{'year'}[0]><input type='hidden' name='month' value=$$params{'month'}[0]>");

	while ($j <= 31) {
	
		##this scalar holds the name of the parameter flagging the selection status for the day represented by the day counter	
		$c_day = 'day_'.$j;
		
		##the presence of the value 'yes' indicates that the date was selected 
		if ($$params{$c_day}[0]=~/yes/)	{
		
		
			##name of the parameters holding the characteristics of the games for a given day, and which will be printed in a given table
			my $game='game_'.$table;
			my $home='home_'.$table;
			my $away='away_'.$table;
			my $time='time_'.$table;
			my $date='date_'.$table;
		
		
			##create descriptive arrays		
			my @a = ('Home',$home,'select',$select[6]);
			my @b = ('Away',$away,'select',$select[6]);	
			my @c = ('Time',$time,'select',$select[7]);
			my @d = ('',$game,'hidden','');
			my @e =	('',$date,'hidden','');
			##store  references to those arrays in the @names array
			my @names=(\@a,\@b,\@c,\@d,\@e);

Once a selected day is identified with the if() statement, a series of scalars are created that hold the names that will be assigned to the widgets generated as part of the table of games for any given day. These names will, of course, be the names of the parameters parsed from the request object as the server responds to the submission of the page being generated here. I know that when I refer to them as parameter names at this point I am short-circuiting that connection, but one can only restate that association so many times before it gets a little repetitive <grin>. After assigning those names, the descriptive arrays that hold the information pertinent to the elements of the arrays of values are constructed, and references to those descriptive arrays are stored in @names. Once that is accomplished, I step through the parameter arrays current to this submission as I did before, but in this version rather than generating a page with the values I store the associated values into an array and push a reference to that array onto @rows.
			##initialize array position counter
			my $k=0;

			##initialize data array
			my @rows;

			foreach my $t (@{$$params{'home_'.$j}})	{
		
				my @temp = ($$params{$home}[$k],$$params{$away}[$k],$$params{$time}[$k],$$params{$game}[$k]);
				push @rows,\@temp;
				$k++;
		
			}
			
Now that the AoA's have been populated for a given date, the table can be generated. Before I get into that, however, I want to point out some changes I made to the edit_table() subroutine. When I developed the prototype of edit_table() earlier in the chapter, I did not include the interfaces necessary to iteratively generate multiple tables on a single page. Required for this process is a consistent and predictable set of associated widget names for each table generated, so the server will have a coherent structure of parameters to process after the page is submitted. In the previous version of the subroutine it was relatively straightforward to use the values of the day counter and the array element counter in that role. Here, however, I am making the operation of edit_table() independent of the environment from which it is called. That is, of course, necessary if I am going to call the subroutine in a wide range of enviroments. Therefore, I had to explicitly define a mechanism to use to control the naming of the widgets generated by edit_table(). This was the driving force behind the introduction of the $table scalar within the calling scope, mentioned a little earlier, and of the $t_row scalar now added to edit_table(). ($t_row, of course, is shorthand for table row. I could have used $row, because perl is smart enough to know the difference between the scalar $row and the various expressions used to access an array named @row, such as $row[0]. The human eye, however, is easier to fool, so I used a name that could be more easily recognized as different from the references to @rows that are present within the subroutine.) Within edit_table(), these two scalars determine the naming of the radio widget that holds the delete selection status of a given row in the generated table.
 		my $delete_sel='del_'.$table.'_'.$t_row;
As the names established for the row elements in the new version of sched_edit() are associated with the value in the $table scalar, the naming scheme will lead to a parameter structure that can be accessed and processed in just the same manner as edit_schedule_proc() currently does once the generated page is submitted. More on that in just a bit.


Generating the page of tables now seems almost trivial. With all of these elements in place, generating a page that looks the same as I generated in the previous version is simply a matter of printing the date, calling edit_table() to generate the table with the material I stuffed into the @rows and @names arrays, and incrementing the $table counter.

			##start the table for a given date's games
			$$r->print("<br><center><table border='1' $colors><tr><td><b>$$params{'month'}[0] - $j - $$params{'year'}[0]</b></td></tr></table>");
			
			##use the edit_table() subroutine with the arrays populated above to generate the table rows for that date
			edit_table($params,\@rows,\@names,$max_games,1,$r,$colors,$table);
			$$r->print("<br>");
			
			##increment the table counter	
			$table++;
The result is a page that looks like this:


The discerning reader, upon viewing this image, might well point out that there is no provision on that screen for the entry of additional games. Well, that is true. I wanted to get the framework of the subroutine implemented before I included the code required to extend into this bit of functionality.


The approach followed here is the same as that which I adopted in the previous version, in which I step through the elements of the parameter arrays submitted for a value, keeping track of the number of lines that have been written, and then print "blank" lines until the point at which I reach some pre-determined value. While I gave some thought to adopting a more sophisticated approach, consideration of alternative structures led me to decide that they would be more difficult to maintain, and that I would be adding that maintenance burden for no reason other than doing something that looked fancy. Therefore, I decided to stick with an implementation similar to that which I used previously.


This is, however, slightly more involved here than in the previous version, in which I simply looped through a short block that called sel_box() with the appropriate parameters. Remember, the purpose of this chapter is to produce a generalized version of the subroutine that can be used with different sets of data. The only source of descriptive information available within the subroutine about the elements to be drawn on the page is the information contained in the arrays referenced by @names. As the elements of the @names array are in the display order of the items in the table, however, all that is required is that I step through those elements and use the information in the arrays each of those elements reference to draw the appropriately-named widgets. The task of drawing these rows is slightly simplified by the fact that, at least in the current context, there is no need to print hidden fields within each of these rows. Therefore, the code that implements this process is fairly straightforward.

 	while ($t_row < $tot_rows)	{
			
			$k=0;	
			$$r->print("<td></td><td></td>") if $delete;
			
			foreach my $s2 (@$names)	{	
				
				
				
				SWITCH: {
				
				
				if ($names->[$k][2] =~ /select/)	{
					
					$$r->print("<td>");
					sel_box($names->[$k][3],$r,$names->[$k][1],'','','');
					$$r->print("</td>");
					last SWITCH;
					
				}
				
				if ($names->[$k][2] =~ /text/)	{
					
					$$r->print("<td>");
					$$r->print("<input type='text' name=$names->[$k][1] >");
					$$r->print("</td>");
					last SWITCH;
					
				}	
				
			}
		$k++;
	
		}
		$$r->print("</tr>");
		$t_row++;
	}	 
This snippet executes as long as the $t_row counter is less than the value of $tot_rows. (Remember, as I initialized $t_row with the value 0, there is no need to make that comparison "less than or equal to".) After resetting the $k scalar two empty table cells are returned to the browser if the $delete flag is set. This moves the current table column past the columns that are used to select existing records for deletion. The subroutine then steps through each element of the @names array, printing a select box with the relevant hash but without a specified selected value, if the relevant element of the relevant element of @names contains the string "select", or an empty text widget if that element contains the string "text". The $k scalar is incremented, indicating the position of the next element of the @names array, and execution of the loop continues as long as there are elements in the @names array. After the array has been processed, the table row is closed, the $t_row counter incremented, and additional lines drawn until the value of $tot_rows is reached.


The addition of this bit of code to the subroutine now results in the generation of a familiar page.




Now that the edit page is generated appropriately, the next step was to be able to process the submitted material. edit_schedule_proc() was almost able to process the material unchanged, but not quite. The first stumbling block had to do with the index values used to assign widget names on the edit page. In the previous version of sched_edit(), the widgets were named with the day of the month counter ($j) as part of the name, and edit_schedule_proc() simply iterated over the range from 1 through 31 to find sets of parameters to process. Here, however, the initial value of the $tables scalar (0) not only results in the skipping of any deletions of the earliest game for a date, but also messes up the operation of the scheme that I use to add new records. At root, this is a trivial problem, and easily fixed, but it is also the kind of problem that can require a bit of time to track down.


As an aside, as I was working through this I realized that as I had been putting together the code that provides user feedback in edit_schedule_proc() in the Processing Schedule Modifications chapter, I had not changed the inequality comparison that verifies insert operations from "$deletes ... $all_deletes" to "$inserts ... $all_inserts". Mea culpa, this is one of the hazards of cut and paste. That modification has of course been made to the samples for this chapter. I have not, however, fixed it in the snippet included in the text near the end of that chapter, so a curious user could look back at that if desired.


I discovered that bug after making sure that the edit_schedule_proc() subroutine was using the same starting counter value as was used to generate the submitted material. At that point, I knew that the subroutine was bery close to being able to process the submitted material appropriately, albeit in a slightly inefficient manner in that most submitted pages would involve far fewer tables than the 31 allowed in that version of the subroutine. Out of curiosity, I decided to see how close it would come to working without further modification. In this case, when I submitted a page that included added records, modifications and deletions would be recorded, but those added records were not stored and no feedback on the records inserted would be returned to the browser. I looked in the /var/log/apache-perl/error.log, and found this line.

DBD::Pg::st execute failed: ERROR:  Bad date external representation '6/0/2004' at /home/www/bb_lib/BB_APP_INTERFACE.pm line 1001, <FH> line 11.
Ok, I thought, that makes sense. I had forgotten that I was using $j to create a date to insert. Before fixing that, however, I wanted to track the lack of feedback, and it was then that I found the problem described above. After fixing that, the feedback generated was appropriate.



Once the error reporting was behaving, I addressed the source of the error. In order to minimize the amount of change associated with this process, I simply created a new hidden field named "day" with the value of the $j counter in sched_edit_2(). This hidden field is returned to the browser immediately after the server determines that the date has been flagged for editing.
		##the presence of the value 'yes' indicates that the date was selected 
		if ($$params{$c_day}[0]=~/yes/)	{
		

			$$r->print("<input type='hidden' name='day' value=$j>");

This is actually the most efficient manner in which to go about making the appropriate date information available in the generated page. The month and year are printed as hidden fields at the beginning of the page, and the actual day involved is printed when the table for a given day is generated. When the submitted page is processed in edit_schedule_proc(), the $new_game statement handle now executes with a date argument that includes the $jth element of the "day" parameter array.
my $res=$$dbh2->execute($next_id,$$params{'month'}[0].'/'.$$params{'day'}[$j].'/'.$$params{'year'}[0],
	@{$$params{'time_'.$j}}[$k],@{$$params{'home_'.$j}}[$k],@{$$params{'away_'.$j}}[$k],
	$$rev_team{@{$$params{'home_'.$j}}[$k]},$$rev_team{@{$$params{'away_'.$j}}[$k]});


Now while this subroutine can function by simply iterating over a pre-determined range of integers like this, that is hardly the most efficient way to go about it. Furthermore, there is no reason to do it that way, because the parameters are now named based on table and row values rather than the day of the month. Given that structure, I can just iterate $j for the number of tables that were generated. The first way I went about this was to print the values of $table as a hidden field named "tables" at the end of the page generation in sched_edit_2(), using the resultant parameter as the upper bound for the loop as the submitted page is processed.

while ($j <= @{$$params{tables}}[0]) 	
As always, however, there is more than one way to do this. As the "day" hidden field is printed once for each table generated, the number of elements in the resultant parameter array is equal to the number of tables. Since assigning an array to a scalar stores the number of elements in the array to the scalar, that scalar could be used to control the execution of the loop, as in
	my $days=@{$$params{'day'}};
	while ($j <= $days)	{
That works, but it presumes at least the presence of a similarly constructed parameter in any submitted page. While that would not be all that big of a deal to implement, the $table scalar is integral to any page generation using edit_table(), and its use is therefore much more straightforward.


The logical next step, of course, is to similarly generalize edit_schedule_proc() into a form capable of handling the output of any page generated with edit_table(). As this chapter is already very long, I will do that as part of one of the chapters that immediately follow, in which I apply what I have just done to the management of teams and players.



Next: Managing Team Records