In the last two chapters, I have created a generic subroutine that generates the table format that I use to display sets of records in a manner that facilitates maintenance of those records, and have generalized the subroutine used to process pages thus generated sufficiently to allow the functionality of that subbroutine to be extended to process new sets of submissions with the incorporation of a well-defined set of variables that customize the execution of the subroutine to process those sets. In this chapter I will be using those two developments to implement a page that will allow the maintenance of player information.
As part of this process, I am going to introduce structures similar to those I used in the last chapter to allow the teams_players() subroutine to generate the appropriate page for either context. This will serve as the basis for further extension of the subroutine in later chapters as I create an interface to manage system tables like event and event_result.
First, however, I want to correct an inappropriately-constructed statement I have on occassion used in previous chapter. Somehow I started using a statement like the following to initialize a set of scalars with the value 0.
my ($a,$b,$c ...)=0;This is wrong. Only the first scalar will hold the value 0, with the remaining initialized with an undefined value. The reason for this should be clear with a modest amount of reflection. The statement above contains a list, but stores only a single value to that list. It is as if I had created an array and only assigned to it a single value; the first element of the array would hold that value and the remainder would be present, but undefined. The correct form of this statement, in the most simple form, is
my ($k,$table)=(0,0);For the most part, no problems resulted from this misconstruction in this application. Incrementing an undefined scalar will, for example, result in that scalar holding the value 1, which would be the same if the scalar had been initialized with the value 0. If the scalar were expected to hold the value 3 on initialization, however, with comparison to other values following, the results would not be as expected. In the context of this subroutine, problems would occur when the scalar was used to construct a string, as in the statements in edit_schedule_proc() that access pertinent parameter values, for example:
@control=@{$$params{'home_'.$j}};
An undefined $j would result in an attempt to access a parameter array keyed to the value "home_'. Of course, the %params hash would not be accessed appropriately, and the operations dependent upon that access would fail. Problems like these, however, would likely be found as the pertinent subroutine was first tested.Returning to the subject at hand, my first step was to modify the menu structure to create player maintenance as an option. To that end, I constructed another menu file to hold the options to be under "Team and Player Maintenance" on the league menu. (The wording of that option, of course, is new; the result of the modification of the second line of la_menu.txt to
Team and Player MaintenanceZzZ/bb_app/league/la-teamThis is just a label, of course. Selection of this option returns the same path information as previously.) The new menu file, la_team_player.txt, currently includes these three lines:
TeamsZzZ/bb_app/league/la-team-tadd PlayersZzZ/bb_app/league/la-team-padd Associate Players with TeamsZzZ/bb_app/league/la-team-associateAs with the other menus, I store the fully-qualified file name to a scalar
my $team_menu_file='/mfs/3/data/www/la_team_player.txt';and use that scalar in the call to construct_menu() that creates the string of html that displays the menu with associated URI's.
my $team_menu=construct_menu($team_menu_file,"80%",$pa_colors,$la_colors);Looking back at the lines in the text file used to create this menu, the last part of each line represents the extra path information that I use to direct server execution in response to any given request. Adhering to the model I have adopted previously, the path information specifies the set of actions that will be performed for the given object. As I have discussed previously, given the form of the pattern specification employed here, care must be taken to avoid specifying a path that will trigger the inadvertent execution of another condition. For example, if the path I had specified for the schedule maintenance option in the league menu included the string la_game_schedule, BB_STACKED as it currently exists would execute both the
if ($path=~/game/)and the
if ($path=~/sched/)conditions within the league() subroutine. This sounds more unwieldy than it actually is, and in many cases a mis-specified string would not create a problem because nothing in the string would result in the execution of any of the conditions within that block. Indeed, layering conditons in the manner in which I have done in BB_STACKED helps to avoid these problems by keeping some strings pertinent to a limited set of contexts. Regardless, there may come a point at which I find it appropriate to tighten matches, as I have done with the top-level matches that are anchored to the beginning of the string. The form in which I specify path information is a natural for a split(), for example, and it may well be that I will ultimately tighten things by specifying that the match be in a specific array element. For now, however, I will simply advise caution.
Once that menu structure is in place, the behavior of the system in the previous chapter can be replicated by the inclusion of the following snippet in the league() subroutine in BB_STACKED.
if ($path=~/team/) {
$$r->print("<center>$team_menu</center>");
if ($path=~/tadd/) {
teams_players($params,$r,$colors,$db);
}
Once the server has been restarted, selection of Team and Player Maintenance will display the new menu,

My next step was to start putting the teams_players() subroutine into a form analogous to that I implemented to process submissions in the previous chapter. First in the process was the creation of the switch structure and the determination of just what is conditional to the context in which the subroutine is being called. As I had defined scalars at the beginning of the subroutine in the previous chapter, it was short work to make that definition contingent upon the calling context.
my (@t_names,@rows);
my ($k,$table)=(0,0);
my ($dbh,$submit);
SWITCH: {
if ($$r->path_info =~ /tadd/) {
##initialize scalars holding widget names for teams table
my $id='team_'.$table;
my $name='name_'.$table;
my $fax='fax_'.$table;
my $c_fname='c_fname_'.$table;
my $c_lname='c_lname_'.$table;
my $address='address_'.$table;
my $city='city_'.$table;
my $state='state_'.$table;
my $zip='zip_'.$table;
##initialize descriptive arrays for teams
my @a=('',$id,'hidden','');
my @b=('Name',$name,'text','');
my @c=('Fax',$fax,'text','');
my @d=('Contact First',$c_fname,'text','');
my @e=('Contact Last',$c_lname,'text','');
my @f=('Address',$address,'text','');
my @g=('City',$city,'text','');
my @h=('State',$state,'text','');
my @i=('Zip',$zip,'text','');
@t_names=(\@a,\@b,\@c,\@d,\@e,\@f,\@g,\@h,\@i);
$submit="<input type='submit' name='submit' value='Submit Team Modifications'>";
$dbh=$$db{'all_teams'};
last SWITCH;
}
}
my $t_res=$$dbh->execute;
There is relatively little new here. Note that in the if() statment I am matching against the output of the path_info method rather than against the contents of a scalar. That is fine here, but once a number of conditions are added I will store that result into a scalar and match against that, thus requiring that the path_info method be executed only once. All of the scalars and arrays holding values unique to this condition are scoped to the block under the if() statement, with only those variables that operate globally scoped at that level. The $submit scalar holds the html string the will print the submit button at the end of the form. As I put the entire submit button definition within the scalar, rather than just the string to be attached to the button value as in the last chapter, that entire sting is returned to the browser and perl is not required to evaluate a scalar embedded within it. As a result, I do not have to put underscores in place of the whitespace in the value label as I did in the last chapter.Again, what I have done here is to move everything unique to the additon of teams to within a conditon in the switch block, this being currently the only condition within that block. After reloading the server with this version the page is generated appropriately.
The next step, of course, is to implement a players maintenance page within this framework. (I have, and probably will continue to, used the terms players and participants interchangably. Strictly speaking I probably should use participants, as umpires and other incidental participants will also be included, but for now I am not going to worry about that. Changing the text displayed at pertinent locations will be a trivial endeavor at a later point.) By far the most of what is involved here revolves around constructing the structures from which the subroutine will generate the output. This continues a general theme in these pages that began with the development of sel_box(), that of separating the generation of output from the data that both controls and is being displayed by that generation.
Beginning at the beginning, the first step was to prepare the various database statements that perform the requisite maintainence operations. As I have done this same set of operations on different tables a couple of times before, I just copied one of those sets and made the appropriate modifications. BB_STACKED now includes the following lines:
##participant statements
##return all information in the participant table
my $all_part=$dbh->prepare("select participant_id,part_fname,part_lname from participant where participant_id <> ' '
order by part_lname,part_fname");
##delete a participant
my $del_part=$dbh->prepare("delete from participant where participant_id=?");
##update a participant record
my $update_part=$dbh->prepare("update participant set part_fname=?,part_lname=? where participant_id=?");
##get the highest participant_id used
my $max_part_id=$dbh->prepare("select max(participant_id) from participant");
##insert a new participant
my $new_part=$dbh->prepare("insert into participant (participant_id,part_fname,part_lname) values (?,?,?)");
Since the participant table has only three columns, these statements are much shorter than those associated with the team table. Note that in the first statement the result set is ordered first by last name, then by first name. The following five lines have also been added to %db_hash:
all_participants=>\$all_part,
delete_participant=>\$del_part,
update_participant=>\$update_part,
last_participant=>\$max_part_id,
new_participant=>\$new_part);
These add references to those prepared statements to the hash.As the teams_players() subroutine is now going to handle the generation of the maintenance pages for both teams and participants, execution is directed there in either context.
if ($path=~/tadd/ or $path=~/padd/) {
teams_players($params,$r,$colors,$db);
}
The task of establishing the items to be defined within the new condition in the switch block is eased by the fact that I have previously defined those items in another context, and by the relative simplicity of the participant table.
if ($$r->path_info =~ /padd/) {
##scalars holding widget names
my $id='part_'.$table;
my $fname='fname_'.$table;
my $lname='lname_'.$table;
##descriptive arrays
my @a=('',$id,'hidden','');
my @b=('First Name',$fname,'text','');
my @c=('Last Name',$lname,'text','');
@t_names=(\@a,\@b,\@c);
$submit="<input type='submit' name='submit' value='Submit Participant Modifications'>";
$dbh=$$db{'all_participants'};
last SWITCH;
}
This is all that is required to generate the desired output page, which looks like this:
Not too shabby, eh? Now I have to add the conditions to the subroutine currently named edit_schedule_proc() (That always feels like I am saying "The artist formerly known as Prince") to allow that subroutine to process the submitted page. Just as I say that, however, I realize that I have forgotten something: the hidden field "task" must also be written conditionally. Therefore, I added this line to the team condition:
$task="<input type='hidden' name='task' value='team'>";and this to the player condition:
$task="<input type='hidden' name='task' value='players'>";and modified the next to the last line in the subroutine to
$$r->print("$task<input type='hidden' name='tables' value=$table>");
Now I am ready to go forward.The modifications to edit_schedule_proc() required to process a submitted page of player information are much like those I made to teams_players(), only more extensive. Only one new scalar was required, that which will serve as the logical variable to flag this context, which I have named $players. Otherwise this is simply a matter of adding another of set of conditions like I first defined for this subroutine in the last chapter. The first group, those global to the subroutine, are as follows:
if (@{$$params{'task'}}[0] =~ /players/) {
$players=1;
$id_len=3;
$del_dbh=$$db{'delete_participant'};
$update_dbh=$$db{'update_participant'};
$last_dbh=$$db{'last_participant'};
$new_dbh=$$db{'new_participant'};
$max_id='998';
$form_action="<form action='/bb_app/league/la-team-padd' method='post'>";
$submit_value=qq/Re-Display_Players/;
last SWITCH;
}
Once within the while() loop that iterates over the number of tables, an appropriate parameter array can be specified as the @control array,
elsif ($players) {
@control=@{$$params{'fname_'.$j}} if @{$$params{'fname_'.$j}};
}
and within the loop that iterates over the elements of the parameter arrays the @update array can be defined and the appropriate value stored in the $id scalar.
if ($players) {
@update=(@{$$params{'fname_'.$j}}[$k],@{$$params{'lname_'.$j}}[$k],
@{$$params{'part_'.$j}}[$k]);
$id=@{$$params{'part_'.$j}}[$k];
last SWITCH;
}
Finally, the @new array is defined within the code block executed if this is a new record.
elsif ($players) {
@new=($next_id,$$params{'fname_'.$j}[$k],
$$params{'lname_'.$j}[$k]);
}
All that remains now is to make sure that execution is directed into this subroutine when appropriate. This was just a matter of adding the appropriate condition to those which trigger this subroutine within the store condition in the league() subroutine in BB_STACKED.
elsif ($$params{'task'}[0] =~ /schedule/
or $$params{'task'}[0] =~ /team/
or $$params{'task'}[0] =~ /players/) {
edit_schedule_proc(@pass);
}
With these changes in place and the server restarted, a submitted page of player information is processed appropriately.Even with the restructuring of teams_players() early in this chapter, this has been by far the easiest addition of a system component to date. That, of course, is the point of creating generalized subroutines that can be called in different contexts. At the same time, the current structure could grow unwieldy if I were to stick more than another condition or two into the mix. I have been starting to think about manners in which to achieve the same end in a less wordy fashion, and when I start using this set of subroutines to maintain system tables I will likely implement something in this regard. But that is down the road a bit.
In the next chapter, I will implement a page on which players can be associated with teams.
NOTE: I frequently break up long lines to allow browsers to display them without stretching the page. These lines are not broken in the actual code. Depending on the individual line and the operating system, the specific line may not work if used in the displayed format, with a line feed character at the break point. In general in linux and unix, commands are continued across multiple lines with the "\" character. As an example, the elsif statement above would be written as
elsif ($$params{'task'}[0] =~ /schedule/ \
or $$params{'task'}[0] =~ /team/ \
or $$params{'task'}[0] =~ /players/)
if the command was split across multiple lines in the code.