Win32::ASP::DBRecordGroup - an abstract parent class for representing groups of database records |
Win32::ASP::DBRecordGroup - an abstract parent class for representing groups of database records
The main purpose of Win32::ASP::DBRecordGroup
is to be subclassed. It implements a generic set
of default behavior for the purpose of reading a group of records from a table, displaying that
group of records in an HTML table, and allowing edits to that group if applicable. All
Win32::ASP::DBRecordGroup
classes rely upon a Win32::ASP::DBRecord
class that implements the
underlying record.
The internal data structure of a instance of Win32::ASP::DBRecordGroup
consists of the
following elements, all optional:
Class methods were used to implement access to class properties. Since Perl doesn't enforce a
distinction between class and instance methods, these methods can be called on both class names
and on instances of the class, which ends up being incredibly useful. I strongly recommend against
ever calling these methods using subroutine notation (i.e. &_DB
or &_PRIMARY_KEY
).
Perl methods execute in the namespace in which they were defined, which means that if you further
subclass and define a new implementation of those methods, any methods you don't override that were
in the parent class will call the parent class's versions of those methods. That's bad. Always
call these methods with the arrow notation and you'll be safe.
These class methods will be overridden in every child class.
_DB
method should return the Win32::ASP::DB
(or subclass there-of) object that is used
for database access. A frequent implementation looks like this:
sub _DB { return $main::TheDB; }
_TYPE
method should return the name of the Win32::ASP::DBRecord
subclass that implements
the underlying records for this DBRecordGroup object.
_QUERY_METAS
method should return a reference to a hash of subroutines that implement more
complicated querying behavior. The subroutines will be passed the appropriate query specification
and should return legal SQL for inclusion within a query. Of note, for performance reasons the
method is usually implemented like so:
sub _QUERY_METAS { return $MyStuff::MyRecordGroup::query_metas; }
$MyStuff::MyRecordGroup::query_metas = {
Status => sub { my($values) = @_; $values or return; return "Status LIKE '[$values]'"; },
};
The above Status
query_meta presumes a single character status field and that the passed value
indicates a list of desired status values. For instance, the status values might be N
for new
records, P
for in process records, and F
for finished records. Using the above query_meta,
a user could query for Status=NP
, which would indicate they desired new and in process records.
They could get the same results by querying for !F
.
Note that there is a security hole in the above code - if a user queries for Status=N] GO
do_something_ugly_here
, they will effectively ``jump'' out of the LIKE statement and may be able to
execute arbitrary SQL code. Defending against this possibility is left as an excercise for the
reader.
These class methods can be overriden in a child class.
_MIN_COUNT
method defines the minimum number of records to display when allowing the user
to edit a group of records.
_NEW_COUNT
method defines the minimum number of blank records to display when allowing the
user to edit a group of records.
This is a basic new
method. It simply creates an anonymous hash and returns a reference. The
new
method is not responsible for reading data or anything else. Just creating a new record
group object. You will probably not need to override this method.
This is the heart of the DBRecordGroup class. The method is passed three parameters: a reference to a hash of constraints, a string specifying how to order the results, and a string specifying a list of columns to retrieve.
The hash of constraints should be indexed on the field name (or query_meta name). If the index
references a query_meta, the value will be passed to the query_meta subroutine. If the index
doesn't reference a query_meta, the field will be tested for equality with the specified value.
The specified value will be formatted by the field's as_sql
method before being included in the
SQL. All of the constraints will be ANDed together to form the WHERE
clause in the SQL.
The order string should be a comma separated list of field names. Bare field names will be sorted in ascending order; field names preceded by a minus sign will be sorted in descending order.
The columns string should be one of three things: empty, an asterisk, or a comma separated list of
field names. If the string is absent or an asterisk, the query will retrieve all the columns If
a comma separated list is specified, the query will only retrieve those columns. The advantage of
this is that queries can be optimized to return only the information that will be displayed to the
user. Keep in mind, however, that if the DBRecord object requires specific fields in order to
make determinations about viewability or the like, those columns need to be specified in the
column list. As a result, query
is frequently overriden to automatically append those columns
to the column list before call SUPER::query
.
After setting up the SQL for the query, query
calls exec_sql
on the appropriate
Win32::ASP::DB object (determined by calling $self->_DB
). It then iterates over the result
set returned, creating new DBRecord objects of the appropriate class and calling _read
on them.
The call to _read
is wrapped in a try
block - if the user doesn't have rights to view the
record, _read
will throw an exception. That exception will be trapped and the record won't be
be appended to the array of DBRecord objects.
Another common modification to query
involves adding constraints to all queries to explicitly
call query_metas that are responsible for ascertaining viewability. This can greatly improve
performance - if the user asks for every record in the system, the query handles the weeding out
of those records that are not viewable, rather than reading the data and letting _read
throw an
exception. Again, this can be easily handled by overriding the method and then calling
SUPER::query
.
Win32::ASP::DBRecordGroup - an abstract parent class for representing groups of database records |