Manual:ORMTable

This page documents the DBDataObject class of the Education Program extension.

Rationale
Often when creating a new database table, you have a class corresponding to a row in this table. This class then contains various database interaction methods as well as logic specific to its type. The database interaction code is often similar and can to a large degree be abstracted out, preventing lots of manual object to table mappings, as well as increase consistency by having the same base interfaces for all classes. This class does this abstraction by building upon MediaWikis database abstraction layer and is conceptually similar to PEARs DB_DataObject class. The main goals of this class are making interaction with the database less cumbersome and more maintainable in an as simple pragmatic fashion while retaining flexibility. It is meant for use where the relation between a class and it's table is "simple". It is not applicable for tables primarily linking data or in situations where many joins are needed.

Implementation
An instance of a deriving class represents a single row in the associated table. Static methods on the class allow for interaction with this table not limited to a single row. Deriving classes can implement or override methods to provide table specific info such as fields and their types. Deriving classes are registered in a global var together with their table and field prefixes, which are never needed when interacting with the class.

Requirements

 * MediaWiki 1.16 or later (I think), tested with 1.18 and trunk
 * PHP 5.3 or later - Makes heavy use of Late Static Bindings

Usage
Methods that need to be implemented:


 * getDBTable - Returns the name of the database table objects of this type are stored in. This allows for never having to specify the table when interacting with a DBDataObject (unless you do joins).
 * getFieldPrefix - Return db field prefix. This is the only place the prefix needs to be specified.
 * getFieldTypes - Returns an array with the fields and their types this object contains.

Methods that are commonly overridden:


 * getDefaults - returns default values for zero or more of the fields. This can be used to initialize new objects and feed them to stuff like forms.
 * remove - deleted the object.
 * insert - insert the object.
 * saveExisting - update the object.
 * loadSummaryFields - computes and sets the summary fields (see summary field section)
 * getSummaryFields - returns the names of the summary fields

Main instance methods
These are the core methods you are likely to have use for on instances.

getField
Returns the value of a set field.

Args:
 * $name - the name of the field to get. Field name without prefix.
 * $default - value to use when the field is not set. When null (=default) the function will complain if the field is not loaded.

Usage:

Returns: mixed, whatever the field type is. The class makes sure that fields are of the right type, so if an int field got set to user input '1', it'll be an int, not a string. Types include int, float, string, array, blob and boolean.

getFields
Returns the set fields.

Usage:

Returns

setField
Sets the value of a field.

Args:
 * $name - the name of the field to set. Field name without prefix.
 * $value - value to set. Mixed. Function takes care of type conversions. ie an int field that gets passed '42' (string) will end up with 42 (int).

Usage:

setFields
Sets the value of a set of fields.

Args:
 * $fields - the values to set. Keys are field names, values are the values. Field names without prefix.
 * $override - Boolean, optional, true by default. If fields that are already set should be set to the newly provided values.

Usage:

save
Stores the object in the db. If it's a new object, it's inserted, if the object already has an associated ID, it's updated.

Usage:

remove
Removed the object from the database.

Usage:

Main static methods
These are the core static methods you are likely to have use for.

select
Selects the the specified fields of the records matching the provided conditions and returns them as an array of EPDBObject (or rather the deriving class).

Important args:
 * $fields - the fields to select. Array, string or null. Null for all fields. Null is the default.
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

Selecting all courses:

Selecting the id and name of all courses:

Selecting all courses with 42 students:

update
Update the specified fields for the matching records.

Important args:
 * $values - Array. Field name => new value. Field name without prefix.
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

All courses with 42 students are awesome:

delete
Delete the matching records.

Important args:
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

Delete non-awesome courses:

count
Count the matching records.

Important args:
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

Count the awesome courses:

has
See if there are any matching records.

Important args:
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

Are there any awesome courses with 42 students:

If there are any courses:

selectRow
Select only the first matching row and return it as EPDBObject (or false if nothing matches).

Important args:
 * $fields - the fields to select. Array, string or null. Null for all fields. Null is the default.
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.

Selecting the Master in Angry Birds course:

Selecting the Master in Angry Birds course and only loading the id field:

selectFields
Selects the the specified fields of the records matching the provided conditions and returns them as associative arrays.

Important args:
 * $fields - the fields to select. Array, string or null. Null for all fields. Null is the default.
 * $conditions - conditions the select should match. Field name => value. Field name without prefix.
 * $collapse - true by default, and not the third arg

When $collapse is true:
 * If one field is selected, each item in the result array will be this field.
 * If two fields are selected, each item in the result array will have as key the first field and as value the second field.
 * If more then two fields are selected, each item will be an associative array.

Selecting the name and id of the awesome courses:

Results into:

if $collapse was false, it would result into:

Selecting all terms (using the third arg $options):

Results into:

Summary fields
This is an utility feature not part of the core functionality of this class, and could easily be put in a deriving class. Since it is not part of the core functionality, you can completely ignore it if you have no use for it.

In order to efficiently do certain queries, it's often needed to have secondary storage for certain data. For example if you have a course pager which allows sorting on student count, you need the amount of students per course. This value needs to be computed every time its dependencies change. The  method is a place where you can put code that does this computation and which can then be called with an argument that specifies exactly what summary values need to be re-computed and updated. The static method  allows for updating the summary fields of all rows matching the provided conditions. Since this is all done in the base class, it's possible to do things such as ignore updates which only involve summary fields, for example for logging changes. After all, you do not want to log a change to a course if a student signed up for it - you want to log the student signing up for that course. And having it in the base class on one standard location makes keeping track of all these secondary storage related things much easier :)

Inheritance and composition
There are various places where you have some kind of functionality that has some differences in behaviour which can be derived from the type of object it's handling, where one can write generic code that extends or composites a EPDBObject instead of duplicating common functionality over a file per object type. These are classes that already do this:


 * Table pager in the Education program extension
 * API query module in the Contest extension
 * View action in the Education Program extension

Example implementations

 * EPRevision - revision object - represents a revision of an object (which happens to be objects deriving from EPRevisionedObject)
 * EPRevisionedObject - extends DBDataObject with revision history and logging functionality
 * EPOrg - organization/institution object - makes use of the summary functionality

Extensions using this

 * Education Program (code)
 * Reviews - slightly older version
 * Contest (code) - slightly older version, php 5.2 ported
 * Survey (code) - older version