Implements: Serializable
Object Relational Mapping (ORM) is a method of abstracting database access to standard PHP calls. All table rows are represented as model objects, with object properties representing row data. ORM in Kohana generally follows the Active Record pattern.
Class declared in MODPATH/orm/classes/orm.php on line 3.
array
$_belongs_to"Belongs to" relationships
array
$_cast_dataData to be loaded into the model from a database call cast
array
$_changedarray
$_column_cacheStores column information for ORM models
array(0)
string
$_created_columnAuto-update columns for creation
Database
$_dbDatabase Object
array
$_db_appliedDatabase methods applied
Database_Query_Builder_Where
$_db_builderDatabase query builder
String
$_db_groupDatabase config group
array
$_db_methodsCallable database methods
array(28) ( 0 => string(5) "where" 1 => string(9) "and_where" 2 => string(8) "or_where" 3 => string(10) "where_open" 4 => string(14) "and_where_open" 5 => string(13) "or_where_open" 6 => string(11) "where_close" 7 => string(15) "and_where_close" 8 => string(14) "or_where_close" 9 => string(8) "distinct" 10 => string(6) "select" 11 => string(4) "from" 12 => string(4) "join" 13 => string(2) "on" 14 => string(8) "group_by" 15 => string(6) "having" 16 => string(10) "and_having" 17 => string(9) "or_having" 18 => string(11) "having_open" 19 => string(15) "and_having_open" 20 => string(14) "or_having_open" 21 => string(12) "having_close" 22 => string(16) "and_having_close" 23 => string(15) "or_having_close" 24 => string(8) "order_by" 25 => string(5) "limit" 26 => string(6) "offset" 27 => string(6) "cached" )
array
$_db_pendingDatabase methods pending
bool
$_db_resetReset builder
string
$_foreign_key_suffixForeign key suffix
array
$_has_many"Has many" relationships
array
$_has_one"Has one" relationships
array
$_load_withRelationships that should always be joined
bool
$_loadedarray
$_objectCurrent object
string
$_object_nameModel name
string
$_object_pluralPlural model name
string
$_primary_keyTable primary key
mixed
$_primary_key_valuePrimary key value
array
$_propertiesMembers that have access methods
array(15) ( 0 => string(11) "object_name" 1 => string(13) "object_plural" 2 => string(6) "loaded" 3 => string(5) "saved" 4 => string(11) "primary_key" 5 => string(10) "table_name" 6 => string(13) "table_columns" 7 => string(7) "has_one" 8 => string(10) "belongs_to" 9 => string(8) "has_many" 10 => string(16) "has_many_through" 11 => string(9) "load_with" 12 => string(14) "updated_column" 13 => string(14) "created_column" 14 => string(10) "validation" )
array
$_relatedbool
$_reload_on_wakeupModel configuration, reload on wakeup?
bool
$_savedarray
$_sortingarray
$_table_columnsTable columns
string
$_table_nameTable name
bool
$_table_names_pluralModel configuration, table names plural?
string
$_updated_columnAuto-update columns for updates
bool
$_validValidation
$_validationValidation object created before saving/updating
array
$_with_appliedWith calls already applied
Handles pass-through to database methods. Calls to query methods (query, get, insert, update) are not allowed. Query builder methods are chainable.
string
$method
required - Method namearray
$args
required - Method argumentsmixed
public function __call($method, array $args)
{
if (in_array($method, ORM::$_properties))
{
if ($method === 'validation')
{
if ( ! isset($this->_validation))
{
// Initialize the validation object
$this->_validation();
}
}
// Return the property
return $this->{'_'.$method};
}
elseif (in_array($method, ORM::$_db_methods))
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array('name' => $method, 'args' => $args);
return $this;
}
else
{
throw new Kohana_Exception('Invalid method :method called in :class',
array(':method' => $method, ':class' => get_class($this)));
}
}
Constructs a new model and loads a record if given
mixed
$id
= NULL - Parameter for find or object to loadvoid
public function __construct($id = NULL)
{
$this->_initialize();
if ($id !== NULL)
{
if (is_array($id))
{
foreach ($id as $column => $value)
{
// Passing an array of column => values
$this->where($column, '=', $value);
}
$this->find();
}
else
{
// Passing the primary key
$this->where($this->_table_name.'.'.$this->_primary_key, '=', $id)->find();
}
}
elseif ( ! empty($this->_cast_data))
{
// Load preloaded data from a database call cast
$this->_load_values($this->_cast_data);
$this->_cast_data = array();
}
}
Handles retrieval of all model values, relationships, and metadata.
string
$column
required - Column namemixed
public function __get($column)
{
if (array_key_exists($column, $this->_object))
{
return $this->_object[$column];
}
elseif (isset($this->_related[$column]))
{
// Return related model that has already been fetched
return $this->_related[$column];
}
elseif (isset($this->_belongs_to[$column]))
{
$model = $this->_related($column);
// Use this model's column and foreign model's primary key
$col = $model->_table_name.'.'.$model->_primary_key;
$val = $this->_object[$this->_belongs_to[$column]['foreign_key']];
// Make sure we don't run WHERE "AUTO_INCREMENT column" = NULL queries. This would
// return the last inserted record instead of an empty result.
// See: http://mysql.localhost.net.ar/doc/refman/5.1/en/server-session-variables.html#sysvar_sql_auto_is_null
if ($val !== NULL)
{
$model->where($col, '=', $val)->find();
}
return $this->_related[$column] = $model;
}
elseif (isset($this->_has_one[$column]))
{
$model = $this->_related($column);
// Use this model's primary key value and foreign model's column
$col = $model->_table_name.'.'.$this->_has_one[$column]['foreign_key'];
$val = $this->pk();
$model->where($col, '=', $val)->find();
return $this->_related[$column] = $model;
}
elseif (isset($this->_has_many[$column]))
{
$model = ORM::factory($this->_has_many[$column]['model']);
if (isset($this->_has_many[$column]['through']))
{
// Grab has_many "through" relationship table
$through = $this->_has_many[$column]['through'];
// Join on through model's target foreign key (far_key) and target model's primary key
$join_col1 = $through.'.'.$this->_has_many[$column]['far_key'];
$join_col2 = $model->_table_name.'.'.$model->_primary_key;
$model->join($through)->on($join_col1, '=', $join_col2);
// Through table's source foreign key (foreign_key) should be this model's primary key
$col = $through.'.'.$this->_has_many[$column]['foreign_key'];
$val = $this->pk();
}
else
{
// Simple has_many relationship, search where target model's foreign key is this model's primary key
$col = $model->_table_name.'.'.$this->_has_many[$column]['foreign_key'];
$val = $this->pk();
}
return $model->where($col, '=', $val);
}
else
{
throw new Kohana_Exception('The :property property does not exist in the :class class',
array(':property' => $column, ':class' => get_class($this)));
}
}
Checks if object data is set.
string
$column
required - Column nameboolean
public function __isset($column)
{
return (isset($this->_object[$column]) OR
isset($this->_related[$column]) OR
isset($this->_has_one[$column]) OR
isset($this->_belongs_to[$column]) OR
isset($this->_has_many[$column]));
}
Base set method - this should not be overridden.
string
$column
required - Column namemixed
$value
required - Column valuevoid
public function __set($column, $value)
{
if ( ! isset($this->_object_name))
{
// Object not yet constructed, so we're loading data from a database call cast
$this->_cast_data[$column] = $value;
}
else
{
// Set the model's column to given value
$this->set($column, $value);
}
}
Displays the primary key of a model when it is converted to a string.
string
public function __toString()
{
return (string) $this->pk();
}
Unsets object data.
string
$column
required - Column namevoid
public function __unset($column)
{
unset($this->_object[$column], $this->_changed[$column], $this->_related[$column]);
}
Adds a new relationship to between this model and another.
// Add the login role using a model instance
$model->add('roles', ORM::factory('role', array('name' => 'login')));
// Add the login role if you know the roles.id is 5
$model->add('roles', 5);
// Add multiple roles (for example, from checkboxes on a form)
$model->add('roles', array(1, 2, 3, 4));
string
$alias
required - Alias of the has_many "through" relationshipmixed
$far_keys
required - Related model, primary key, or an array of primary keysORM
public function add($alias, $far_keys)
{
$far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
$columns = array($this->_has_many[$alias]['foreign_key'], $this->_has_many[$alias]['far_key']);
$foreign_key = $this->pk();
$query = DB::insert($this->_has_many[$alias]['through'], $columns);
foreach ( (array) $far_keys as $key)
{
$query->values(array($foreign_key, $key));
}
$query->execute($this->_db);
return $this;
}
Returns the values of this object as an array, including any related one-one models that have already been loaded using with()
array
public function as_array()
{
$object = array();
foreach ($this->_object as $column => $value)
{
// Call __get for any user processing
$object[$column] = $this->__get($column);
}
foreach ($this->_related as $column => $model)
{
// Include any related objects that are already loaded
$object[$column] = $model->as_array();
}
return $object;
}
Validates the current model's data
Validation
$extra_validation
= NULL - Validation objectORM
public function check(Validation $extra_validation = NULL)
{
// Determine if any external validation failed
$extra_errors = ($extra_validation AND ! $extra_validation->check());
// Always build a new validation object
$this->_validation();
$array = $this->_validation;
if (($this->_valid = $array->check()) === FALSE OR $extra_errors)
{
$exception = new ORM_Validation_Exception($this->_object_name, $array);
if ($extra_errors)
{
// Merge any possible errors from the external object
$exception->add_object('_external', $extra_validation);
}
throw $exception;
}
return $this;
}
Unloads the current object and clears the status.
ORM
public function clear()
{
// Create an array with all the columns set to NULL
$values = array_combine(array_keys($this->_table_columns), array_fill(0, count($this->_table_columns), NULL));
// Replace the object and reset the object status
$this->_object = $this->_changed = $this->_related = array();
// Replace the current object with an empty one
$this->_load_values($values);
// Reset primary key
$this->_primary_key_value = NULL;
// Reset the loaded state
$this->_loaded = FALSE;
$this->reset();
return $this;
}
Count the number of records in the table.
integer
public function count_all()
{
$selects = array();
foreach ($this->_db_pending as $key => $method)
{
if ($method['name'] == 'select')
{
// Ignore any selected columns for now
$selects[] = $method;
unset($this->_db_pending[$key]);
}
}
if ( ! empty($this->_load_with))
{
foreach ($this->_load_with as $alias)
{
// Bind relationship
$this->with($alias);
}
}
$this->_build(Database::SELECT);
$records = $this->_db_builder->from($this->_table_name)
->select(array('COUNT("*")', 'records_found'))
->execute($this->_db)
->get('records_found');
// Add back in selected columns
$this->_db_pending += $selects;
$this->reset();
// Return the total number of records in a table
return $records;
}
Insert a new object to the database
Validation
$validation
= NULL - Validation objectORM
public function create(Validation $validation = NULL)
{
if ($this->_loaded)
throw new Kohana_Exception('Cannot create :model model because it is already loaded.', array(':model' => $this->_object_name));
// Require model validation before saving
if ( ! $this->_valid OR $validation)
{
$this->check($validation);
}
$data = array();
foreach ($this->_changed as $column)
{
// Generate list of column => values
$data[$column] = $this->_object[$column];
}
if (is_array($this->_created_column))
{
// Fill the created column
$column = $this->_created_column['column'];
$format = $this->_created_column['format'];
$data[$column] = $this->_object[$column] = ($format === TRUE) ? time() : date($format);
}
$result = DB::insert($this->_table_name)
->columns(array_keys($data))
->values(array_values($data))
->execute($this->_db);
if ( ! array_key_exists($this->_primary_key, $data))
{
// Load the insert id as the primary key if it was left out
$this->_object[$this->_primary_key] = $this->_primary_key_value = $result[0];
}
if (empty($this->_primary_key_value))
{
// Set the primary key value if it was manually chosen by the user
$this->_primary_key_value = $this->_object[$this->_primary_key];
}
// Object is now loaded and saved
$this->_loaded = $this->_saved = TRUE;
// All changes have been saved
$this->_changed = array();
return $this;
}
Deletes a single record while ignoring relationships.
ORM
public function delete()
{
if ( ! $this->_loaded)
throw new Kohana_Exception('Cannot delete :model model because it is not loaded.', array(':model' => $this->_object_name));
// Use primary key value
$id = $this->pk();
// Delete the object
DB::delete($this->_table_name)
->where($this->_primary_key, '=', $id)
->execute($this->_db);
return $this->clear();
}
Creates and returns a new model.
string
$model
required - Model namemixed
$id
= NULL - Parameter for find()ORM
public static function factory($model, $id = NULL)
{
// Set class name
$model = 'Model_'.ucfirst($model);
return new $model($id);
}
Filter definitions for validation
array
public function filters()
{
return array();
}
Finds and loads a single database row into the object.
ORM
public function find()
{
if ($this->_loaded)
throw new Kohana_Exception('Method find() cannot be called on loaded objects');
if ( ! empty($this->_load_with))
{
foreach ($this->_load_with as $alias)
{
// Bind auto relationships
$this->with($alias);
}
}
$this->_build(Database::SELECT);
return $this->_load_result(FALSE);
}
Finds multiple database rows and returns an iterator of the rows found.
Database_Result
public function find_all()
{
if ($this->_loaded)
throw new Kohana_Exception('Method find_all() cannot be called on loaded objects');
if ( ! empty($this->_load_with))
{
foreach ($this->_load_with as $alias)
{
// Bind auto relationships
$this->with($alias);
}
}
$this->_build(Database::SELECT);
return $this->_load_result(TRUE);
}
Tests if this object has a relationship to a different model, or an array of different models.
// Check if $model has the login role
$model->has('roles', ORM::factory('role', array('name' => 'login')));
// Check for the login role if you know the roles.id is 5
$model->has('roles', 5);
// Check for all of the following roles
$model->has('roles', array(1, 2, 3, 4));
string
$alias
required - Alias of the has_many "through" relationshipmixed
$far_keys
required - Related model, primary key, or an array of primary keysDatabase_Result
public function has($alias, $far_keys)
{
$far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
// We need an array to simplify the logic
$far_keys = (array) $far_keys;
// Nothing to check if the model isn't loaded or we don't have any far_keys
if ( ! $far_keys OR ! $this->_loaded)
return FALSE;
$count = (int) DB::select(array('COUNT("*")', 'records_found'))
->from($this->_has_many[$alias]['through'])
->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk())
->where($this->_has_many[$alias]['far_key'], 'IN', $far_keys)
->execute($this->_db)->get('records_found');
// Rows found need to match the rows searched
return $count === count($far_keys);
}
Label definitions for validation
array
public function labels()
{
return array();
}
Returns last executed query
string
public function last_query()
{
return $this->_db->last_query;
}
Proxy method to Database list_columns.
array
public function list_columns()
{
// Proxy to database
return $this->_db->list_columns($this->_table_name);
}
Returns the value of the primary key
mixed
- Primary keypublic function pk()
{
return $this->_primary_key_value;
}
Reloads the current object from the database.
ORM
public function reload()
{
$primary_key = $this->pk();
// Replace the object and reset the object status
$this->_object = $this->_changed = $this->_related = array();
// Only reload the object if we have one to reload
if ($this->_loaded)
return $this->clear()
->where($this->_table_name.'.'.$this->_primary_key, '=', $primary_key)
->find();
else
return $this->clear();
}
Reload column definitions.
boolean
$force
= bool FALSE - Force reloadingORM
public function reload_columns($force = FALSE)
{
if ($force === TRUE OR empty($this->_table_columns))
{
if (isset(ORM::$_column_cache[$this->_object_name]))
{
// Use cached column information
$this->_table_columns = ORM::$_column_cache[$this->_object_name];
}
else
{
// Grab column information from database
$this->_table_columns = $this->list_columns();
// Load column cache
ORM::$_column_cache[$this->_object_name] = $this->_table_columns;
}
}
return $this;
}
Removes a relationship between this model and another.
// Remove a role using a model instance
$model->remove('roles', ORM::factory('role', array('name' => 'login')));
// Remove the role knowing the primary key
$model->remove('roles', 5);
// Remove multiple roles (for example, from checkboxes on a form)
$model->remove('roles', array(1, 2, 3, 4));
// Remove all related roles
$model->remove('roles');
string
$alias
required - Alias of the has_many "through" relationshipmixed
$far_keys
= NULL - Related model, primary key, or an array of primary keysORM
public function remove($alias, $far_keys = NULL)
{
$far_keys = ($far_keys instanceof ORM) ? $far_keys->pk() : $far_keys;
$query = DB::delete($this->_has_many[$alias]['through'])
->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk());
if ($far_keys !== NULL)
{
// Remove all the relationships in the array
$query->where($this->_has_many[$alias]['far_key'], 'IN', (array) $far_keys);
}
$query->execute($this->_db);
return $this;
}
Clears query builder. Passing FALSE is useful to keep the existing query conditions for another query.
bool
$next
= bool TRUE - Pass FALSE to avoid resetting on the next callORM
public function reset($next = TRUE)
{
if ($next AND $this->_db_reset)
{
$this->_db_pending = array();
$this->_db_applied = array();
$this->_db_builder = NULL;
$this->_with_applied = array();
}
// Reset on the next call?
$this->_db_reset = $next;
return $this;
}
Rule definitions for validation
array
public function rules()
{
return array();
}
Updates or Creates the record depending on loaded()
Validation
$validation
= NULL - Validation objectORM
public function save(Validation $validation = NULL)
{
return $this->loaded() ? $this->update($validation) : $this->create($validation);
}
Allows serialization of only the object data and state, to prevent "stale" objects being unserialized, which also requires less memory.
string
public function serialize()
{
// Store only information about the object
foreach (array('_primary_key_value', '_object', '_changed', '_loaded', '_saved', '_sorting') as $var)
{
$data[$var] = $this->{$var};
}
return serialize($data);
}
Handles setting of column
string
$column
required - Column namemixed
$value
required - Column valuevoid
public function set($column, $value)
{
if (array_key_exists($column, $this->_object))
{
// Filter the data
$value = $this->run_filter($column, $value);
// See if the data really changed
if ($value !== $this->_object[$column])
{
$this->_object[$column] = $value;
// Data has changed
$this->_changed[$column] = $column;
// Object is no longer saved or valid
$this->_saved = $this->_valid = FALSE;
}
}
elseif (isset($this->_belongs_to[$column]))
{
// Update related object itself
$this->_related[$column] = $value;
// Update the foreign key of this model
$this->_object[$this->_belongs_to[$column]['foreign_key']] = $value->pk();
$this->_changed[$column] = $this->_belongs_to[$column]['foreign_key'];
}
else
{
throw new Kohana_Exception('The :property: property does not exist in the :class: class',
array(':property:' => $column, ':class:' => get_class($this)));
}
return $this;
}
Prepares the database connection and reloads the object.
string
$data
required - String for unserializationvoid
public function unserialize($data)
{
// Initialize model
$this->_initialize();
foreach (unserialize($data) as $name => $var)
{
$this->{$name} = $var;
}
if ($this->_reload_on_wakeup === TRUE)
{
// Reload the object
$this->reload();
}
}
Updates a single record or multiple records
Validation
$validation
= NULL - Validation objectORM
public function update(Validation $validation = NULL)
{
if ( ! $this->_loaded)
throw new Kohana_Exception('Cannot update :model model because it is not loaded.', array(':model' => $this->_object_name));
// Run validation if the model isn't valid or we have additional validation rules.
if ( ! $this->_valid OR $validation)
{
$this->check($validation);
}
if (empty($this->_changed))
{
// Nothing to update
return $this;
}
$data = array();
foreach ($this->_changed as $column)
{
// Compile changed data
$data[$column] = $this->_object[$column];
}
if (is_array($this->_updated_column))
{
// Fill the updated column
$column = $this->_updated_column['column'];
$format = $this->_updated_column['format'];
$data[$column] = $this->_object[$column] = ($format === TRUE) ? time() : date($format);
}
// Use primary key value
$id = $this->pk();
// Update a single record
DB::update($this->_table_name)
->set($data)
->where($this->_primary_key, '=', $id)
->execute($this->_db);
if (isset($data[$this->_primary_key]))
{
// Primary key was changed, reflect it
$this->_primary_key_value = $data[$this->_primary_key];
}
// Object has been saved
$this->_saved = TRUE;
// All changes have been saved
$this->_changed = array();
return $this;
}
Set values from an array with support for one-one relationships. This method should be used for loading in post data, etc.
array
$values
required - Array of column => valarray
$expected
= NULL - Array of keys to take from $valuesORM
public function values(array $values, array $expected = NULL)
{
// Default to expecting everything except the primary key
if ($expected === NULL)
{
$expected = array_keys($this->_table_columns);
// Don't set the primary key by default
unset($values[$this->_primary_key]);
}
foreach ($expected as $key => $column)
{
if (is_string($key))
{
// isset() fails when the value is NULL (we want it to pass)
if ( ! array_key_exists($key, $values))
continue;
// Try to set values to a related model
$this->{$key}->values($values[$key], $column);
}
else
{
// isset() fails when the value is NULL (we want it to pass)
if ( ! array_key_exists($column, $values))
continue;
// Update the column, respects __set()
$this->$column = $values[$column];
}
}
return $this;
}
Binds another one-to-one object to this model. One-to-one objects can be nested using 'object1:object2' syntax
string
$target_path
required - Target model to bind tovoid
public function with($target_path)
{
if (isset($this->_with_applied[$target_path]))
{
// Don't join anything already joined
return $this;
}
// Split object parts
$aliases = explode(':', $target_path);
$target = $this;
foreach ($aliases as $alias)
{
// Go down the line of objects to find the given target
$parent = $target;
$target = $parent->_related($alias);
if ( ! $target)
{
// Can't find related object
return $this;
}
}
// Target alias is at the end
$target_alias = $alias;
// Pop-off top alias to get the parent path (user:photo:tag becomes user:photo - the parent table prefix)
array_pop($aliases);
$parent_path = implode(':', $aliases);
if (empty($parent_path))
{
// Use this table name itself for the parent path
$parent_path = $this->_table_name;
}
else
{
if ( ! isset($this->_with_applied[$parent_path]))
{
// If the parent path hasn't been joined yet, do it first (otherwise LEFT JOINs fail)
$this->with($parent_path);
}
}
// Add to with_applied to prevent duplicate joins
$this->_with_applied[$target_path] = TRUE;
// Use the keys of the empty object to determine the columns
foreach (array_keys($target->_object) as $column)
{
$name = $target_path.'.'.$column;
$alias = $target_path.':'.$column;
// Add the prefix so that load_result can determine the relationship
$this->select(array($name, $alias));
}
if (isset($parent->_belongs_to[$target_alias]))
{
// Parent belongs_to target, use target's primary key and parent's foreign key
$join_col1 = $target_path.'.'.$target->_primary_key;
$join_col2 = $parent_path.'.'.$parent->_belongs_to[$target_alias]['foreign_key'];
}
else
{
// Parent has_one target, use parent's primary key as target's foreign key
$join_col1 = $parent_path.'.'.$parent->_primary_key;
$join_col2 = $target_path.'.'.$parent->_has_one[$target_alias]['foreign_key'];
}
// Join the related object into the result
$this->join(array($target->_table_name, $target_path), 'LEFT')->on($join_col1, '=', $join_col2);
return $this;
}
Initializes the Database Builder to given query type
integer
$type
required - Type of Database queryORM
protected function _build($type)
{
// Construct new builder object based on query type
switch ($type)
{
case Database::SELECT:
$this->_db_builder = DB::select();
break;
case Database::UPDATE:
$this->_db_builder = DB::update($this->_table_name);
break;
case Database::DELETE:
$this->_db_builder = DB::delete($this->_table_name);
}
// Process pending database method calls
foreach ($this->_db_pending as $method)
{
$name = $method['name'];
$args = $method['args'];
$this->_db_applied[$name] = $name;
call_user_func_array(array($this->_db_builder, $name), $args);
}
return $this;
}
Returns an array of columns to include in the select query. This method can be overridden to change the default select behavior.
array
- Columns to selectprotected function _build_select()
{
$columns = array();
foreach ($this->_table_columns as $column => $_)
{
$columns[] = array($this->_table_name.'.'.$column, $column);
}
return $columns;
}
Prepares the model database connection, determines the table name, and loads column information.
void
protected function _initialize()
{
// Set the object name and plural name
$this->_object_name = strtolower(substr(get_class($this), 6));
$this->_object_plural = Inflector::plural($this->_object_name);
if ( ! is_object($this->_db))
{
// Get database instance
$this->_db = Database::instance($this->_db_group);
}
if (empty($this->_table_name))
{
// Table name is the same as the object name
$this->_table_name = $this->_object_name;
if ($this->_table_names_plural === TRUE)
{
// Make the table name plural
$this->_table_name = Inflector::plural($this->_table_name);
}
}
foreach ($this->_belongs_to as $alias => $details)
{
$defaults['model'] = $alias;
$defaults['foreign_key'] = $alias.$this->_foreign_key_suffix;
$this->_belongs_to[$alias] = array_merge($defaults, $details);
}
foreach ($this->_has_one as $alias => $details)
{
$defaults['model'] = $alias;
$defaults['foreign_key'] = $this->_object_name.$this->_foreign_key_suffix;
$this->_has_one[$alias] = array_merge($defaults, $details);
}
foreach ($this->_has_many as $alias => $details)
{
$defaults['model'] = Inflector::singular($alias);
$defaults['foreign_key'] = $this->_object_name.$this->_foreign_key_suffix;
$defaults['through'] = NULL;
$defaults['far_key'] = Inflector::singular($alias).$this->_foreign_key_suffix;
$this->_has_many[$alias] = array_merge($defaults, $details);
}
// Load column information
$this->reload_columns();
// Clear initial model state
$this->clear();
}
Loads a database result, either as a new record for this model, or as an iterator for multiple rows.
bool
$multiple
= bool FALSE - Return an iterator or load a single rowORM|Database_Result
protected function _load_result($multiple = FALSE)
{
$this->_db_builder->from($this->_table_name);
if ($multiple === FALSE)
{
// Only fetch 1 record
$this->_db_builder->limit(1);
}
// Select all columns by default
$this->_db_builder->select_array($this->_build_select());
if ( ! isset($this->_db_applied['order_by']) AND ! empty($this->_sorting))
{
foreach ($this->_sorting as $column => $direction)
{
if (strpos($column, '.') === FALSE)
{
// Sorting column for use in JOINs
$column = $this->_table_name.'.'.$column;
}
$this->_db_builder->order_by($column, $direction);
}
}
if ($multiple === TRUE)
{
// Return database iterator casting to this object type
$result = $this->_db_builder->as_object(get_class($this))->execute($this->_db);
$this->reset();
return $result;
}
else
{
// Load the result as an associative array
$result = $this->_db_builder->as_assoc()->execute($this->_db);
$this->reset();
if ($result->count() === 1)
{
// Load object values
$this->_load_values($result->current());
}
else
{
// Clear the object, nothing was found
$this->clear();
}
return $this;
}
}
Loads an array of values into into the current object.
array
$values
required - Values to loadORM
protected function _load_values(array $values)
{
if (array_key_exists($this->_primary_key, $values))
{
if ($values[$this->_primary_key] !== NULL)
{
// Flag as loaded, saved, and valid
$this->_loaded = $this->_saved = $this->_valid = TRUE;
// Store primary key
$this->_primary_key_value = $values[$this->_primary_key];
}
else
{
// Not loaded, saved, or valid
$this->_loaded = $this->_saved = $this->_valid = FALSE;
}
}
// Related objects
$related = array();
foreach ($values as $column => $value)
{
if (strpos($column, ':') === FALSE)
{
// Load the value to this model
$this->_object[$column] = $value;
}
else
{
// Column belongs to a related model
list ($prefix, $column) = explode(':', $column, 2);
$related[$prefix][$column] = $value;
}
}
if ( ! empty($related))
{
foreach ($related as $object => $values)
{
// Load the related objects with the values in the result
$this->_related($object)->_load_values($values);
}
}
return $this;
}
Returns an ORM model for the given one-one related alias
string
$alias
required - Alias nameORM
protected function _related($alias)
{
if (isset($this->_related[$alias]))
{
return $this->_related[$alias];
}
elseif (isset($this->_has_one[$alias]))
{
return $this->_related[$alias] = ORM::factory($this->_has_one[$alias]['model']);
}
elseif (isset($this->_belongs_to[$alias]))
{
return $this->_related[$alias] = ORM::factory($this->_belongs_to[$alias]['model']);
}
else
{
return FALSE;
}
}
Initializes validation rules, and labels
void
protected function _validation()
{
// Build the validation object with its rules
$this->_validation = Validation::factory($this->_object)
->bind(':model', $this);
foreach ($this->rules() as $field => $rules)
{
$this->_validation->rules($field, $rules);
}
// Use column names by default for labels
$columns = array_keys($this->_table_columns);
// Merge user-defined labels
$labels = array_merge(array_combine($columns, $columns), $this->labels());
foreach ($labels as $field => $label)
{
$this->_validation->label($field, $label);
}
}
Filters a value for a specific column
string
$field
required - The column namestring
$value
required - The value to filterstring
protected function run_filter($field, $value)
{
$filters = $this->filters();
// Get the filters for this column
$wildcards = empty($filters[TRUE]) ? array() : $filters[TRUE];
// Merge in the wildcards
$filters = empty($filters[$field]) ? $wildcards : array_merge($wildcards, $filters[$field]);
// Bind the field name and model so they can be used in the filter method
$_bound = array
(
':field' => $field,
':model' => $this,
);
foreach ($filters as $array)
{
// Value needs to be bound inside the loop so we are always using the
// version that was modified by the filters that already ran
$_bound[':value'] = $value;
// Filters are defined as array($filter, $params)
$filter = $array[0];
$params = Arr::get($array, 1, array(':value'));
foreach ($params as $key => $param)
{
if (is_string($param) AND array_key_exists($param, $_bound))
{
// Replace with bound value
$params[$key] = $_bound[$param];
}
}
if (is_array($filter) OR ! is_string($filter))
{
// This is either a callback as an array or a lambda
$value = call_user_func_array($filter, $params);
}
elseif (strpos($filter, '::') === FALSE)
{
// Use a function call
$function = new ReflectionFunction($filter);
// Call $function($this[$field], $param, ...) with Reflection
$value = $function->invokeArgs($params);
}
else
{
// Split the class and method of the rule
list($class, $method) = explode('::', $filter, 2);
// Use a static method call
$method = new ReflectionMethod($class, $method);
// Call $Class::$method($this[$field], $param, ...) with Reflection
$value = $method->invokeArgs(NULL, $params);
}
}
return $value;
}