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_tolink to this"Belongs to" relationships
array(0)
array
$_cast_datalink to thisData to be loaded into the model from a database call cast
array(0)
array
$_changedlink to thisarray(0)
array
$_column_cachelink to thisStores column information for ORM models
array(0)
string
$_created_columnlink to thisAuto-update columns for creation
NULL
Database
$_dblink to thisDatabase Object
NULL
array
$_db_appliedlink to thisDatabase methods applied
array(0)
Database_Query_Builder_Select
$_db_builderlink to thisDatabase query builder
NULL
String
$_db_grouplink to thisDatabase config group
NULL
array
$_db_pendinglink to thisDatabase methods pending
array(0)
bool
$_db_resetlink to thisReset builder
bool TRUE
string
$_errors_filenamelink to thisThe message filename used for validation errors. Defaults to ORM::$_object_name
NULL
string
$_foreign_key_suffixlink to thisForeign key suffix
string(3) "_id"
array
$_has_manylink to this"Has many" relationships
array(0)
array
$_has_onelink to this"Has one" relationships
array(0)
array
$_init_cachelink to thisInitialization storage for ORM models
array(0)
array
$_load_withlink to thisRelationships that should always be joined
array(0)
bool
$_loadedlink to thisbool FALSE
array
$_objectlink to thisCurrent object
array(0)
string
$_object_namelink to thisModel name
NULL
string
$_object_plurallink to thisPlural model name
NULL
array
$_original_valueslink to thisarray(0)
string
$_primary_keylink to thisTable primary key
string(2) "id"
mixed
$_primary_key_valuelink to thisPrimary key value
NULL
array
$_relatedlink to thisarray(0)
bool
$_reload_on_wakeuplink to thisModel configuration, reload on wakeup?
bool TRUE
bool
$_savedlink to thisbool FALSE
array
$_serialize_columnslink to thisAuto-serialize and unserialize columns on get/set
array(0)
array
$_sortinglink to thisNULL
array
$_table_columnslink to thisTable columns
NULL
string
$_table_namelink to thisTable name
NULL
bool
$_table_names_plurallink to thisModel configuration, table names plural?
bool TRUE
string
$_updated_columnlink to thisAuto-update columns for updates
NULL
bool
$_validlink to thisbool FALSE
Validation
$_validationlink to thisValidation object created before saving/updating
NULL
array
$_with_appliedlink to thisWith calls already applied
array(0)
Constructs a new model and loads a record if given
mixed
$id
= NULL - Parameter for find or object to load
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
->_object_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 = [];
}
}
Handles retrieval of all model values, relationships, and metadata. [!!] This should not be overridden.
string
$column
required - Column name mixed
public
function
__get(
$column
)
{
return
$this
->get(
$column
);
}
Checks if object data is set.
string
$column
required - Column name boolean
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 name mixed
$value
required - Column value void
public
function
__set(
$column
,
$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 name void
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'
, [
'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'
, [1, 2, 3, 4]);
string
$alias
required - Alias of the has_many "through" relationship mixed
$far_keys
required - Related model, primary key, or an array of primary keys ORM
public
function
add(
$alias
,
$far_keys
)
{
$far_keys
= (
$far_keys
instanceof
ORM) ?
$far_keys
->pk() :
$far_keys
;
$columns
= [
$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([
$foreign_key
,
$key
]);
}
$query
->execute(
$this
->_db);
return
$this
;
}
Creates a new "AND HAVING" condition for the query.
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
= NULL - Column value $this
public
function
and_having(
$column
,
$op
,
$value
= null)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_having'
,
'args'
=> [
$column
,
$op
,
$value
],
];
return
$this
;
}
Closes an open "AND HAVING (...)" grouping.
$this
public
function
and_having_close()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_having_close'
,
'args'
=> [],
];
return
$this
;
}
Opens a new "AND HAVING (...)" grouping.
$this
public
function
and_having_open()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_having_open'
,
'args'
=> [],
];
return
$this
;
}
Creates a new "AND WHERE" condition for the query.
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
required - Column value $this
public
function
and_where(
$column
,
$op
,
$value
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_where'
,
'args'
=> [
$column
,
$op
,
$value
],
];
return
$this
;
}
Closes an open "AND WHERE (...)" grouping.
$this
public
function
and_where_close()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_where_close'
,
'args'
=> [],
];
return
$this
;
}
Opens a new "AND WHERE (...)" grouping.
$this
public
function
and_where_open()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'and_where_open'
,
'args'
=> [],
];
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
= [];
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
;
}
public
function
belongs_to()
{
return
$this
->_belongs_to;
}
Enables the query to be cached for a specified amount of time.
integer
$lifetime
= NULL - Number of seconds to cache $this
public
function
cached(
$lifetime
= null)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'cached'
,
'args'
=> [
$lifetime
],
];
return
$this
;
}
Check whether the model data has been modified. If $field is specified, checks whether that field was modified.
string
$field
= NULL - Field to check for changes bool
- Whether or not the field has changed
public
function
changed(
$field
= null)
{
return
(
$field
=== null) ?
$this
->_changed : Arr::get(
$this
->_changed,
$field
);
}
Validates the current model's data
Validation
$extra_validation
= NULL - Validation object ORM
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
->errors_filename(),
$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 =
$this
->_original_values = [];
// 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
= [];
foreach
(
$this
->_db_pending
as
$key
=>
$method
) {
if
(
$method
[
'name'
] ==
'select'
) {
// Ignore any selected columns for now
$selects
[
$key
] =
$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,
$this
->_object_name])
->select([DB::expr(
'COUNT('
.
$this
->_db->quote_column(
$this
->_object_name .
'.'
.
$this
->_primary_key) .
')'
),
'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
(int)
$records
;
}
Returns the number of relationships
// Counts the number of times the login role is attached to $model
$model
->count_relations(
'roles'
, ORM::factory(
'role'
, [
'name'
=>
'login'
]));
// Counts the number of times role 5 is attached to $model
$model
->count_relations(
'roles'
, 5);
// Counts the number of times any of roles 1, 2, 3, or 4 are attached to
// $model
$model
->count_relations(
'roles'
, [1, 2, 3, 4]);
// Counts the number roles attached to $model
$model
->count_relations(
'roles'
)
string
$alias
required - Alias of the has_many "through" relationship mixed
$far_keys
= NULL - Related model, primary key, or an array of primary keys integer
public
function
count_relations(
$alias
,
$far_keys
= null)
{
if
(
$far_keys
=== null) {
return
(int) DB::select([DB::expr(
'COUNT(*)'
),
'records_found'
])
->from(
$this
->_has_many[
$alias
][
'through'
])
->where(
$this
->_has_many[
$alias
][
'foreign_key'
],
'='
,
$this
->pk())
->execute(
$this
->_db)->get(
'records_found'
);
}
$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
0;
$count
= (int) DB::select([DB::expr(
'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
(int)
$count
;
}
Insert a new object to the database
Validation
$validation
= NULL - Validation object ORM
public
function
create(Validation
$validation
= null)
{
if
(
$this
->_loaded)
throw
new
Kohana_Exception(
'Cannot create :model model because it is already loaded.'
, [
':model'
=>
$this
->_object_name]);
// Require model validation before saving
if
(!
$this
->_valid OR
$validation
) {
$this
->check(
$validation
);
}
$data
= [];
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];
}
else
{
$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 = [];
$this
->_original_values =
$this
->_object;
return
$this
;
}
public
function
created_column()
{
return
$this
->_created_column;
}
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.'
, [
':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();
}
Enables or disables selecting only unique columns using "SELECT DISTINCT"
boolean
$value
required - Enable or disable distinct columns $this
public
function
distinct(
$value
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'distinct'
,
'args'
=> [
$value
],
];
return
$this
;
}
public
function
errors_filename()
{
return
$this
->_errors_filename;
}
Creates and returns a new model. Model name must be passed with its' original casing, e.g.
$model = ORM::factory('User_Token');
string
$model
required - Model name mixed
$id
= NULL - Parameter for find() ORM
public
static
function
factory(
$model
,
$id
= null)
{
// Set class name
$model
=
'Model_'
.
$model
;
return
new
$model
(
$id
);
}
Filter definitions for validation
array
public
function
filters()
{
return
[];
}
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);
}
Choose the tables to select "FROM ..."
mixed
$tables
required - Table name or [$table, $alias] or object $this
public
function
from(
$tables
)
{
$tables
= func_get_args();
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'from'
,
'args'
=>
$tables
,
];
return
$this
;
}
Handles getting of column Override this method to add custom get behavior
string
$column
required - Column name mixed
public
function
get(
$column
)
{
if
(
array_key_exists
(
$column
,
$this
->_object)) {
return
(in_array(
$column
,
$this
->_serialize_columns)) ?
$this
->_unserialize_value(
$this
->_object[
$column
]) :
$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
->_object_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
->_object_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
->_object_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
->_object_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'
, [
':property'
=>
$column
,
':class'
=> get_class(
$this
)]);
}
}
Creates a "GROUP BY ..." filter.
mixed
$columns
required - Column name or [$column, $alias] or object $this
public
function
group_by(
$columns
)
{
$columns
= func_get_args();
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'group_by'
,
'args'
=>
$columns
,
];
return
$this
;
}
Tests if this object has a relationship to a different model, or an array of different models. When providing far keys, the number of relations must equal the number of keys.
// Check if $model has the login role
$model
->has(
'roles'
, ORM::factory(
'role'
, [
'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'
, [1, 2, 3, 4]);
// Check if $model has any roles
$model
->has(
'roles'
)
string
$alias
required - Alias of the has_many "through" relationship mixed
$far_keys
= NULL - Related model, primary key, or an array of primary keys boolean
public
function
has(
$alias
,
$far_keys
= null)
{
$count
=
$this
->count_relations(
$alias
,
$far_keys
);
if
(
$far_keys
=== null) {
return
(bool)
$count
;
}
else
{
return
$count
===
count
(
$far_keys
);
}
}
Tests if this object has a relationship to a different model, or an array of different models. When providing far keys, this function only checks that at least one of the relationships is satisfied.
// Check if $model has the login role
$model
->has(
'roles'
, ORM::factory(
'role'
, [
'name'
=>
'login'
]));
// Check for the login role if you know the roles.id is 5
$model
->has(
'roles'
, 5);
// Check for any of the following roles
$model
->has(
'roles'
, [1, 2, 3, 4]);
// Check if $model has any roles
$model
->has(
'roles'
)
string
$alias
required - Alias of the has_many "through" relationship mixed
$far_keys
= NULL - Related model, primary key, or an array of primary keys boolean
public
function
has_any(
$alias
,
$far_keys
= null)
{
return
(bool)
$this
->count_relations(
$alias
,
$far_keys
);
}
public
function
has_many()
{
return
$this
->_has_many;
}
public
function
has_one()
{
return
$this
->_has_one;
}
Alias of and_having()
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
= NULL - Column value $this
public
function
having(
$column
,
$op
,
$value
= null)
{
return
$this
->and_having(
$column
,
$op
,
$value
);
}
Closes an open "AND HAVING (...)" grouping.
$this
public
function
having_close()
{
return
$this
->and_having_close();
}
Alias of and_having_open()
$this
public
function
having_open()
{
return
$this
->and_having_open();
}
Adds addition tables to "JOIN ...".
mixed
$table
required - Column name or [$column, $alias] or object string
$type
= NULL - Join type (LEFT, RIGHT, INNER, etc) $this
public
function
join(
$table
,
$type
= null)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'join'
,
'args'
=> [
$table
,
$type
],
];
return
$this
;
}
Label definitions for validation
array
public
function
labels()
{
return
[];
}
Returns last executed query
string
public
function
last_query()
{
return
$this
->_db->last_query;
}
Return up to "LIMIT ..." results
integer
$number
required - Maximum results to return $this
public
function
limit(
$number
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'limit'
,
'args'
=> [
$number
],
];
return
$this
;
}
Proxy method to Database list_columns.
array
public
function
list_columns()
{
// Proxy to database
return
$this
->_db->list_columns(
$this
->_table_name);
}
public
function
load_with()
{
return
$this
->_load_with;
}
public
function
loaded()
{
return
$this
->_loaded;
}
public
function
object()
{
return
$this
->_object;
}
public
function
object_name()
{
return
$this
->_object_name;
}
public
function
object_plural()
{
return
$this
->_object_plural;
}
Start returning results after "OFFSET ..."
integer
$number
required - Starting result number $this
public
function
offset(
$number
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'offset'
,
'args'
=> [
$number
],
];
return
$this
;
}
Adds "ON ..." conditions for the last created JOIN statement.
mixed
$c1
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$c2
required - Column name or [$column, $alias] or object $this
public
function
on(
$c1
,
$op
,
$c2
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'on'
,
'args'
=> [
$c1
,
$op
,
$c2
],
];
return
$this
;
}
Creates a new "OR HAVING" condition for the query.
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
= NULL - Column value $this
public
function
or_having(
$column
,
$op
,
$value
= null)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_having'
,
'args'
=> [
$column
,
$op
,
$value
],
];
return
$this
;
}
Closes an open "OR HAVING (...)" grouping.
$this
public
function
or_having_close()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_having_close'
,
'args'
=> [],
];
return
$this
;
}
Opens a new "OR HAVING (...)" grouping.
$this
public
function
or_having_open()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_having_open'
,
'args'
=> [],
];
return
$this
;
}
Creates a new "OR WHERE" condition for the query.
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
required - Column value $this
public
function
or_where(
$column
,
$op
,
$value
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_where'
,
'args'
=> [
$column
,
$op
,
$value
],
];
return
$this
;
}
Closes an open "OR WHERE (...)" grouping.
$this
public
function
or_where_close()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_where_close'
,
'args'
=> [],
];
return
$this
;
}
Opens a new "OR WHERE (...)" grouping.
$this
public
function
or_where_open()
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'or_where_open'
,
'args'
=> [],
];
return
$this
;
}
Applies sorting with "ORDER BY ..."
mixed
$column
required - Column name or [$column, $alias] or object string
$direction
= NULL - Direction of sorting $this
public
function
order_by(
$column
,
$direction
= null)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'order_by'
,
'args'
=> [
$column
,
$direction
],
];
return
$this
;
}
public
function
original_values()
{
return
$this
->_original_values;
}
Set the value of a parameter in the query.
string
$param
required - Parameter key to replace mixed
$value
required - Value to use $this
public
function
param(
$param
,
$value
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'param'
,
'args'
=> [
$param
,
$value
],
];
return
$this
;
}
Returns the value of the primary key
mixed
- Primary key
public
function
pk()
{
return
$this
->_primary_key_value;
}
public
function
primary_key()
{
return
$this
->_primary_key;
}
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 =
$this
->_original_values = [];
// Only reload the object if we have one to reload
if
(
$this
->_loaded)
return
$this
->clear()
->where(
$this
->_object_name .
'.'
.
$this
->_primary_key,
'='
,
$primary_key
)
->find();
else
return
$this
->clear();
}
Reload column definitions.
boolean
$force
= bool FALSE - Force reloading ORM
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'
, [
'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'
, [1, 2, 3, 4]);
// Remove all related roles
$model
->remove(
'roles'
);
string
$alias
required - Alias of the has_many "through" relationship mixed
$far_keys
= NULL - Related model, primary key, or an array of primary keys ORM
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 call ORM
public
function
reset(
$next
= true)
{
if
(
$next
AND
$this
->_db_reset) {
$this
->_db_pending = [];
$this
->_db_applied = [];
$this
->_db_builder = null;
$this
->_with_applied = [];
}
// Reset on the next call?
$this
->_db_reset =
$next
;
return
$this
;
}
Rule definitions for validation
array
public
function
rules()
{
return
[];
}
Updates or Creates the record depending on loaded()
Validation
$validation
= NULL - Validation object ORM
public
function
save(Validation
$validation
= null)
{
return
$this
->loaded() ?
$this
->update(
$validation
) :
$this
->create(
$validation
);
}
public
function
saved()
{
return
$this
->_saved;
}
Choose the columns to select from.
mixed
$columns
= NULL - Column name or [$column, $alias] or object $this
public
function
select(
$columns
= null)
{
$columns
= func_get_args();
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'select'
,
'args'
=>
$columns
,
];
return
$this
;
}
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
([
'_primary_key_value'
,
'_object'
,
'_changed'
,
'_loaded'
,
'_saved'
,
'_sorting'
,
'_original_values'
]
as
$var
) {
$data
[
$var
] =
$this
->{
$var
};
}
return
serialize(
$data
);
}
Handles setting of columns Override this method to add custom set behavior
string
$column
required - Column name mixed
$value
required - Column value ORM
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
;
return
$this
;
}
if
(in_array(
$column
,
$this
->_serialize_columns)) {
$value
=
$this
->_serialize_value(
$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
instanceof
ORM) ?
$value
->pk() : null;
$this
->_changed[
$column
] =
$this
->_belongs_to[
$column
][
'foreign_key'
];
}
else
{
throw
new
Kohana_Exception(
'The :property: property does not exist in the :class: class'
, [
':property:'
=>
$column
,
':class:'
=> get_class(
$this
)]);
}
return
$this
;
}
public
function
table_columns()
{
return
$this
->_table_columns;
}
public
function
table_name()
{
return
$this
->_table_name;
}
Checks whether a column value is unique. Excludes itself if loaded.
string
$field
required - The field to check for uniqueness mixed
$value
required - The value to check for uniqueness bool
- Whteher the value is unique
public
function
unique(
$field
,
$value
)
{
$model
= ORM::factory(
$this
->object_name())
->where(
$field
,
'='
,
$value
)
->find();
if
(
$this
->loaded()) {
return
(!(
$model
->loaded() AND
$model
->pk() !=
$this
->pk()));
}
return
(!
$model
->loaded());
}
Prepares the database connection and reloads the object.
string
$data
required - String for unserialization void
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 object ORM
public
function
update(Validation
$validation
= null)
{
if
(!
$this
->_loaded)
throw
new
Kohana_Exception(
'Cannot update :model model because it is not loaded.'
, [
':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
= [];
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 = [];
$this
->_original_values =
$this
->_object;
return
$this
;
}
public
function
updated_column()
{
return
$this
->_updated_column;
}
Adds "USING ..." conditions for the last created JOIN statement.
string
$columns
required - Column name $this
public
function
using(
$columns
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'using'
,
'args'
=> [
$columns
],
];
return
$this
;
}
public
function
validation()
{
if
(!isset(
$this
->_validation)) {
// Initialize the validation object
$this
->_validation();
}
return
$this
->_validation;
}
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 => val array
$expected
= NULL - Array of keys to take from $values ORM
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
;
}
Alias of and_where()
mixed
$column
required - Column name or [$column, $alias] or object string
$op
required - Logic operator mixed
$value
required - Column value $this
public
function
where(
$column
,
$op
,
$value
)
{
// Add pending database call which is executed after query type is determined
$this
->_db_pending[] = [
'name'
=>
'where'
,
'args'
=> [
$column
,
$op
,
$value
],
];
return
$this
;
}
Closes an open "AND WHERE (...)" grouping.
$this
public
function
where_close()
{
return
$this
->and_where_close();
}
Alias of and_where_open()
$this
public
function
where_open()
{
return
$this
->and_where_open();
}
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 to ORM
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
->_object_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([
$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([
$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 query ORM
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,
$this
->_object_name]);
break
;
case
Database::
DELETE
:
// Cannot use an alias for DELETE queries
$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([
$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 select
protected
function
_build_select()
{
$columns
= [];
foreach
(
$this
->_table_columns
as
$column
=>
$_
) {
$columns
[] = [
$this
->_object_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 if none predefined
if
(
empty
(
$this
->_object_name)) {
$this
->_object_name =
strtolower
(
substr
(get_class(
$this
), 6));
}
// Check if this model has already been initialized
if
(!
$init
= Arr::get(ORM::
$_init_cache
,
$this
->_object_name, false)) {
$init
= [
'_belongs_to'
=> [],
'_has_one'
=> [],
'_has_many'
=> [],
];
// Set the object plural name if none predefined
if
(!isset(
$this
->_object_plural)) {
$init
[
'_object_plural'
] = Inflector::plural(
$this
->_object_name);
}
if
(!
$this
->_errors_filename) {
$init
[
'_errors_filename'
] =
$this
->_object_name;
}
if
(!
is_object
(
$this
->_db)) {
// Get database instance
$init
[
'_db'
] = Database::instance(
$this
->_db_group);
}
if
(
empty
(
$this
->_table_name)) {
// Table name is the same as the object name
$init
[
'_table_name'
] =
$this
->_object_name;
if
(
$this
->_table_names_plural === true) {
// Make the table name plural
$init
[
'_table_name'
] = Arr::get(
$init
,
'_object_plural'
,
$this
->_object_plural);
}
}
$defaults
= [];
foreach
(
$this
->_belongs_to
as
$alias
=>
$details
) {
if
(!isset(
$details
[
'model'
])) {
$defaults
[
'model'
] =
str_replace
(
' '
,
'_'
, ucwords(
str_replace
(
'_'
,
' '
,
$alias
)));
}
$defaults
[
'foreign_key'
] =
$alias
.
$this
->_foreign_key_suffix;
$init
[
'_belongs_to'
][
$alias
] =
array_merge
(
$defaults
,
$details
);
}
foreach
(
$this
->_has_one
as
$alias
=>
$details
) {
if
(!isset(
$details
[
'model'
])) {
$defaults
[
'model'
] =
str_replace
(
' '
,
'_'
, ucwords(
str_replace
(
'_'
,
' '
,
$alias
)));
}
$defaults
[
'foreign_key'
] =
$this
->_object_name .
$this
->_foreign_key_suffix;
$init
[
'_has_one'
][
$alias
] =
array_merge
(
$defaults
,
$details
);
}
foreach
(
$this
->_has_many
as
$alias
=>
$details
) {
if
(!isset(
$details
[
'model'
])) {
$defaults
[
'model'
] =
str_replace
(
' '
,
'_'
, ucwords(
str_replace
(
'_'
,
' '
, Inflector::singular(
$alias
))));
}
$defaults
[
'foreign_key'
] =
$this
->_object_name .
$this
->_foreign_key_suffix;
$defaults
[
'through'
] = null;
if
(!isset(
$details
[
'far_key'
])) {
$defaults
[
'far_key'
] = Inflector::singular(
$alias
) .
$this
->_foreign_key_suffix;
}
$init
[
'_has_many'
][
$alias
] =
array_merge
(
$defaults
,
$details
);
}
ORM::
$_init_cache
[
$this
->_object_name] =
$init
;
}
// Assign initialized properties to the current object
foreach
(
$init
as
$property
=>
$value
) {
$this
->{
$property
} =
$value
;
}
// 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 row ORM|Database_Result
protected
function
_load_result(
$multiple
= false)
{
$this
->_db_builder->from([
$this
->_table_name,
$this
->_object_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
->_object_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 load ORM
protected
function
_load_values(
array
$values
)
{
if
(
array_key_exists
(
$this
->_primary_key,
$values
)) {
if
(
$values
[
$this
->_primary_key] !== null) {
// Flag as loaded and valid
$this
->_loaded =
$this
->_valid = true;
// Store primary key
$this
->_primary_key_value =
$values
[
$this
->_primary_key];
}
else
{
// Not loaded or valid
$this
->_loaded =
$this
->_valid = false;
}
}
// Related objects
$related
= [];
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
);
}
}
if
(
$this
->_loaded) {
// Store the object in its original state
$this
->_original_values =
$this
->_object;
}
return
$this
;
}
Returns an ORM model for the given one-one related alias
string
$alias
required - Alias name ORM
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;
}
}
protected
function
_serialize_value(
$value
)
{
return
json_encode(
$value
);
}
protected
function
_unserialize_value(
$value
)
{
return
json_decode(
$value
, true);
}
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
)
->bind(
':original_values'
,
$this
->_original_values)
->bind(
':changed'
,
$this
->_changed);
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 name string
$value
required - The value to filter string
protected
function
run_filter(
$field
,
$value
)
{
$filters
=
$this
->filters();
// Get the filters for this column
$wildcards
=
empty
(
$filters
[true]) ? [] :
$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
= [
':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 [$filter, $params]
$filter
=
$array
[0];
$params
= Arr::get(
$array
, 1, [
':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
;
}