Skip to content

ActiveRecord

Viames Marino edited this page Jun 15, 2018 · 18 revisions

Pair allows the creation of objects related to each respective database table using the ActiveRecord class, based on the homonymous ActiveRecord pattern.

The configuration of the objects described above does not require the creation of XML files, as usual, in the ORM. Objects created by the DB records are converted in both directions to the desired PHP type. See further on this page.

In addition, each class inherited from ActiveRecord supports many convenient methods including those for managing the internal cache for saving data that saves queries.

The Pair base tables are InnoDB utf-8mb4.

Create a new ActiveRecord class

To create a new ActiveRecord class, is necessary to indicate which are the columns of the DB to be connected to the class through a list of properties with protected attribute. Eg:

<?php

use Pair\ActiveRecord;

class Person extends ActiveRecord {

	/**
	 * Name of related db table.
	 * @var string
	 */
	const TABLE_NAME = 'persons';
		
	/**
	 * Name of the primary-key column.
	 * @var array
	 */
	const TABLE_KEY = ['id'];
	
	/**
	 * Property that binds “id” column.
	 * @var int
	 */
	protected $id;

	/**
	 * Property that binds “full_name” column.
	 * @var string
	 */
	protected $fullName;

	/**
	 * Method called by the constructor after populating the object.
	 */
	protected function init() {

		$this->bindAsInteger('id');

	}

}

In the example there are two constants TABLE_NAME and TABLE_KEY which define respectively the name of the table connected to this class and its primary-key / compound-key.

Below is a list of properties linked to the table columns. In the example there are id (integer) and fullName (string). Following these, the init() method that automatically casts id to a PHP integer, although the MySQL driver returns it to PHP as a string.

The ActiveRecord class expects each property to have a corresponding column in the mapped DB table. This is done automatically by ActiveRecord by converting the DB column names from snake case to the names provided by Pair in camel case, for example the attribute_name column is linked to the attributeName property of the object. In the example, the full_name column of the persons table will automatically be available as the fullName property of the Person object.

The static method that takes care of this connection is getBinds(). You can customize the naming system to link table columns and properties overloading the method and returning an associative array with this structure:

	/**
	 * Returns array with matching object property name on related table columns.
	 *
	 * @return array
	 */
	protected static function getBinds() {
		
		$binds = [
			'propertyName1' => 'column_name_1',
			'propertyName2' => 'column_name_2 '
		];
		
		return $binds;
		
	}

Object constructor

The purpose of this class is to provide inheritance for the methods of the ActiveRecord paradigm, which involves coupling a class to a database table.

Creating an object that inherits from ActiveRecord using the PHP __construct() method can be done in two ways:

  1. using the key field in the table
  2. manually populating all the expected properties

Key field of the table

To construct an object using the table key, you can indicate three types of keys:

  1. integer for simple tables or autoincrement
  2. string for simple tables
  3. Array for tables with composite keys

A query to the database will retrieve the object identified by the key value and all the properties of the object bound to the table fields will be populated and converted accordingly (see automatic cast).

Example:

<?php

$id = 1;
$person = new Person($id);

print $person->fullName;

The $person object has the id and name properties populated as in the record of db where id = 1.

Note: id object property is casted to integer when its value is collected by database record.

Populate object properties

The second way to create an object is the manual population of its properties. This is useful when you have already loaded a list of complete rows of the table and want to create the related objects without further queries.

To construct an object in this way, it is sufficient to pass as a parameter an object of type PHP stdClass containing the same properties of the object to be created and its values.

Example:

<?php

use Pair\Database;

// load  an array of stdClass object with all rows in persons
$db = Database::getInstance();
$db->setQuery('SELECT * FROM persons');
$list = $db->loadObjects();

// initialize persons list
$persons = array();

// populate persons with Person objects with no further db queries
foreach ($list as $row) {
	$persons[] = new Person($row);
}

If some properties are not of the same expected type, an automatic cast will be performed by the parent ActiveRecord class. The above code, written in full to facilitate the explanation, can be summarized in a single line through a smart method of ActiveRecord:

<?php

// load  an array of Person objects
$persons = Person::getAllObjects();

Automatic properties cast

Each property of a Pair\ActiveRecord object can be automatically converted to a specific type of PHP. This happens when an object is requested by loading it from the DB. When an object is to be stored in the DB, a smart reverse conversion occurs. It is recommended to call these methods within the init() method available for each Pair\ActiveRecord child object.

The following self-explanatory methods perform the proper conversions when loaded a record from DB and when the object is saved to DB.

bindAsBoolean()

