[system] / trunk / webwork-modperl / lib / WeBWorK / DB.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork-modperl/lib/WeBWorK/DB.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 956 - (view) (download) (as text)

1 : sh002i 775 ################################################################################
2 :     # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
3 :     # $Id$
4 :     ################################################################################
5 :    
6 :     package WeBWorK::DB;
7 :    
8 :     =head1 NAME
9 :    
10 : sh002i 956 WeBWorK::DB - interface with the WeBWorK databases.
11 : sh002i 775
12 : sh002i 956 =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 : sh002i 775 =cut
99 :    
100 :     use strict;
101 :     use warnings;
102 : sh002i 904 use Data::Dumper;
103 : sh002i 775 use WeBWorK::Utils qw(runtime_use);
104 :    
105 : sh002i 798 use constant TABLES => qw(password permission key user set set_user problem problem_user);
106 : sh002i 775
107 :     ################################################################################
108 :     # constructor
109 :     ################################################################################
110 :    
111 : sh002i 956 =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 : sh002i 775 sub new($$) {
122 : sh002i 814 my ($invocant, $ce) = @_;
123 : sh002i 775 my $class = ref($invocant) || $invocant;
124 : sh002i 798 my $self = {};
125 : sh002i 931 bless $self, $class; # bless this here so we can pass it to the schema
126 : sh002i 775
127 :     # load the modules required to handle each table, and create driver
128 :     foreach my $table (TABLES) {
129 : sh002i 798 unless (defined $ce->{dbLayout}->{$table}) {
130 : sh002i 931 warn "ignoring table $table: layout not specified in dbLayout"; # ***
131 : sh002i 798 next;
132 :     }
133 : sh002i 775
134 :     my $layout = $ce->{dbLayout}->{$table};
135 : sh002i 798 my $record = $layout->{record};
136 : sh002i 775 my $schema = $layout->{schema};
137 :     my $driver = $layout->{driver};
138 :     my $source = $layout->{source};
139 : sh002i 808 my $params = $layout->{params};
140 : sh002i 775
141 : sh002i 798 runtime_use($record);
142 :     runtime_use($schema);
143 :     runtime_use($driver);
144 : sh002i 931 $self->{$table} = $schema->new(
145 :     $self,
146 :     $driver->new($source, $params),
147 :     $table,
148 :     $record,
149 :     $params
150 :     );
151 : sh002i 775 }
152 :    
153 :     return $self;
154 :     }
155 :    
156 :     ################################################################################
157 :     # password functions
158 :     ################################################################################
159 :    
160 :     sub listPasswords($) {
161 :     my ($self) = @_;
162 : sh002i 808 return map { $_->[0] }
163 :     $self->{password}->list(undef);
164 : sh002i 775 }
165 :    
166 : sh002i 808 sub addPassword($$) {
167 : sh002i 775 my ($self, $Password) = @_;
168 : sh002i 808 die "addPassword failed: user ", $Password->user_id, " does not exist.\n"
169 : sh002i 775 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 : sh002i 808 return map { $_->[0] }
195 :     $self->{permission}->list(undef);
196 : sh002i 775 }
197 :    
198 : sh002i 808 sub addPermissionLevel($$) {
199 : sh002i 775 my ($self, $PermissionLevel) = @_;
200 : sh002i 808 die "addPermissionLevel failed: user ", $PermissionLevel->user_id, " does not exist.\n"
201 : sh002i 775 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 : sh002i 808 return map { $_->[0] }
227 :     $self->{key}->list(undef);
228 : sh002i 775 }
229 :    
230 : sh002i 808 sub addKey($$) {
231 : sh002i 775 my ($self, $Key) = @_;
232 : sh002i 808 die "addKey failed: user ", $Key->user_id, " does not exist.\n"
233 : sh002i 775 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 : sh002i 808 return map { $_->[0] }
259 :     $self->{user}->list(undef);
260 : sh002i 775 }
261 :    
262 : sh002i 808 sub addUser($$) {
263 : sh002i 775 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 : sh002i 808 return map { $_->[0] }
294 :     $self->{set}->list(undef);
295 : sh002i 775 }
296 :    
297 : sh002i 808 sub addGlobalSet($$) {
298 : sh002i 775 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 : sh002i 909 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 : sh002i 775 my ($self, $userID) = @_;
333 : sh002i 808 return map { $_->[1] } # extract set_id
334 :     $self->{set_user}->list($userID, undef);
335 : sh002i 775 }
336 :    
337 : sh002i 808 sub addUserSet($$) {
338 : sh002i 775 my ($self, $UserSet) = @_;
339 : sh002i 808 die "addUserSet failed: user ", $UserSet->user_id, " does not exist.\n"
340 : sh002i 775 unless $self->{user}->exists($UserSet->user_id);
341 : sh002i 808 die "addUserSet failed: set ", $UserSet->set_id, " does not exist.\n"
342 : sh002i 775 unless $self->{set}->exists($UserSet->set_id);
343 :     return $self->{set_user}->add($UserSet);
344 :     }
345 :    
346 : sh002i 909 sub getUserSet($$$) {
347 : sh002i 775 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 : sh002i 909 sub deleteUserSet($$$) {
357 : sh002i 775 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 : sh002i 953 #grep { $_->[0] eq $setID }
371 :     $self->{problem}->list($setID, undef);
372 : sh002i 775 }
373 :    
374 : sh002i 808 sub addGlobalProblem($$) {
375 : sh002i 775 my ($self, $GlobalProblem) = @_;
376 : sh002i 808 die "addGlobalProblem failed: set ", $GlobalProblem->set_id, " does not exist.\n"
377 : sh002i 775 unless $self->{set}->exists($GlobalProblem->set_id);
378 :     return $self->{problem}->add($GlobalProblem);
379 :     }
380 :    
381 :     sub getGlobalProblem($$$) {
382 :     my ($self, $setID, $problemID) = @_;
383 : sh002i 916 return $self->{problem}->get($setID, $problemID);
384 : sh002i 775 }
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 : sh002i 923 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 : sh002i 775 sub listUserProblems($$$) {
409 :     my ($self, $userID, $setID) = @_;
410 : sh002i 923 return map { $_->[2] } # extract problem_id
411 : sh002i 808 $self->{problem_user}->list($userID, $setID, undef);
412 : sh002i 775 }
413 :    
414 : sh002i 808 sub addUserProblem($$) {
415 : sh002i 775 my ($self, $UserProblem) = @_;
416 : sh002i 808 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 : sh002i 914 unless $self->{problem}->exists($UserProblem->set_id, $UserProblem->problem_id);
420 : sh002i 775 return $self->{problem_user}->add($UserProblem);
421 :     }
422 :    
423 : sh002i 798 sub getUserProblem($$$$) {
424 : sh002i 775 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 : sh002i 798 sub deleteUserProblem($$$$) {
434 : sh002i 775 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 : sh002i 798 sub getGlobalUserSet($$$) {
443 :     my ($self, $userID, $setID) = @_;
444 : sh002i 814 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 : sh002i 798 }
456 : sh002i 775
457 :     ################################################################################
458 :     # problem+problem_user functions
459 :     ################################################################################
460 :    
461 : sh002i 798 sub getGlobalUserProblem($$$$) {
462 :     my ($self, $userID, $setID, $problemID) = @_;
463 : sh002i 814 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 : sh002i 798 }
475 : sh002i 775
476 : sh002i 808 ################################################################################
477 :     # debugging
478 :     ################################################################################
479 :    
480 :     sub dumpDB($$) {
481 :     my ($self, $table) = @_;
482 :     return $self->{$table}->dumpDB();
483 :     }
484 :    
485 : sh002i 775 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9