################################################################################ # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project # $Id$ ################################################################################ package WeBWorK::ContentGenerator; =head1 NAME WeBWorK::ContentGenerator - base class for modules that generate page content. =cut use strict; use warnings; use Apache::Constants qw(:common); use CGI qw(); use URI::Escape; use WeBWorK::Authz; use WeBWorK::DB; use WeBWorK::Utils qw(readFile); ################################################################################ # This is a very unruly file, so I'm going to use very large comments to divide # it into logical sections. ################################################################################ # new(Apache::Request, WeBWorK::CourseEnvironment) - create a new instance of a # content generator. Usually only called by the dispatcher, although one might # be able to use it for things like "sub-requests". Uh... uh... I have to think # about that one. The dispatcher uses this idiom: # # WeBWorK::ContentGenerator::WHATEVER->new($r, $ce)->go(@whatever); # # and throws away the result ;) # sub new($$$$) { my ($invocant, $r, $ce, $db) = @_; my $class = ref($invocant) || $invocant; my $self = { r => $r, ce => $ce, db => $db, authz => WeBWorK::Authz->new($r, $ce, $db), noContent => undef, # false }; bless $self, $class; return $self; } ################################################################################ # Invocation and template processing ################################################################################ # go(@otherArguments) - render a page, using methods from the particular # subclass of ContentGenerator. @otherArguments is passed to each method, so # that the dispatcher can pass CG-specific data. The order of calls looks like # this: # # * &pre_header_initialize - give subclasses a chance to do initialization # necessary for generating the HTTP header. # * &header - this class provides a standard HTTP header with Content-Type # text/html. Subclasses are welcome to overload this for things like # an image-creation content generator or a PDF generator. # In addition, if &header returns a value, that will be the value # returned by the entire PerlHandler. # * &initialize - let subclasses do post-header initialization. # * any "template escapes" defined in the system template and supported by # the subclass. # (if &content exists on a content generator, it is called # and no template processing occurs.) # # If &pre_header_initialize or &header sets $self->{noContent} to a true value, # &initialize will not be run and the content or template processing code # will not be executed. This is probably only desirable if a redirect has been # issued. sub go { my $self = shift; my $r = $self->{r}; my $courseEnvironment = $self->{ce}; my $returnValue = OK; $self->pre_header_initialize(@_) if $self->can("pre_header_initialize"); my $headerReturn = $self->header(@_); $returnValue = $headerReturn if defined $headerReturn; return $returnValue if $r->header_only or $self->{noContent}; $self->initialize(@_) if $self->can("initialize"); # A content generator will have a "content" method if it does not # wish to be passed through template processing, but wishes to be # completely responsible for it's own output. if ($self->can("content")) { $self->content(@_); } else { $self->template($courseEnvironment->{templates}->{system}, @_); } return $returnValue; } # template(STRING, @otherArguments) - parse a template, looking for escapes of # the form and calling a member function NAME # (if available) for each NAME. The escapes are called like: # # $self->NAME(@otherArguments, \%escapeArguments) # # where @otherArguments originates in the dispatcher and %escapeArguments is # parsed out of the escape itself (i.e. ARG1 => FOO, ARG2 => BAR) # sub template { my ($self, $templateFile) = (shift, shift); my $r = $self->{r}; my $courseEnvironment = $self->{ce}; my @ifstack = (1); # Start off in printing mode # say $ifstack[-1] to get the result of the last <#!--if--> # so even though the variable $/ APPEARS to contain a newline, #