Jump to content

Developer Documentation

Active Records

What is an active record?

IPS4 makes extensive use of the active record pattern, where each active record object represents a row in your database, and the object provides methods for interacting with that row (including adding new rows). For example, since the \IPS\Member model returns an active record, we can fetch and interact with a member row in the database like so:

$member = \IPS\Member::load(1);
$member->name = "Dave";
$member->save();

IPS4's base active record class is \IPS\Patterns\ActiveRecord. Most of the model classes you'll work with (including \IPS\Node\Model\IPS\Content\Item\IPS\Content\Comment and \IPS\Content\Review) extend the active record pattern, meaning they all offer a consistent interface for working with your data.

It's important you make use of the active record methods provided instead of accessing the database directly, as when you add additional features to your content item, the methods will perform more complicated tasks.

 

Configuring ActiveRecord classes

When writing a class that extends \IPS\Patterns\ActiveRecord in the inheritance chain (even if you're not extending it yourself directly), you need to specify some properties that allow the class to locate records in the database. They are:

public static $databaseTable = 'string';

Required. Specifies the database table that this ActiveRecord maps to.

 

public static $databasePrefix = 'string';

Optional. Specifies the field prefix this table uses. For example, if your table named its fields item_id, item_name, item_description and so on, then $databasePrefix would be set as item_. This allows for automatic mapping of properties to database columns.

 

public static $databaseColumnId = 'string';

Optional (default: 'id'). Specifies the primary key field of this database table.

 

Loading records

static \IPS\Patterns\ActiveRecord load( int $id [, string $idField=NULL [, mixed $extraWhereClause=NULL ]] )

Example:

$row = \IPS\YourClass::load(1);

This method retrieves a row with the ID 1 from the database and returns it as an active record instance of your class. Results are cached, so you can call load for the same item multiple times, and it will only perform one query, returning the same object by reference on subsequent calls.

  • $id (Integer; required)
    The primary key ID of the record to load.
  • $idField (String; optional)
    The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
  • $extraWhereClause (Mixed; optional)
    Additional where clause(s) (see \IPS\Db::build for details)

Throws InvalidArgumentException if $idField does not exist in the table, or OutOfRangeException if a record with the given ID is not found.

Note: this method does not check user permissions on the item being loaded. When writing a class that extends one of the content models (\IPS\Node\Model\IPS\Content\Item\IPS\Content\Comment or \IPS\Content\Review, for example), you should instead use loadAndCheckPerms when loading data for the front end. This is a method with the same signature as the load method above, but loadAndCheckPerms will throw an OutOfRangeException if the user does not have permission to view the record.

 

static \IPS\Patterns\ActiveRecord constructFromData( array $data [, boolean $updateMultitonStoreIfExists=TRUE] )

Example:

$row = \IPS\YourClass::constructFromData( \IPS\Db::i()->select(...)->first() );

If you have retrieved a database row by manually querying (for example, to fetch the most recent record), and you need to build an ActiveRecord object from the data, this method allows you to do so without having to call load (which would cause another database query).

  • $data (Array; required)
    Database row returned from \IPS\Db, as an array.
  • $updateMultitonStoreIfExists (Boolean; optional)
    If true, will update the current cached object if one exists for this ID

 

Updating data on an ActiveRecord

You can get or set the data for a record simply by setting properties on the object, which map to your database column names. If you configured the $databasePrefix property in your class, then you should not include the prefix when you reference properties.

Example (assuming our database table contained columns named title and description):

$item = \IPS\YourClass::load( 1 );
$item->title = "My record title";
echo $item->description;

Note that to actually update the database, the save method should be called after you've made all of your changes (see below).

If your class needs to perform processing on properties before getting or setting them, you can define getters or setters for each property by adding a method named get_<property> or set_<property>. Within these methods, you can access the raw values using the $this->_data array.

Example that uppercases the title property when set:

// YourClass.php
public function set_title( $title )
{
	$this->_data['title'] = strtoupper( $title );
}

// OtherClass.php
$item = \IPS\YourClass::load( 1 );
$item->title = 'my title';
echo $item->title;

//--> 'MY TITLE'

 

Saving & deleting records

void save()

Example:

$item = \IPS\YourClass::load( 1 );
$item->title = 'New Title';
$item->save();

After changing data in an ActiveRecord, save must be called in order to update the database.

 

void delete()

Example:

$item = \IPS\YourClass::load( 1 );
$item->delete();

Deletes a row from the database.

 

Cloning records

You can clone records simply by using a clone expression. Internally, \IPS\Patterns\ActiveRecord ensures that primary keys are adjusted as needed. Note that you still need to call save after cloning in order to create the record in the database.

$item = \IPS\YourClass::load( 1 );
$copy = clone $item;
$copy->save();
echo $copy->id;

//--> 2

 

Using Bitwise flags

The ActiveRecord class implements a bitwise feature, allowing you to store multiple boolean values in a single field, without needing to add new fields (and therefore database columns) to your model.

Under the hood, the bitwise field is stored as an integer. You define your bitwise flags as keys with a numeric value; this numeric value doubles for each new value you add (so the order would go 1, 2, 4, 8, 16, 32, and so on).

You define your bitwise flags as a static property on your model, like so:

public static $bitOptions = array(
    'model_bitoptions'	=> array(
        'model_bitoptions'	=> array(
            'property_1'		=> 1,			// Some option for this model
            'property_2'		=> 2,			// Another option for this model
            'property_3'		=> 4			// A third option for this model
        )
    )
);

In this example, our model's database table would have a column named model_bitoptions - and we use this name in the $bitOptions array to identify it. We're storing three options, but you can define more by following the pattern of doubling the value each time. It's very good practice to comment each option here to explain what it does.

Your ActiveRecord model will automatically provide an \IPS\Patterns\Bitwise object for this column, which implements \ArrayAccess, allowing you to get and set values as it it were an array:

/* Getting a value */
if ( $object->model_bitoptions[‘property_1’] ) {
	// ...
}

/* Setting a value - remember it can be TRUE or FALSE only! */
$object->model_bitoptions[‘property_2’] = FALSE;
$object->save();

/* Getting database rows */
$rowsWithPropery1AsTrue = \IPS\Db::i()->select( ‘*’, table’, \IPS \Db::i()->bitwiseWhere( \IPS\YourClass::$bitOptions['model_bitoptions'], 'property_1' ));

 


  Report Document


×
×
  • Create New...