[system] / trunk / webwork2 / lib / WeBWorK / DB.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/DB.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 958 - (download) (as text) (annotate)
Fri May 30 21:37:15 2003 UTC (9 years, 11 months ago) by sh002i
File size: 14332 byte(s)
fixed several stupid errors.
-sam

    1 ################################################################################
    2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
    3 # $Id$
    4 ################################################################################
    5 
    6 package WeBWorK::DB;
    7 
    8 =head1 NAME
    9 
   10 WeBWorK::DB - interface with the WeBWorK databases.
   11 
   12 =head1 DESCRIPTION
   13 
   14 WeBWorK::DB provides a consistent interface to a number of database backends.
   15 Access and modification functions are provided for each logical table used by
   16 the webwork system. The particular backend ("schema" and "driver"), record
   17 class, data source, and additional parameters are specified by the %dbLayout
   18 hash in the course environment.
   19 
   20 =head1 ARCHITECTURE
   21 
   22 The new database system uses a three-tier architecture to insulate each layer
   23 from the adjacent layers.
   24 
   25 =head2 Top Layer: DB
   26 
   27 The top layer of the architecture is the DB module. It provides the methods
   28 listed below, and uses schema modules (via tables) to implement those methods.
   29 
   30                / list* exists* add* get* put* delete* \               <- api
   31  +------------------------------------------------------------------+
   32  |                                DB                                |
   33  +------------------------------------------------------------------+
   34   \ password permission key user set set_user problem problem_user /  <- tables
   35 
   36 =head2 Middle Layer: Schemas
   37 
   38 The middle layer of the architecture is provided by one or more schema modules.
   39 They are called "schema" modules because they control the structure of the data
   40 for a table. This includes odd things like the way multiple tables are encoded
   41 in a single hash in the WWHash schema, and the encoding scheme used.
   42 
   43 The schema modules provide an API that matches the requirements of the DB
   44 layer, on a per-table basis. Each schema module has a style that determines
   45 which drivers it can interface with. For example, WW1Hash is a "hash" style
   46 schema. SQL is a "dbi" style schema.
   47 
   48 =head3 Examples
   49 
   50 Both WeBWorK 1.x and 2.x courses use:
   51 
   52   / password  permission  key \        / user \      <- tables provided
   53  +-----------------------------+  +----------------+
   54  |          Auth1Hash          |  | Classlist1Hash |
   55  +-----------------------------+  +----------------+
   56              \ hash /                  \ hash /      <- driver style required
   57 
   58 WeBWorK 1.x courses also use:
   59 
   60   / set_user problem_user \       / set problem \
   61  +-------------------------+  +---------------------+
   62  |         WW1Hash         |  | GlobalTableEmulator |
   63  +-------------------------+  +---------------------+
   64            \ hash /                   \ null /
   65 
   66 The GlobalTableEmulator schema emulates the global set and problem tables using
   67 data from the set_user and problem_user tables.
   68 
   69 WeBWorK 2.x courses also use:
   70 
   71   / set set_user problem problem_user \
   72  +-------------------------------------+
   73  |               WW2Hash               |
   74  +-------------------------------------+
   75                  \ hash /
   76 
   77 =head2 Bottom Layer: Drivers
   78 
   79 Driver modules implement a style for a schema. They provide physical access to
   80 a data source containing the data for a table. The style of a driver determines
   81 what methods it provides. All drivers provide connect(MODE) and disconnect()
   82 methods. A hash style driver provides a hash() method which returns the tied
   83 hash. A dbi style driver provides a handle() method which returns the DBI
   84 handle.
   85 
   86 =head3 Examples
   87 
   88   / hash \    / hash \    / hash \  <- style
   89  +--------+  +--------+  +--------+
   90  |   DB   |  |  GDBM  |  |   DB3  |
   91  +--------+  +--------+  +--------+
   92 
   93   / dbi \    / ldap \
   94  +-------+  +--------+
   95  |  SQL  |  |  LDAP  |
   96  +-------+  +--------+
   97 
   98 =cut
   99 
  100 use strict;
  101 use warnings;
  102 use Data::Dumper;
  103 use WeBWorK::Utils qw(runtime_use);
  104 
  105 use constant TABLES => qw(password permission key user set set_user problem problem_user);
  106 
  107 ################################################################################
  108 # constructor
  109 ################################################################################
  110 
  111 =head1 CONSTRUCTOR
  112 =over
  113 =item new (ENVIRONMENT)
  114 
  115 The C<new> method creates a DB object and brings up the underlying schema/driver
  116 structure according to the C<%dbLayout> hash in the ENVIRONMENT. Environment is
  117 a C<WeBWorK::CourseEnvironment> object.
  118 
  119 =cut
  120 
  121 sub new($$) {
  122   my ($invocant, $ce) = @_;
  123   my $class = ref($invocant) || $invocant;
  124   my $self = {};
  125   bless $self, $class; # bless this here so we can pass it to the schema
  126 
  127   # load the modules required to handle each table, and create driver
  128   foreach my $table (TABLES) {
  129     unless (defined $ce->{dbLayout}->{$table}) {
  130       warn "ignoring table $table: layout not specified in dbLayout"; # ***
  131       next;
  132     }
  133 
  134     my $layout = $ce->{dbLayout}->{$table};
  135     my $record = $layout->{record};
  136     my $schema = $layout->{schema};
  137     my $driver = $layout->{driver};
  138     my $source = $layout->{source};
  139     my $params = $layout->{params};
  140 
  141     runtime_use($record);
  142     runtime_use($schema);
  143     runtime_use($driver);
  144     $self->{$table} = $schema->new(
  145       $self,
  146       $driver->new($source, $params),
  147       $table,
  148       $record,
  149       $params
  150     );
  151   }
  152 
  153   return $self;
  154 }
  155 
  156 ################################################################################
  157 # password functions
  158 ################################################################################
  159 
  160 sub listPasswords($) {
  161   my ($self) = @_;
  162   return map { $_->[0] }
  163     $self->{password}->list(undef);
  164 }
  165 
  166 sub addPassword($$) {
  167   my ($self, $Password) = @_;
  168   die "addPassword failed: user ", $Password->user_id, " does not exist.\n"
  169     unless $self->{user}->exists($Password->user_id);
  170   return $self->{password}->add($Password);
  171 }
  172 
  173 sub getPassword($$) {
  174   my ($self, $userID) = @_;
  175   return $self->{password}->get($userID);
  176 }
  177 
  178 sub putPassword($$) {
  179   my ($self, $Password) = @_;
  180   return $self->{password}->put($Password);
  181 }
  182 
  183 sub deletePassword($$) {
  184   my ($self, $userID) = @_;
  185   return $self->{password}->delete($userID);
  186 }
  187 
  188 ################################################################################
  189 # permission functions
  190 ################################################################################
  191 
  192 sub listPermissionLevels($) {
  193   my ($self) = @_;
  194   return map { $_->[0] }
  195     $self->{permission}->list(undef);
  196 }
  197 
  198 sub addPermissionLevel($$) {
  199   my ($self, $PermissionLevel) = @_;
  200   die "addPermissionLevel failed: user ", $PermissionLevel->user_id, " does not exist.\n"
  201     unless $self->{user}->exists($PermissionLevel->user_id);
  202   return $self->{permission}->add($PermissionLevel);
  203 }
  204 
  205 sub getPermissionLevel($$) {
  206   my ($self, $userID) = @_;
  207   return $self->{permission}->get($userID);
  208 }
  209 
  210 sub putPermissionLevel($$) {
  211   my ($self, $PermissionLevel) = @_;
  212   return $self->{permission}->put($PermissionLevel);
  213 }
  214 
  215 sub deletePermissionLevel($$) {
  216   my ($self, $userID) = @_;
  217   return $self->{permission}->delete($userID);
  218 }
  219 
  220 ################################################################################
  221 # key functions
  222 ################################################################################
  223 
  224 sub listKeys($) {
  225   my ($self) = @_;
  226   return map { $_->[0] }
  227     $self->{key}->list(undef);
  228 }
  229 
  230 sub addKey($$) {
  231   my ($self, $Key) = @_;
  232   die "addKey failed: user ", $Key->user_id, " does not exist.\n"
  233     unless $self->{user}->exists($Key->user_id);
  234   return $self->{key}->add($Key);
  235 }
  236 
  237 sub getKey($$) {
  238   my ($self, $userID) = @_;
  239   return $self->{key}->get($userID);
  240 }
  241 
  242 sub putKey($$) {
  243   my ($self, $Key) = @_;
  244   return $self->{key}->put($Key);
  245 }
  246 
  247 sub deleteKey($$) {
  248   my ($self, $userID) = @_;
  249   return $self->{key}->delete($userID);
  250 }
  251 
  252 ################################################################################
  253 # user functions
  254 ################################################################################
  255 
  256 sub listUsers($) {
  257   my ($self) = @_;
  258   return map { $_->[0] }
  259     $self->{user}->list(undef);
  260 }
  261 
  262 sub addUser($$) {
  263   my ($self, $User) = @_;
  264   return $self->{user}->add($User);
  265 }
  266 
  267 sub getUser($$) {
  268   my ($self, $userID) = @_;
  269   return $self->{user}->get($userID);
  270 }
  271 
  272 sub putUser($$) {
  273   my ($self, $User) = @_;
  274   return $self->{user}->put($User);
  275 }
  276 
  277 sub deleteUser($$) {
  278   my ($self, $userID) = @_;
  279   $self->deletePassword($userID);
  280   $self->deletePermissionLevel($userID);
  281   $self->deleteKey($userID);
  282   $self->deleteUserSet($userID, $_)
  283     foreach $self->listUsers();
  284   return $self->{user}->delete($userID);
  285 }
  286 
  287 ################################################################################
  288 # set functions
  289 ################################################################################
  290 
  291 sub listGlobalSets($) {
  292   my ($self) = @_;
  293   return map { $_->[0] }
  294     $self->{set}->list(undef);
  295 }
  296 
  297 sub addGlobalSet($$) {
  298   my ($self, $GlobalSet) = @_;
  299   return $self->{set}->add($GlobalSet);
  300 }
  301 
  302 sub getGlobalSet($$) {
  303   my ($self, $setID) = @_;
  304   return $self->{set}->get($setID);
  305 }
  306 
  307 sub putGlobalSet($$) {
  308   my ($self, $GlobalSet) = @_;
  309   return $self->{set}->put($GlobalSet);
  310 }
  311 
  312 sub deleteGlobalSet($$) {
  313   my ($self, $setID) = @_;
  314   $self->deleteGlobalProblem($setID, $_)
  315     foreach $self->listGlobalProblems($setID);
  316   $self->deleteUserSet($_, $setID)
  317     foreach $self->listUsers();
  318   return $self->{set}->delete($setID);
  319 }
  320 
  321 ################################################################################
  322 # set_user functions
  323 ################################################################################
  324 
  325 sub listSetUsers($$) {
  326   my ($self, $setID) = @_;
  327   return map { $_->[0] } # extract user_id
  328     $self->{set_user}->list(undef, $setID);
  329 }
  330 
  331 sub listUserSets($$) {
  332   my ($self, $userID) = @_;
  333   return map { $_->[1] } # extract set_id
  334     $self->{set_user}->list($userID, undef);
  335 }
  336 
  337 sub addUserSet($$) {
  338   my ($self, $UserSet) = @_;
  339   die "addUserSet failed: user ", $UserSet->user_id, " does not exist.\n"
  340     unless $self->{user}->exists($UserSet->user_id);
  341   die "addUserSet failed: set ", $UserSet->set_id, " does not exist.\n"
  342     unless $self->{set}->exists($UserSet->set_id);
  343   return $self->{set_user}->add($UserSet);
  344 }
  345 
  346 sub getUserSet($$$) {
  347   my ($self, $userID, $setID) = @_;
  348   return $self->{set_user}->get($userID, $setID);
  349 }
  350 
  351 sub putUserSet($$) {
  352   my ($self, $UserSet) = @_;
  353   return $self->{set_user}->put($UserSet);
  354 }
  355 
  356 sub deleteUserSet($$$) {
  357   my ($self, $userID, $setID) = @_;
  358   $self->deleteUserProblem($userID, $setID, $_)
  359     foreach $self->listUserProblems($userID, $setID);
  360   return $self->{set_user}->delete($userID, $setID);
  361 }
  362 
  363 ################################################################################
  364 # problem functions
  365 ################################################################################
  366 
  367 sub listGlobalProblems($$) {
  368   my ($self, $setID) = @_;
  369   return map { $_->[1] }
  370     #grep { $_->[0] eq $setID }
  371       $self->{problem}->list($setID, undef);
  372 }
  373 
  374 sub addGlobalProblem($$) {
  375   my ($self, $GlobalProblem) = @_;
  376   die "addGlobalProblem failed: set ", $GlobalProblem->set_id, " does not exist.\n"
  377     unless $self->{set}->exists($GlobalProblem->set_id);
  378   return $self->{problem}->add($GlobalProblem);
  379 }
  380 
  381 sub getGlobalProblem($$$) {
  382   my ($self, $setID, $problemID) = @_;
  383   return $self->{problem}->get($setID, $problemID);
  384 }
  385 
  386 sub putGlobalProblem($$) {
  387   my ($self, $GlobalProblem) = @_;
  388   return $self->{problem}->put($GlobalProblem);
  389 }
  390 
  391 sub deleteGlobalProblem($$$) {
  392   my ($self, $setID, $problemID) = @_;
  393   $self->deleteUserProblem($_, $setID, $problemID)
  394     foreach $self->listUsers();
  395   return $self->{problem}->delete($setID, $problemID);
  396 }
  397 
  398 ################################################################################
  399 # problem_user functions
  400 ################################################################################
  401 
  402 sub listProblemUsers($$$) {
  403   my ($self, $setID, $problemID) = @_;
  404   return map { $_->[0] } # extract user_id
  405     $self->{problem_user}->list(undef, $setID, $problemID);
  406 }
  407 
  408 sub listUserProblems($$$) {
  409   my ($self, $userID, $setID) = @_;
  410   return map { $_->[2] } # extract problem_id
  411     $self->{problem_user}->list($userID, $setID, undef);
  412 }
  413 
  414 sub addUserProblem($$) {
  415   my ($self, $UserProblem) = @_;
  416   die "addUserProblem failed: user set ", $UserProblem->set_id, " does not exist.\n"
  417     unless $self->{set_user}->exists($UserProblem->user_id, $UserProblem->set_id);
  418   die "addUserProblem failed: problem ", $UserProblem->problem_id, " does not exist.\n"
  419     unless $self->{problem}->exists($UserProblem->set_id, $UserProblem->problem_id);
  420   return $self->{problem_user}->add($UserProblem);
  421 }
  422 
  423 sub getUserProblem($$$$) {
  424   my ($self, $userID, $setID, $problemID) = @_;
  425   return $self->{problem_user}->get($userID, $setID, $problemID);
  426 }
  427 
  428 sub putUserProblem($$) {
  429   my ($self, $UserProblem) = @_;
  430   return $self->{problem_user}->put($UserProblem);
  431 }
  432 
  433 sub deleteUserProblem($$$$) {
  434   my ($self, $userID, $setID, $problemID) = @_;
  435   return $self->{problem_user}->delete($userID, $setID, $problemID);
  436 }
  437 
  438 ################################################################################
  439 # set+set_user functions
  440 ################################################################################
  441 
  442 sub getGlobalUserSet($$$) {
  443   my ($self, $userID, $setID) = @_;
  444   my $UserSet = $self->getUserSet($userID, $setID);
  445   return unless $UserSet;
  446   my $GlobalSet = $self->getGlobalSet($setID);
  447   if ($GlobalSet) {
  448     foreach ($UserSet->FIELDS()) {
  449       next unless $GlobalSet->can($_);
  450       next if $UserSet->$_();
  451       $UserSet->$_($GlobalSet->$_());
  452     }
  453   }
  454   return $UserSet;
  455 }
  456 
  457 ################################################################################
  458 # problem+problem_user functions
  459 ################################################################################
  460 
  461 sub getGlobalUserProblem($$$$) {
  462   my ($self, $userID, $setID, $problemID) = @_;
  463   my $UserProblem = $self->getUserProblem($userID, $setID, $problemID);
  464   return unless $UserProblem;
  465   my $GlobalProblem = $self->getGlobalProblem($setID, $problemID);
  466   if ($GlobalProblem) {
  467     foreach ($UserProblem->FIELDS()) {
  468       next unless $GlobalProblem->can($_);
  469       next if $UserProblem->$_();
  470       $UserProblem->$_($GlobalProblem->$_());
  471     }
  472   }
  473   return $UserProblem;
  474 }
  475 
  476 ################################################################################
  477 # enforcement
  478 ################################################################################
  479 
  480 ################################################################################
  481 # debugging
  482 ################################################################################
  483 
  484 sub dumpDB($$) {
  485   my ($self, $table) = @_;
  486   return $self->{$table}->dumpDB();
  487 }
  488 
  489 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9