Converts the value of the field, usually an integer of any size, to TRUE or FALSE. The PHP NULL value is not foreseen under any circumstances.

bindAsCsv()

This special type is very useful for storing properties of the array object in a string, ENUM or SET field of the database by executing the conversion of the array into a comma-separated values string before storing the record.

bindAsDatetime()

This is the most sophisticated method of the series. The date can be set in different ways and could have only the date or both date and time. In any case, the available property will be a PHP DateTime object or, if the DB column is Nullable, the NULL value.

First assign the TimeZone of the connected user, if there is one, otherwise assign the default TimeZone in the case of a guest or stand-alone process.

Then it distinguishes the different cases in which the date can be indicated. If the constant UTC_DATE in configuration file is TRUE and the date is of type integer or consisting of a string of numbers only, then it interprets it as a timestamp.

Then check if the date is in date or time format of the dbms and in the case or directly a PHP DateTime object and assign it to the object property.

In case of unrecognized date, it is assigned NULL to the property.

bindAsFloat()

Converts field value to PHP Float type. It is recommended for use with the DB fields of the type DEC, DECIMAL, DOUBLE, DOUBLE PRECISION, FIXED, FLOAT, NUMERIC, REAL. If the DB field is Nullable, the value can be of PHP NULL type, which will otherwise be converted to 0.0.

bindAsInteger()

Converts the value of the DB field to the PHP integer type. If the DB field is Nullable, this property can have NULL value, otherwise the assignment from code of the NULL value will be automatically converted to 0.
Tip: Do not use this method to handle BIGINT fields because of PHP int value limits will produce side effects when out-of-range.

Store the object

To store an object you can use the store() method. This distinguishes the action to be performed based on the primary-key related to the object class. If the key is single and has the auto-increment attribute, the object creates a new record when the field linked to the primary-key has a value of NULL by invoking the method create(). In other cases, compound-key or primary-key with a string or integer value, the update() method is invoked.

Before storing an object in the DB, it is possible to indicate the actions to be performed. For this you can insert some code in the following methods:

  • beforeCreate(), invoked before the creation of a record
  • beforeUpdate(), invoked before a record is updated
  • beforeStore(), invoked in both the above cases

With the same logic, you can run some code immediately after editing an ActiveRecord object by inserting it in one of the following methods, as needed:

  • afterCreate(), invoked after creating a record
  • afterUpdate(), invoked after updating a record
  • afterStore(), invoked in both the above cases

Before storing the record, whether it is created or updated, each property value that has a corresponding one in the columns of the DB is converted appropriately according to the indications provided by the bindAs* methods. If the field was primary-key with auto-increment, the property of the key field is populated with the real value of the key field in the corresponding record.

Delete the object

The deletion of an object is done with the following code:

$result = $person->delete();

if (!$result) {
	// error message
}

In case you want to run some code before deleting the object, for example deleting a file that makes sense only if connected to the record to be deleted, you can implement this method in your class:

	/**
	 * Trigger function called before delete() method execution.
	 */
	protected function beforeDelete() {
	
		// code to run
	
	}

With the same logic, to perform an action after deleting the object, you can implement the method afterDelete().

Check on existent constraints

Please remember that Pair analyzes the database structure while working on it, so it can determine if a record can be deleted before actually executing the query. If a record has a foreign key that binds one of the columns linked to its properties, ActiveRecord verifies that the constraint is not RESTRICT. The isDeletable() method may help, which reveals if an ActiveRecord object can actually be deleted based on its constraints and on the presence in other required record tables.

if ($person->isDeletable()) {
	// show delete button
}

Object cache

ActiveRecord stores in the private property cache all the values that could be useful to save time and calculation effort in the server. Four methods manage the cache of every object inherited from ActiveRecord.

getCache ($name)

Returns a variable by its name. NULL in case of variable not found.

setCache ($name, $value)

Adds a variable to the object’s cache by settings its name and its value as parameters.

issetCache ($name)

Returns TRUE if object's cache has been previously set, FALSE otherwise. Expect the variable name as parameter.

unsetCache ($name)

Reset to cache variable by its name.

Error handling

Errors that occur during the execution of ActiveRecord methods, but also errors that are added from the outside, are handled by the following methods.

addError ($message)

Adds an error text to the error list of this object.

GetLastError ()

Returns the text of the last recorded error. If there are no errors, it returns FALSE.

getErrors ()

Returns an array with all error messages logged in the system.

resetErrors ()

Reset the error list. It is useful for endlessly running processes, such as a daemon emulation for the Linux system.

You can’t perform that action at this time.