Implements: Serializable
Core Post Class for handling content and content types
This is the API for handling content, extend this for handling content types. See blog model for example
Class declared in MODPATH/gleez/classes/gleez/post.php on line 15.
string(16) "<!--nowidgets-->"integer 5
array $_belongs_to"Belongs to" relationships
bool $_cachearray $_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
object $_datatablesDataTables
Database $_dbDatabase Object
array $_db_appliedDatabase methods applied
Database_Query_Builder_Where $_db_builderDatabase query builder
String $_db_groupDatabase config group
array $_db_pendingDatabase methods pending
bool $_db_resetReset builder
string $_errors_filenameThe message filename used for validation errors. Defaults to ORM::$_object_name
string $_foreign_key_suffixForeign key suffix
array $_has_many"Has many" relationships
array $_has_many_keys"Many to many" relationships
array $_has_one"Has one" relationships
array $_ignored_columnsIgnored columns
array $_init_cacheInitialization storage for ORM models
array(0) $_last_versionarray $_load_withRelationships that should always be joined
bool $_loadedarray $_objectCurrent object
string $_object_nameModel name
string $_object_pluralPlural model name
array $_original_valuesstring $_post_typePost type
string $_primary_keyTable primary key
mixed $_primary_key_valuePrimary key value
array $_relatedbool $_reload_on_wakeupModel configuration, reload on wakeup?
$_restorebool $_savedarray $_serialize_columnsAuto-serialize and unserialize columns on get/set
array $_sortingarray $_table_columnsTable columns
string $_table_nameTable name
bool $_table_names_pluralModel configuration, table names plural?
bool $_updated $_updated_columnAuto fill create and update columns
bool $_validValidation $_validationValidation object created before saving/updating
array $_with_appliedWith calls already applied
Reading data from inaccessible properties
string
$field
required - $fieldmixedpublic function __get($field)
{
switch ($field)
{
case 'title':
return Text::plain(parent::__get('title'));
break;
case 'teaser':
return Text::markup($this->rawteaser, $this->format);
break;
case 'body':
return Text::markup($this->rawbody, $this->format);
break;
case 'terms_form':
return $this->terms->find()->id;
break;
case 'tags_form':
return $this->tags->find_all()->as_array('id', 'name');
break;
case 'taxonomy':
return HTML::links($this->terms->find_all(), array('class' => 'nav nav-pills pull-right'));
break;
case 'tagcloud':
return HTML::links($this->tags->find_all(), array('class' => 'nav nav-pills'));
break;
case 'links':
return HTML::links($this->links(), array('class' => 'links inline'));
break;
case 'rawtitle':
// Raw fields without markup. Usage: during edit or etc!
return parent::__get('title');;
break;
case 'rawteaser':
// Raw fields without markup. Usage: during edit or etc!
return parent::__get('teaser');
break;
case 'rawbody':
// Raw fields without markup. Usage: during edit or etc!
return parent::__get('body');
break;
case 'rawurl':
return Route::get($this->type)->uri(array( 'id' => $this->id));
break;
case 'url':
// Model specefic links; view, edit, delete url's
return ($path = Path::load($this->rawurl)) ? $path['alias'] : $this->rawurl;
break;
case 'edit_url':
return Route::get($this->type)->uri(array('id' => $this->id, 'action' => 'edit'));
break;
case 'delete_url':
return Route::get($this->type)->uri(array('id' => $this->id, 'action' => 'delete'));
break;
case 'count_comments':
return (int) DB::select('COUNT("*") AS mycount')
->from('comments')
->where('status', '=', 'publish')
->where('post_id', '=', $this->id)
->execute()->get('mycount');
break;
}
return parent::__get($field);
}
Bulk actions
boolean
$list
= bool FALSE - TRUE for dropdown for bult actions [Optional]string
$type
= string(4) "post" - Type of post [Optional]mixed - Statespublic static function bulk_actions($list = FALSE, $type = 'post')
{
$states = array(
'publish' => array(
'label' => __('Publish'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('status' => 'publish')),
),
'unpublish' => array(
'label' => __('Unpublish'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('status' => 'draft')),
),
'promote' => array(
'label' => __('Promote to front page'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('status' => 'publish', 'promote' => 1)),
),
'demote' => array(
'label' => __('Demote from front page'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('promote' => 0)),
),
'sticky' => array(
'label' => __('Make sticky'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('sticky' => 1)),
),
'unsticky' => array(
'label' => __('Remove stickiness'),
'callback' => 'Post::bulk_update',
'arguments' => array('updates' => array('sticky' => 0)),
),
'delete' => array(
'label' => __('Delete'),
'callback' => NULL,
),
'ct_page' => array(
'label' => __('Convert to @page', array('@page' => __('Page'))),
'callback' => 'Post::bulk_convert',
'arguments' => array('actions' => array('page')),
),
'ct_blog' => array(
'label' => __('Convert to @blog', array('@blog' => __('Blog'))),
'callback' => 'Post::bulk_convert',
'arguments' => array('actions' => array('blog')),
),
'ct_forum' => array(
'label' => __('Convert to @forum', array('@forum' => __('Forum'))),
'callback' => 'Post::bulk_convert',
'arguments' => array('actions' => array('forum')),
),
);
// Allow module developers to override
$values = Module::action('post_bulk_actions', $states);
if($list)
{
$options = array();
foreach ($values as $operation => $array)
{
if( $operation == "ct_{$type}") continue;
$options[$operation] = $array['label'];
}
return $options;
}
return $values;
}
Bulk convert post type(s)
Usage:
Post::bulk_convert(array(1, 2, 3, ...), 'blog');
array
$ids
required - Array of post id'sarray
$actions
required - Array of post type (new type)string
$type
required - Type of post [Optional]voidpublic static function bulk_convert(array $ids, array $actions, $type)
{
$new_type = (string) $actions[0];
$posts = ORM::factory($type)
->where('id', 'IN', $ids)
->find_all();
foreach($posts as $post)
{
// Delete the path aliases associated with this object
Path::delete(array('source' => $post->rawurl));
// Remove the previous terms relationship
$post->remove('terms');
// Remove the previous tags relationship
$post->remove('tags');
// Ipdate the type column in comments
DB::update('comments')
->set(array('type' => $new_type))
->where('post_id', '=', $post->id)
->execute();
// Set the post type to new type
$post->type = $new_type;
// Be sure unpublish the converted posts
$post->status = 'draft';
$post->promote = 0;
$post->sticky = 0;
// Finally update the object
$post->save();
}
}
Bulk delete posts
Usage:
Post::bulk_delete(array(1, 2, 3, ...), 'blog');
array
$ids
required - Array of post id'sstring
$type
= string(4) "post" - Type of post [Optional]voidpublic static function bulk_delete(array $ids, $type = 'post')
{
$posts = ORM::factory($type)
->where('id', 'IN', $ids)
->find_all();
foreach($posts as $post)
{
$post->delete();
}
}
Bulk update posts
Usage:
Post::bulk_update(array(1, 2, 3, ...), array('status' => 'publish', 'promote' => 1), 'blog');
array
$ids
required - Array of post id'sarray
$actions
required - Array of post actionsstring
$type
= string(4) "post" - Type of post [Optional]voidpublic static function bulk_update(array $ids, array $actions, $type = 'post')
{
$posts = ORM::factory($type)
->where('id', 'IN', $ids)
->find_all();
foreach($posts as $post)
{
foreach ($actions as $name => $value)
{
$post->$name = $value;
}
$post->save();
}
}
Dynamic per post cache for performance
integer
$id
required - The post idstring
$type
required - The post typeobject
$config
required - The post type config objectobject - $post The post objectpublic static function dcache($id, $type, $config)
{
$cache = Cache::instance($type);
if( ! $post = $cache->get("$type-$id"))
{
$post = ORM::factory($type, $id);
if ( ! $post->loaded())
{
throw new HTTP_Exception_404('Attempt to non-existent post.');
}
$post->content = View::factory('page/body')->set('config', $config)->bind('post', $post);
$data = array();
$data['author'] = (int)$post->author;
$data['status'] = $post->status;
$data['title'] = $post->title;
$data['comment'] = $post->comment;
$data['url'] = $post->url;
$data['id'] = (int)$post->id;
$data['type'] = $post->type;
$data['content'] = (string) $post->content;
$cache->set("$type-$id", (object) $data, DATE::WEEK);
}
return $post;
}
Deletes a single post or multiple posts, ignoring relationships.
Gleez_Postpublic function delete()
{
if ( ! $this->_loaded)
{
throw new Gleez_Exception('Cannot delete :model model because it is not loaded.',
array(':model' => $this->_object_name)
);
}
$source = $this->rawurl;
parent::delete();
// Delete the path aliases associated with this object
Path::delete(array('source' => $source));
unset($source);
return $this;
}
Validation callback
Validation
$name
required - $validation Validation objectstring
$validation
required - $field Field nameunknown
$field
requiredvoidpublic function is_valid($name, Validation $validation, $field)
{
// Make sure we have a valid term id set
if ($name == 'category')
{
if (isset($this->categories) AND is_array($this->categories))
{
foreach ($this->categories as $id => $term)
{
if ($term == 'last' OR ! Valid::numeric($term))
{
$validation->error('categories', 'invalid', array($validation[$field]));
}
}
}
}
// Make sure we have an valid date is set, or current time
elseif ($name == 'created')
{
if ( ! empty($this->author_date) AND ! ($date = strtotime($this->author_date)))
{
$validation->error($field, 'invalid', array($this->author_date));
}
else
{
if (isset($date))
{
$this->created = $date;
}
}
}
// Make sure we have an valid author id set, or a guest id
elseif ($name == 'autor')
{
if ( ! empty($this->author_name) AND ! ($account = User::lookup_by_name($this->author_name)))
{
$validation->error($field, 'invalid', array($this->author_name));
}
else
{
if (isset($account))
{
$this->author = $account->id;
}
}
}
// Make sure we have an valid date is set, or current time
elseif ($name == 'pubdate')
{
if ( ! empty($this->author_pubdate) AND ! ($date = strtotime($this->author_pubdate)))
{
$validation->error($field, 'invalid', array($validation[$field]));
}
else
{
if (isset($date))
{
$this->pubdate = $date;
}
}
}
}
Labels for fields in this model
array - Labelspublic function labels()
{
return array(
'title' => __('Title'),
'body' => __('Body'),
'teaser' => __('Teaser'),
);
}
List of links
array - Linkspublic function links()
{
$links = array(
'more' => array('link' => $this->url, 'name' => __('Read More')),
'edit' => array('link' => $this->edit_url, 'name' => __('Edit')),
'delete' => array('link' => $this->delete_url, 'name' => __('Delete')),
);
// Unset read more link on full page view
if(Request::current()->uri() == $this->url)
{
unset($links['more']);
}
$values = Module::action('post_links', $links);
return $values;
}
Rules for the post model
array - Rulespublic function rules()
{
return array(
'title' => array(
array('not_empty'),
),
'body' => array(
array('not_empty'),
array('min_length', array(':value', 10)),
),
'author' => array(
array(array($this, 'is_valid'), array('author', ':validation', ':field')),
),
'created' => array(
array(array($this, 'is_valid'), array('created', ':validation', ':field')),
),
'pubdate' => array(
array(array($this, 'is_valid'), array('pubdate', ':validation', ':field')),
),
'status' => array(
array('not_empty'),
array('Post::valid_state', array(':value')),
),
'categories' => array(
array(array($this, 'is_valid'), array('category', ':validation', ':field')),
),
);
}
Updates or Creates the record depending on loaded()
Validation
$validation
= NULL - Validation object [Optional]Gleez_Postpublic function save(Validation $validation = NULL)
{
// Set some defaults
$this->status = empty($this->status) ? 'draft' : $this->status;
$this->promote = empty($this->promote) ? 0 : $this->promote;
$this->sticky = empty($this->sticky) ? 0 : $this->sticky;
$this->comment = empty($this->comment) ? 0 : $this->comment;
$this->created = empty($this->created) ? time() : $this->created;
$this->pubdate = empty($this->pubdate) ? time() : $this->pubdate;
$this->updated = empty($this->updated) ? time() : $this->updated;
$this->type = empty($this->type) ? $this->_post_type : $this->type;
$this->author = empty($this->author) ? User::active_user()->id : $this->author;
$this->format = empty($this->format) ? Kohana::$config->load('inputfilter.default_format', 1) : $this->format;
// Always save only raw text, unformated text
$this->teaser = empty($this->teaser) ? Text::limit_words( $this->rawbody, 105, ' ...') : $this->rawteaser;
$this->body = $this->rawbody;
parent::save( $validation );
if ( $this->loaded())
{
// Add or remove terms
$this->_terms();
// Add or remove tags
$this->_tags();
// Add or remove path aliases
$this->aliases();
}
Cache::instance($this->type)
->delete($this->type.'-'.$this->id);
return $this;
}
List of status
array - Statusespublic static function status()
{
$states = array(
'archive' => __('Archive'),
'draft' => __('Draft'),
'private' => __('Private'),
'publish' => __('Publish'),
);
$values = Module::action('post_status', $states);
return $values;
}
Make sure that the state is legal.
public static function valid_state($value)
{
return in_array($value, array_keys(Post::status()));
}
Display widgets inline of post body
string
$content
required - The post contentstring
$region
= string(11) "post_inline" - The widget's region namestring - The replaced content with widgetspublic static function widgets($content, $region = 'post_inline')
{
// Save some cpu cycles, when the content is empty
if ($content == NULL or empty($content))
{
return $content;
}
// We found special tag, so dont set widgets!
// Just return the content
if (strpos($content, NO_WIDGETS_TAG) !== FALSE)
{
return $content;
}
$poses = array();
$lastpos = -1;
$repchar = "<p";
// if we didn't find a p tag, try br tag
if (strpos($content, "<p") === FALSE)
{
$repchar = "<br";
}
while (strpos($content, $repchar, $lastpos+1) !== FALSE)
{
$lastpos = strpos($content, $repchar, $lastpos+1);
$poses[] = $lastpos;
}
// Cut the doc in half, so the widgets don't go past the end of the article.
$pickme = $poses[ceil(sizeof($poses)/2) -1];
$widgets = Widgets::instance()->render($region);
$replacewith = ($widgets) ? '<div id="'.$region.'" class="clear-block">'.$widgets.'</div>' : NULL;
$content = substr_replace($content, $replacewith.$repchar, $pickme, 2);
// save some memory
unset($poses, $lastpos, $repchar, $half, $pickme, $widgets, $replacewith);
return $content;
}
Determines the name of a foreign key for a specific table.
stringpublic function foreign_key()
{
return Inflector::singular($this->_table_name).$this->_foreign_key_suffix;
}
Restores the object with data from stored version
integer
$version
required - Version number you want to restoreORMpublic function restore($version)
{
if ( ! $this->loaded())
return $this;
$query = DB::select()->from($this->version_table())
->where($this->foreign_key(), '=', $this->pk())
->where('version', '=', $version)
->limit(1)
->execute($this->_db);
if (count($query))
{
$row = $query->current();
foreach ($row as $key => $value)
{
if ($key === $this->_primary_key OR $key === $this->foreign_key() OR $key == 'version_log')
{
// Do not overwrite the primary key
continue;
}
if ($key === 'version')
{
// Always use the current version
//$value = $this->version;
}
$this->__set($key, $value);
}
//this var used to detect is it general update or version update
$this->_restore = true;
$this->update();
}
return $this;
}
Overload ORM::update() to support versioned data
ORMpublic function update(Validation $validation = NULL)
{
if ( ! $this->_restore)
{
$this->_last_version = 1 + ($this->_last_version === NULL ? $this->_object['version'] : $this->_last_version);
$this->__set('version', $this->_last_version);
$object = DB::select()->from($this->_table_name)
->where($this->_primary_key, '=', $this->pk())
->execute($this->_db)->current();
}
parent::update($validation);
// Create version only if its general update not version restore
if ($this->_saved AND ! $this->_restore)
{
$data = array();
foreach ($object as $key => $value)
{
if ($key === $this->_primary_key OR array_key_exists($key, $this->_ignored_columns))
continue;
if ($key === 'version')
{
// Always use the current version
$value = $this->_last_version;
}
//make sure only column names except primary key is stored in revision
if(array_key_exists($key, $this->_table_columns))
$data[$key] = $value;
}
$data[$this->foreign_key()] = $this->id;
DB::insert($this->version_table())
->columns(array_keys($data))
->values(array_values($data))
->execute($this->_db);
}
return $this;
}
Loads a version from current object
ORMpublic function version( $version = FALSE )
{
if ( ! $this->loaded())
return $this;
$query = DB::select()->from($this->version_table())
->where($this->foreign_key(), '=', $this->pk())
->where('version', '=', $version)
->limit(1)
->execute($this->_db);
if (count($query))
{
$this->values($query->current());
}
return $this;
}
Determines the name of a revision specific table.
stringpublic function version_table()
{
return $this->_table_name.'_versions';
}
Constructs a new model and loads a record if given
mixed
$id
= NULL - Parameter for find or object to loadvoidpublic 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 = array();
}
}
Checks if object data is set.
string
$column
required - Column namebooleanpublic 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 valuevoidpublic 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.
stringpublic function __toString()
{
return (string) $this->pk();
}
Unsets object data.
string
$column
required - Column namevoidpublic 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 keysarray
$data
= NULL - Additional data to store in "through"/pivot tableORMpublic function add($alias, $far_keys, $data = NULL)
{
$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();
if ($data !== NULL)
{
// Additional data stored in pivot table
$columns = array_merge($columns, array_keys($data));
}
$query = DB::insert($this->_has_many[$alias]['through'], $columns);
foreach ( (array) $far_keys as $key)
{
$values = array($foreign_key, $key);
if ($data !== NULL)
{
// Additional data stored in pivot table
$values = array_merge($values, array_values($data));
}
$query->values($values);
}
$query->execute($this->_db);
return $this;
}
Creates a new "AND HAVING" condition for the query.
mixed
$column
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
= NULL - Column value$thispublic function and_having($column, $op, $value = NULL)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_having',
'args' => array($column, $op, $value),
);
return $this;
}
Closes an open "AND HAVING (...)" grouping.
$thispublic function and_having_close()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_having_close',
'args' => array(),
);
return $this;
}
Opens a new "AND HAVING (...)" grouping.
$thispublic function and_having_open()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_having_open',
'args' => array(),
);
return $this;
}
Creates a new "AND WHERE" condition for the query.
mixed
$column
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
required - Column value$thispublic function and_where($column, $op, $value)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_where',
'args' => array($column, $op, $value),
);
return $this;
}
Closes an open "AND WHERE (...)" grouping.
$thispublic function and_where_close()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_where_close',
'args' => array(),
);
return $this;
}
Opens a new "AND WHERE (...)" grouping.
$thispublic function and_where_open()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'and_where_open',
'args' => array(),
);
return $this;
}
Returns the values of this object as an array, including any related one-one models that have already been loaded using with()
arraypublic function as_array()
{
$object = array();
$extra = array('url', 'edit_url', 'delete_url');
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();
}
foreach ($extra as $column)
{
try
{
// Call __get for any user processing
$object[$column] = $this->__get($column);
}catch(Exception $e){}
}
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$thispublic function cached($lifetime = NULL)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'cached',
'args' => array($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 changesbool - Whether or not the field has changedpublic 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 objectORMpublic 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();
// add custom rules to $this->_validation();
Module::event($this->_object_name .'_validation', $this->_validation, $extra_errors);
$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);
}
$this->_validation = NULL; //Fixed memory leak @http://dev.kohanaframework.org/issues/4286
throw $exception;
}
$this->_validation = NULL; //Fixed memory leak @http://dev.kohanaframework.org/issues/4286
return $this;
}
Unloads the current object and clears the status.
ORMpublic 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 = array();
// Replace the current object with an empty one
$this->_load_values($values);
// Reset primary key
$this->_primary_key_value = NULL;
$this->reset();
return $this;
}
Count the number of records in the table.
integerpublic 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]);
}
elseif ($method['name'] == 'order_by')
{
// Also, ignore order clause
$order_by[$key] = $method; // Fix of the fix here!
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(array($this->_table_name, $this->_object_name))
->select(array('COUNT("*")', 'records_found'))
->execute($this->_db)
->get('records_found');
// Add back in selected columns
//$this->_db_pending += $selects;
$this->_db_pending = array_merge($this->_db_pending, $selects);
if( isset($order_by) )
{
// Add back in order_by clause
//$this->_db_pending += $order_by;
$this->_db_pending = array_merge($this->_db_pending, $order_by);
}
$this->reset();
// Return the total number of records in a table
return $records;
}
Insert a new object to the database added event support
Validation
$validation
= NULL - Validation objectORMpublic 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));
Module::event($this->_object_name .'_prevalid', $this, $validation);
// Require model validation before saving
if ( ! $this->_valid OR $validation)
{
$this->check($validation);
}
$this->before_save();
Module::event($this->_object_name .'_presave', $this, $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];
}
// Object is now loaded and saved
$this->_loaded = $this->_saved = TRUE;
// All changes have been saved
$this->_changed = array();
$this->_original_values = $this->_object;
$this->after_save();
Module::event($this->_object_name .'_save', $this);
return $this;
}
public function created_column()
{
return $this->_created_column;
}
Setter/Getter for jquery DataTables support
object - DataTablespublic function dataTables(array $columns = NULL)
{
if ( ! empty($columns) )
{
$this->_datatables = DataTables::factory($this)->columns($columns)->execute();
}
return $this->_datatables;
}
Delete all objects in the associated table. This does NOT destroy relationships that have been created with other objects.
ORMpublic function delete_all()
{
if ( $this->_loaded)
throw new Kohana_Exception('Cannot delete all :model model because it is loaded.', array(':model' => $this->_object_name));
Module::event($this->_object_name .'_pre_delete_all', $this);
$this->_build(ORM::DELETE);
$this->_db_builder->execute($this->_db);
Module::event($this->_object_name .'_delete_all', $this);
return $this->clear();
}
Enables or disables selecting only unique columns using "SELECT DISTINCT"
boolean
$value
required - Enable or disable distinct columns$thispublic function distinct($value)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'distinct',
'args' => array($value),
);
return $this;
}
public function errors_filename()
{
return $this->_errors_filename;
}
Creates and returns a new model.
string
$model
required - Model namemixed
$id
= NULL - Parameter for find()ORMpublic static function factory($model, $id = NULL)
{
// Set class name
$model = 'Model_'.ucfirst($model);
return new $model($id);
}
Filter definitions for validation
arraypublic function filters()
{
return array();
}
Finds and loads a single database row into the object.
ORMpublic 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_Resultpublic 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);
}
Finds or creates a model instance with the given values
array
$values
required - $values$thispublic function find_or_create($values)
{
// Unload any previously loaded objects
$this->clear();
// Attempt to find the object
foreach ($values as $key => $value)
{
$this->where($key, '=', $value);
}
$found = $this->find()->loaded();
if ($found)
{
return $this;
}
else
{
$this->values($values);
$s = $this->save();
return $s;
}
}
Choose the tables to select "FROM ..."
mixed
$tables
required - Table name or array($table, $alias) or object$thispublic function from($tables)
{
$tables = func_get_args();
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'from',
'args' => $tables,
);
return $this;
}
Creates a "GROUP BY ..." filter.
mixed
$columns
required - Column name or array($column, $alias) or object$thispublic function group_by($columns)
{
$columns = func_get_args();
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'group_by',
'args' => $columns,
);
return $this;
}
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));
// Check if $model has any roles
$model->has('roles')
string
$alias
required - Alias of the has_many "through" relationshipmixed
$far_keys
= NULL - Related model, primary key, or an array of primary keysDatabase_Resultpublic function has($alias, $far_keys = NULL)
{
if ($far_keys === NULL)
{
return (bool) DB::select(array('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 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);
}
public function has_many()
{
return $this->_has_many;
}
public function has_many_keys()
{
return $this->_has_many_keys;
}
public function has_one()
{
return $this->_has_one;
}
Alias of and_having()
mixed
$column
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
= NULL - Column value$thispublic function having($column, $op, $value = NULL)
{
return $this->and_having($column, $op, $value);
}
Closes an open "AND HAVING (...)" grouping.
$thispublic function having_close()
{
return $this->and_having_close();
}
Alias of and_having_open()
$thispublic function having_open()
{
return $this->and_having_open();
}
Adds addition tables to "JOIN ...".
mixed
$table
required - Column name or array($column, $alias) or objectstring
$type
= NULL - Join type (LEFT, RIGHT, INNER, etc)$thispublic function join($table, $type = NULL)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'join',
'args' => array($table, $type),
);
return $this;
}
Returns last executed query
stringpublic function last_query()
{
return $this->_db->last_query;
}
Return up to "LIMIT ..." results
integer
$number
required - Maximum results to return$thispublic function limit($number)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'limit',
'args' => array($number),
);
return $this;
}
Proxy method to Database list_columns.
arraypublic 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;
}
Adds "ON ..." conditions for the last created JOIN statement.
mixed
$c1
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$c2
required - Column name or array($column, $alias) or object$thispublic function my_on($c1, $op, $c2)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'join_and',
'args' => array($c1, $op, $c2),
);
return $this;
}
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$thispublic function offset($number)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'offset',
'args' => array($number),
);
return $this;
}
Adds "ON ..." conditions for the last created JOIN statement.
mixed
$c1
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$c2
required - Column name or array($column, $alias) or object$thispublic function on($c1, $op, $c2)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'on',
'args' => array($c1, $op, $c2),
);
return $this;
}
Creates a new "OR HAVING" condition for the query.
mixed
$column
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
= NULL - Column value$thispublic function or_having($column, $op, $value = NULL)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_having',
'args' => array($column, $op, $value),
);
return $this;
}
Closes an open "OR HAVING (...)" grouping.
$thispublic function or_having_close()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_having_close',
'args' => array(),
);
return $this;
}
Opens a new "OR HAVING (...)" grouping.
$thispublic function or_having_open()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_having_open',
'args' => array(),
);
return $this;
}
Creates a new "OR WHERE" condition for the query.
mixed
$column
required - Column name or array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
required - Column value$thispublic function or_where($column, $op, $value)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_where',
'args' => array($column, $op, $value),
);
return $this;
}
Closes an open "OR WHERE (...)" grouping.
$thispublic function or_where_close()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_where_close',
'args' => array(),
);
return $this;
}
Opens a new "OR WHERE (...)" grouping.
$thispublic function or_where_open()
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'or_where_open',
'args' => array(),
);
return $this;
}
Applies sorting with "ORDER BY ..."
mixed
$column
required - Column name or array($column, $alias) or objectstring
$direction
= NULL - Direction of sorting$thispublic function order_by($column, $direction = NULL)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'order_by',
'args' => array($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 replacemixed
$value
required - Value to use$thispublic function param($param, $value)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'param',
'args' => array($param, $value),
);
return $this;
}
Returns the value of the primary key
mixed - Primary keypublic function pk()
{
return $this->_primary_key_value;
}
public function primary_key()
{
return $this->_primary_key;
}
Reloads the current object from the database.
ORMpublic function reload()
{
$primary_key = $this->pk();
// Replace the object and reset the object status
$this->_object = $this->_changed = $this->_related = $this->_original_values = array();
// 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 reloadingORMpublic 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(TRUE);
// 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 keysORMpublic 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 callORMpublic 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;
}
public function saved()
{
return $this->_saved;
}
Choose the columns to select from.
mixed
$columns
= NULL - Column name or array($column, $alias) or object$thispublic function select($columns = NULL)
{
$columns = func_get_args();
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'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.
arraypublic function serialize()
{
// Store only information about the object
foreach (array('_primary_key_value', '_object', '_changed', '_loaded', '_saved', '_sorting', '_original_values', '_ignored_columns') as $var)
{
$data[$var] = $this->{$var};
}
return serialize($data);
}
Handles setting of column
string
$column
required - Column namemixed
$value
required - Column valuevoidpublic 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->_ignored_columns))
{
// No processing for ignored columns, just store it
$this->_object[$column] = $value;
}
elseif (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;
}
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 uniquenessmixed
$value
required - The value to check for uniquenessbool - Whteher the value is uniquepublic 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 unserializationvoidpublic 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();
}
}
public function updated()
{
return $this->_updated;
}
public function updated_column()
{
return $this->_updated_column;
}
Adds "USING ..." conditions for the last created JOIN statement.
string
$columns
required - Column name$thispublic function using($columns)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'using',
'args' => array($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 => valarray
$expected
= NULL - Array of keys to take from $valuesORMpublic 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]);
}
if ( ! empty($this->_ignored_columns) )
{
// merge the columns needed to process
$expected = array_merge($expected, array_keys($this->_ignored_columns) );
}
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 array($column, $alias) or objectstring
$op
required - Logic operatormixed
$value
required - Column value$thispublic function where($column, $op, $value)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'where',
'args' => array($column, $op, $value),
);
return $this;
}
Closes an open "AND WHERE (...)" grouping.
$thispublic function where_close()
{
return $this->and_where_close();
}
Alias of and_where_open()
$thispublic 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 tovoidpublic 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(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;
}
Adds or deletes path aliases
voidprotected function aliases()
{
// Create and save alias for the post
$values = array();
$path = Path::load($this->rawurl);
if ($path)
{
$values['id'] = (int) $path['id'];
}
$alias = empty($this->path) ? $this->_object_plural.'/'.$this->title : $this->path;
$values['source'] = $this->rawurl;
$values['alias'] = Path::clean( $alias );
$values['type'] = NULL;
$values['action'] = empty($this->action) ? $this->type : $this->action;
$values = Module::action('post_aliases', $values, $this);
Path::save($values);
}
Initializes the Database Builder to given query type
integer
$type
required - Type of Database queryORMprotected 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(array($this->_table_name, $this->_object_name));
break;
case Database::DELETE:
$this->_db_builder = DB::delete(array($this->_table_name, $this->_object_name));
break;
case ORM::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->_object_name.'.'.$column, $column);
}
return $columns;
}
Prepares the model database connection, determines the table name, and loads column information.
voidprotected function _initialize()
{
// Set the object name and plural 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 = array(
'_belongs_to' => array(),
'_has_one' => array(),
'_has_many' => array(),
'_has_many_keys' => array(),
);
// 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);
}
}
if ( ! empty($this->_ignored_columns))
{
// Optimize for performance
$init['_ignored_columns']= array_combine($this->_ignored_columns, $this->_ignored_columns);
}
$defaults = array();
foreach ($this->_belongs_to as $alias => $details)
{
$defaults['model'] = $alias;
$defaults['foreign_key'] = $alias.$this->_foreign_key_suffix;
$init['_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;
$init['_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;
$init['_has_many'][$alias] = array_merge($defaults, $details);
}
foreach ($this->_has_many_keys as $alias => $details)
{
$defaults['model'] = Inflector::singular($alias);
$defaults['foreign_key'] = array($this->_object_name.$this->_foreign_key_suffix);
$defaults['far_key'] = array(Inflector::singular($alias).$this->_foreign_key_suffix);
$init['_has_many_keys'][$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 rowORM|Database_Resultprotected function _load_result($multiple = FALSE)
{
$this->_db_builder->from(array($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($this->_object_name.'.*');
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 loadORMprotected 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 = 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);
}
}
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 nameORMprotected 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);
}
Initializes validation rules, and labels
voidprotected 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);
}
}
Override this method to take actions after the document is deleted
protected function after_delete($id){}
Override this method to take actions after the values are loaded
protected function after_load(){}
Override this method to take actions after data is saved
protected function after_save(){}
Override this method to take actions before the document is deleted
protected function before_delete($id){}
Override this method to take actions before the values are loaded
protected function before_load(){}
Override this method to take certain actions before the data is saved
protected function before_save(){}
Filters a value for a specific column
string
$field
required - The column namestring
$value
required - The value to filterstringprotected 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;
}
Adds or deletes terms
voidprivate function _tags()
{
if (isset($this->ftags))
{
$tags = Tags::factory()
->tagging($this->ftags, $this, $this->author, false);
}
}
Adds or deletes terms
voidprivate function _terms()
{
if ( !empty($this->categories))
{
// Filter out empty terms
$this->categories = array_filter($this->categories);
}
if (isset($this->categories) AND is_array($this->categories))
{
// Remove the previous terms relationship
$this->remove('terms');
foreach ($this->categories as $id => $term)
{
// Add the term relationship
if ( isset($term) AND !empty($term) AND $term != 'last')
{
$this->add('terms', (int)$term, array('parent_id' => (int)$id, 'type' => $this->type));
}
}
}
}