Source for file table.php
Documentation is available at table.php
* @package Joomla.Platform
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
* Parent class to all tables.
* @package Joomla.Platform
* @link http://docs.joomla.org/JTable
* @tutorial Joomla.Platform/jtable.cls
* Include paths for searching for JTable classes.
private static $_includePaths =
array();
* Name of the database table to model.
* Name of the primary key field in the table.
* Name of the primary key fields in the table.
* JDatabaseDriver object.
* Should rows be tracked as ACL assets?
* The rules associated with this record.
* @var JAccessRules A JAccessRules object.
* Indicator that the tables have been locked.
* Indicates that the primary keys autoincrement.
* Generic observers for this JTable (Used e.g. for tags Processing)
* Object constructor to set table and key fields. In most cases this will
* be overridden by child classes to explicitly set the table and key fields
* for a particular database table.
* @param string $table Name of the table to model.
* @param mixed $key Name of the primary key field in the table or array of field names that compose the primary key.
* @param JDatabaseDriver $db JDatabaseDriver object.
public function __construct($table, $key, JDatabaseDriver $db)
// Set internal variables.
// Set the key to be an array.
// Set the singular table key for backwards compatibility.
// Initialise the table properties.
foreach ($fields as $name =>
$v)
// Add the field if it is not already present.
// If we are tracking assets, make sure an access field exists and initially set the default.
// If the access property exists, set the default.
// Implement JObservableInterface:
// Create observer updater and attaches all observers interested by $this class:
* Implement JObservableInterface:
* Adds an observer to this instance.
* This method will be called fron the constructor of classes implementing JObserverInterface
* which is instanciated by the constructor of $this with JObserverMapper::attachAllObservers($this)
* @param JObserverInterface|JTableObserver $observer The observer object
* Gets the instance of the observer of class $observerClass
* @param string $observerClass The observer class-name to return the object of
* @return JTableObserver|null
* Get the columns from database table.
* @return mixed An array of the field names, or false if an error occurs.
* @throws UnexpectedValueException
// Lookup the fields for this table only once.
$fields =
$this->_db->getTableColumns($name, false);
throw
new UnexpectedValueException(sprintf('No columns found for %s table', $name));
* Static method to get an instance of a JTable class if it can be found in
* the table include paths. To add include paths for searching for JTable
* classes see JTable::addIncludePath().
* @param string $type The type (name) of the JTable class to get an instance of.
* @param string $prefix An optional prefix for the table class name.
* @param array $config An optional array of configuration values for the JTable object.
* @return mixed A JTable object if found or boolean false if one could not be found.
* @link http://docs.joomla.org/JTable/getInstance
public static function getInstance($type, $prefix =
'JTable', $config =
array())
// Sanitize and prepare the table class name.
$tableClass =
$prefix .
ucfirst($type);
// Only try to load the class if it doesn't already exist.
// Search for the class file in the JTable include paths.
// Import the class file.
// If we were unable to load the proper class, raise a warning and return false.
// If we were unable to find the class file in the JTable include paths, raise a warning and return false.
// If a database object was passed in the configuration array use it, otherwise get the global one from JFactory.
// Instantiate a new table class and return it.
return new $tableClass($db);
* Add a filesystem path where JTable should search for table class files.
* You may either pass a string or an array of paths.
* @param mixed $path A filesystem path or array of filesystem paths to add.
* @return array An array of filesystem paths to find JTable classes in.
* @link http://docs.joomla.org/JTable/addIncludePath
// If the internal paths have not been initialised, do so with the base table path.
if (empty(self::$_includePaths))
self::$_includePaths =
array(__DIR__
);
// Convert the passed path(s) to add to an array.
// If we have new paths to add, do so.
// Check and add each individual new path.
// Add to the front of the list so that custom paths are searched first.
if (!in_array($dir, self::$_includePaths))
array_unshift(self::$_includePaths, $dir);
return self::$_includePaths;
* Method to compute the default name of the asset.
* The default name is in the form table_name.id
* where id is the value of the primary key of the table.
protected function _getAssetName()
$keys[] = (int)
$this->$k;
* Method to return the title to use for the asset table. In
* tracking the assets a title is kept for each asset so that there is some
* context available in a unified access manager. Usually this would just
* return $this->title or $this->name or whatever is being used for the
* primary name of the row. If this method is not overridden, the asset name is used.
* @return string The string to use as the title in the asset table.
* @link http://docs.joomla.org/JTable/getAssetTitle
* Method to get the parent asset under which to register this one.
* By default, all assets are registered to the ROOT node with ID,
* which will default to 1 if none exists.
* The extended class can define a table and id to lookup. If the
* asset does not exist it will be created.
* @param JTable $table A JTable object for the asset parent.
* @param integer $id Id to look up
// For simple cases, parent to the asset root.
$assets =
self::getInstance('Asset', 'JTable', array('dbo' =>
$this->getDbo()));
$rootId =
$assets->getRootId();
* Method to append the primary keys for this table to a query.
* @param JDatabaseQuery $query A query object to append.
* @param mixed $pk Optional primary key parameter.
$query->where($this->_db->quoteName($k) .
' = ' .
$this->_db->quote($this->$k));
$query->where($this->_db->quoteName($k) .
' = ' .
$this->_db->quote($pk->$k));
* Method to get the database table name for the class.
* @return string The name of the database table being modeled.
* @link http://docs.joomla.org/JTable/getTableName
* Method to get the primary key field name for the table.
* @param boolean $multiple True to return all primary keys (as an array) or false to return just the first one (as a string).
* @return mixed Array of primary key field names or string containing the first primary key field.
* @link http://docs.joomla.org/JTable/getKeyName
// Count the number of keys
// If we want multiple keys, return the raw array.
// If we want the standard method, just return the first key.
* Method to get the JDatabaseDriver object.
* @return JDatabaseDriver The internal database driver object.
* @link http://docs.joomla.org/JTable/getDBO
* Method to set the JDatabaseDriver object.
* @param JDatabaseDriver $db A JDatabaseDriver object to be used by the table object.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/setDBO
public function setDBO(JDatabaseDriver $db)
* Method to set rules for the record.
* @param mixed $input A JAccessRules object, JSON string, or array.
* Method to get the rules for the record.
* @return JAccessRules object
* Method to reset class properties to the defaults set in the class
* definition. It will ignore the primary key as well as any private class
* properties (except $_errors).
* @link http://docs.joomla.org/JTable/reset
// Get the default values for the class from the table.
// If the property is not the primary key or private, reset it.
* Method to bind an associative array or object to the JTable instance.This
* method only binds properties that are publicly accessible and optionally
* takes an array of properties to ignore when binding.
* @param mixed $src An associative array or object to bind to the JTable instance.
* @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/bind
* @throws InvalidArgumentException
public function bind($src, $ignore =
array())
// If the source value is not an array or object return false.
// If the source value is an object, get its accessible properties.
// If the ignore value is a string, explode it over spaces.
// Bind the source value, excluding the ignored fields.
// Only process fields not in the ignore array.
* Method to load a row from the database by primary key and bind the fields
* to the JTable instance properties.
* @param mixed $keys An optional primary key value to load the row by, or an array of fields to match. If not
* set the instance property value is used.
* @param boolean $reset True to reset the default values before loading the new row.
* @return boolean True if successful. False if row not found.
* @link http://docs.joomla.org/JTable/load
* @throws InvalidArgumentException
* @throws RuntimeException
* @throws UnexpectedValueException
public function load($keys =
null, $reset =
true)
// Implement JObservableInterface: Pre-processing by observers
$this->_observers->update('onBeforeLoad', array($keys, $reset));
// If empty, use the value of the current key
$empty =
$empty &&
empty($this->$key);
$keys[$key] =
$this->$key;
// If empty primary key there's is no need to load anything
throw
new InvalidArgumentException('Table has multiple primary keys specified, only one primary key value provided.');
throw
new RuntimeException('No table keys defined.');
$query =
$this->_db->getQuery(true)
foreach ($keys as $field =>
$value)
// Check that $field is in the table.
throw
new UnexpectedValueException(sprintf('Missing field in database: %s   %s.', get_class($this), $field));
// Add the search tuple to the query.
$query->where($this->_db->quoteName($field) .
' = ' .
$this->_db->quote($value));
$this->_db->setQuery($query);
$row =
$this->_db->loadAssoc();
// Check that we have a result.
// Bind the object with the row and return.
$result =
$this->bind($row);
// Implement JObservableInterface: Post-processing by observers
$this->_observers->update('onAfterLoad', array(&$result, $row));
* Method to perform sanity checks on the JTable instance properties to ensure
* they are safe to store in the database. Child classes should override this
* method to make sure the data they are storing in the database is safe and
* as expected before storage.
* @return boolean True if the instance is sane and able to be stored in the database.
* @link http://docs.joomla.org/JTable/check
* Method to store a row in the database from the JTable instance properties.
* If a primary key value is set the row with that primary key value will be
* updated with the instance property values. If no primary key value is set
* a new row will be inserted into the database with the properties from the
* @param boolean $updateNulls True to update fields even if they are null.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/store
public function store($updateNulls =
false)
// Implement JObservableInterface: Pre-processing by observers
$this->_observers->update('onBeforeStore', array($updateNulls, $k));
if (!empty($this->asset_id))
$currentAssetId =
$this->asset_id;
// The asset id field is managed privately by this class.
// If a primary key exists update the object, otherwise insert it.
$result =
$this->_db->updateObject($this->_tbl, $this, $this->_tbl_keys, $updateNulls);
// If the table is not set to track assets return true.
$asset =
self::getInstance('Asset', 'JTable', array('dbo' =>
$this->getDbo()));
$asset->loadByName($name);
// Re-inject the asset id.
$this->asset_id =
$asset->id;
// Specify how a new or moved node asset is inserted into the tree.
if (empty($this->asset_id) ||
$asset->parent_id !=
$parentId)
$asset->setLocation($parentId, 'last-child');
// Prepare the asset to be stored.
$asset->parent_id =
$parentId;
$asset->rules = (string)
$this->_rules;
if (!$asset->check() ||
!$asset->store($updateNulls))
// Create an asset_id or heal one that is corrupted.
if (empty($this->asset_id) ||
($currentAssetId !=
$this->asset_id &&
!empty($this->asset_id)))
// Update the asset_id field in this table.
$this->asset_id = (int)
$asset->id;
$query =
$this->_db->getQuery(true)
->update($this->_db->quoteName($this->_tbl))
->set('asset_id = ' . (int)
$this->asset_id);
// Implement JObservableInterface: Post-processing by observers
$this->_observers->update('onAfterStore', array(&$result));
* Method to provide a shortcut to binding, checking and storing a JTable
* instance to the database table. The method will check a row in once the
* data has been stored and if an ordering filter is present will attempt to
* reorder the table rows based on the filter. The ordering filter is an instance
* property name. The rows that will be reordered are those whose value matches
* the JTable instance for the property specified.
* @param mixed $src An associative array or object to bind to the JTable instance.
* @param string $orderingFilter Filter for the order updating
* @param mixed $ignore An optional array or space separated list of properties
* to ignore while binding.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/save
public function save($src, $orderingFilter =
'', $ignore =
'')
// Attempt to bind the source to the instance.
if (!$this->bind($src, $ignore))
// Run any sanity checks on the instance and verify that it is ready for storage.
// Attempt to store the properties to the database table.
// Attempt to check the row in, just in case it was checked out.
// If an ordering filter is set, attempt reorder the rows in the table based on the filter and value.
$filterValue =
$this->$orderingFilter;
$this->reorder($orderingFilter ?
$this->_db->quoteName($orderingFilter) .
' = ' .
$this->_db->quote($filterValue) :
'');
// Set the error to empty and return true.
* Method to delete a row from the database table by primary key value.
* @param mixed $pk An optional primary key value to delete. If not set the instance property value is used.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/delete
* @throws UnexpectedValueException
public function delete($pk =
null)
$pk[$key] =
is_null($pk[$key]) ?
$this->$key :
$pk[$key];
throw
new UnexpectedValueException('Null primary key not allowed.');
// Implement JObservableInterface: Pre-processing by observers
$this->_observers->update('onBeforeDelete', array($pk));
// If tracking assets, remove the asset first.
$asset =
self::getInstance('Asset');
if ($asset->loadByName($name))
// Delete the row by primary key.
$query =
$this->_db->getQuery(true)
$this->_db->setQuery($query);
// Check for a database error.
// Implement JObservableInterface: Post-processing by observers
$this->_observers->update('onAfterDelete', array($pk));
* Method to check a row out if the necessary properties/fields exist. To
* prevent race conditions while editing rows in a database, a row can be
* checked out if the fields 'checked_out' and 'checked_out_time' are available.
* While a row is checked out, any attempt to store the row by a user other
* than the one who checked the row out should be held until the row is checked
* @param integer $userId The Id of the user checking out the row.
* @param mixed $pk An optional primary key value to check out. If not set
* the instance property value is used.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/checkOut
* @throws UnexpectedValueException
public function checkOut($userId, $pk =
null)
// If there is no checked_out or checked_out_time field, just return true.
$pk[$key] =
is_null($pk[$key]) ?
$this->$key :
$pk[$key];
throw
new UnexpectedValueException('Null primary key not allowed.');
// Get the current time in the database format.
// Check the row out by primary key.
$query =
$this->_db->getQuery(true)
->set($this->_db->quoteName('checked_out') .
' = ' . (int)
$userId)
->set($this->_db->quoteName('checked_out_time') .
' = ' .
$this->_db->quote($time));
$this->_db->setQuery($query);
// Set table values in the object.
$this->checked_out = (int)
$userId;
$this->checked_out_time =
$time;
* Method to check a row in if the necessary properties/fields exist. Checking
* a row in will allow other users the ability to edit the row.
* @param mixed $pk An optional primary key value to check out. If not set the instance property value is used.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/checkIn
* @throws UnexpectedValueException
public function checkIn($pk =
null)
// If there is no checked_out or checked_out_time field, just return true.
$pk[$this->$key] =
$this->$key;
$pk[$key] =
empty($pk[$key]) ?
$this->$key :
$pk[$key];
throw
new UnexpectedValueException('Null primary key not allowed.');
// Check the row in by primary key.
$query =
$this->_db->getQuery(true)
->set($this->_db->quoteName('checked_out') .
' = 0')
->set($this->_db->quoteName('checked_out_time') .
' = ' .
$this->_db->quote($this->_db->getNullDate()));
$this->_db->setQuery($query);
// Check for a database error.
// Set table values in the object.
$this->checked_out_time =
'';
* Validate that the primary key has been set.
* @return boolean True if the primary key(s) have been set.
$empty =
$empty &&
empty($this->$key);
$query =
$this->_db->getQuery(true)
$this->_db->setQuery($query);
$count =
$this->_db->loadResult();
* Method to increment the hits for a row if the necessary property/field exists.
* @param mixed $pk An optional primary key value to increment. If not set the instance property value is used.
* @return boolean True on success.
* @link http://docs.joomla.org/JTable/hit
* @throws UnexpectedValueException
public function hit($pk =
null)
// If there is no hits field, just return true.
$pk[$key] =
is_null($pk[$key]) ?
$this->$key :
$pk[$key];
throw
new UnexpectedValueException('Null primary key not allowed.');
// Check the row in by primary key.
$query =
$this->_db->getQuery(true)
->set($this->_db->quoteName('hits') .
' = (' .
$this->_db->quoteName('hits') .
' + 1)');
$this->_db->setQuery($query);
// Set table values in the object.
* Method to determine if a row is checked out and therefore uneditable by
* a user. If the row is checked out by the same user, then it is considered
* not checked out -- as the user can still edit it.
* @param integer $with The userid to preform the match with, if an item is checked
* out by this user the function will return false.
* @param integer $against The userid to perform the match against when the function
* is used as a static function.
* @return boolean True if checked out.
* @link http://docs.joomla.org/JTable/isCheckedOut
// Handle the non-static case.
if (isset
($this) &&
($this instanceof
JTable) &&
is_null($against))
$against =
$this->get('checked_out');
// The item is not checked out or is checked out by the same user.
if (!$against ||
($against ==
$with))
$db->setQuery('SELECT COUNT(userid) FROM ' .
$db->quoteName('#__session') .
' WHERE ' .
$db->quoteName('userid') .
' = ' . (int)
$against);
$checkedOut = (boolean)
$db->loadResult();
// If a session exists for the user then it is checked out.
* Method to get the next ordering value for a group of rows defined by an SQL WHERE clause.
* This is useful for placing a new item last in a group of items in the table.
* @param string $where WHERE clause to use for selecting the MAX(ordering) for the table.
* @return mixed Boolean false an failure or the next ordering value as an integer.
* @link http://docs.joomla.org/JTable/getNextOrder
* @throws UnexpectedValueException
// If there is no ordering field set an error and return false.
throw
new UnexpectedValueException(sprintf('%s does not support ordering.', get_class($this)));
// Get the largest ordering value for a given where clause.
$query =
$this->_db->getQuery(true)
->select('MAX(ordering)')
$this->_db->setQuery($query);
$max = (int)
$this->_db->loadResult();
// Return the largest ordering value + 1.
* Get the primary key values for this table using passed in values as a default.
* @param array $keys Optional primary key values to use.
* @return array An array of primary key names and values.
$keys[$key] =
$this->$key;
* Method to compact the ordering values of rows in a group of rows
* defined by an SQL WHERE clause.
* @param string $where WHERE clause to use for limiting the selection of rows to compact the ordering values.
* @return mixed Boolean True on success.
* @link http://docs.joomla.org/JTable/reorder
* @throws UnexpectedValueException
public function reorder($where =
'')
// If there is no ordering field set an error and return false.
throw
new UnexpectedValueException(sprintf('%s does not support ordering.', get_class($this)));
// Get the primary keys and ordering values for the selection.
$query =
$this->_db->getQuery(true)
// Setup the extra where and ordering clause data.
$this->_db->setQuery($query);
$rows =
$this->_db->loadObjectList();
// Compact the ordering values.
foreach ($rows as $i =>
$row)
// Make sure the ordering is a positive integer.
// Only update rows that are necessary.
// Update the row ordering field.
->set('ordering = ' .
($i +
1));
$this->_db->setQuery($query);
* Method to move a row in the ordering sequence of a group of rows defined by an SQL WHERE clause.
* Negative numbers move the row up in the sequence and positive numbers move it down.
* @param integer $delta The direction and magnitude to move the row in the ordering sequence.
* @param string $where WHERE clause to use for limiting the selection of rows to compact the
* @return mixed Boolean True on success.
* @link http://docs.joomla.org/JTable/move
* @throws UnexpectedValueException
public function move($delta, $where =
'')
// If there is no ordering field set an error and return false.
throw
new UnexpectedValueException(sprintf('%s does not support ordering.', get_class($this)));
// If the change is none, do nothing.
$query =
$this->_db->getQuery(true);
// Select the primary key and ordering values from the table.
// If the movement delta is negative move the row up.
$query->where('ordering < ' . (int)
$this->ordering)
->order('ordering DESC');
// If the movement delta is positive move the row down.
$query->where('ordering > ' . (int)
$this->ordering)
// Add the custom WHERE clause if set.
// Select the first row with the criteria.
$this->_db->setQuery($query, 0, 1);
$row =
$this->_db->loadObject();
// If a row is found, move the item.
// Update the ordering field for this instance to the row's ordering value.
$this->_db->setQuery($query);
// Update the ordering field for the row to this instance's ordering value.
$this->_db->setQuery($query);
// Update the instance value.
// Update the ordering field for this instance.
$this->_db->setQuery($query);
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
* @param mixed $pks An optional array of primary key values to update.
* If not set the instance property value is used.
* @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* @param integer $userId The user id of the user performing the operation.
* @return boolean True on success; false if $pks is empty.
* @link http://docs.joomla.org/JTable/publish
public function publish($pks =
null, $state =
1, $userId =
0)
foreach ($pks AS $key =>
$pk)
$pks[$key] =
array($this->_tbl_key =>
$pk);
// If there are no primary keys set check to see if the instance key is set.
$pk[$this->$key] =
$this->$key;
// We don't have a full primary key - return false
// Update the publishing state for rows with the given primary keys.
$query =
$this->_db->getQuery(true)
->set('published = ' . (int)
$state);
// Determine if there is checkin support for the table.
$query->where('(checked_out = 0 OR checked_out = ' . (int)
$userId .
')');
// Build the WHERE clause for the primary keys.
$this->_db->setQuery($query);
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin &&
(count($pks) ==
$this->_db->getAffectedRows()))
if ($this->$key !=
$pk[$key])
$this->published =
$state;
* Method to lock the database table for writing.
* @return boolean True on success.
* @throws RuntimeException
protected function _lock()
$this->_db->lockTable($this->_tbl);
* Method to unlock the database table for writing.
* @return boolean True on success.
$this->_db->unlockTables();
Documentation generated on Tue, 19 Nov 2013 15:14:51 +0100 by phpDocumentor 1.4.3