Source for file table.php

Documentation is available at table.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Table
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. jimport('joomla.filesystem.path');
  13.  
  14. /**
  15.  * Abstract Table class
  16.  *
  17.  * Parent class to all tables.
  18.  *
  19.  * @package     Joomla.Platform
  20.  * @subpackage  Table
  21.  * @link        http://docs.joomla.org/JTable
  22.  * @since       11.1
  23.  * @tutorial    Joomla.Platform/jtable.cls
  24.  */
  25. abstract class JTable extends JObject implements JObservableInterface
  26. {
  27.     /**
  28.      * Include paths for searching for JTable classes.
  29.      *
  30.      * @var    array 
  31.      * @since  12.1
  32.      */
  33.     private static $_includePaths array();
  34.  
  35.     /**
  36.      * Name of the database table to model.
  37.      *
  38.      * @var    string 
  39.      * @since  11.1
  40.      */
  41.     protected $_tbl = '';
  42.  
  43.     /**
  44.      * Name of the primary key field in the table.
  45.      *
  46.      * @var    string 
  47.      * @since  11.1
  48.      */
  49.     protected $_tbl_key = '';
  50.  
  51.     /**
  52.      * Name of the primary key fields in the table.
  53.      *
  54.      * @var    array 
  55.      * @since  12.2
  56.      */
  57.     protected $_tbl_keys = array();
  58.  
  59.     /**
  60.      * JDatabaseDriver object.
  61.      *
  62.      * @var    JDatabaseDriver 
  63.      * @since  11.1
  64.      */
  65.     protected $_db;
  66.  
  67.     /**
  68.      * Should rows be tracked as ACL assets?
  69.      *
  70.      * @var    boolean 
  71.      * @since  11.1
  72.      */
  73.     protected $_trackAssets = false;
  74.  
  75.     /**
  76.      * The rules associated with this record.
  77.      *
  78.      * @var    JAccessRules  A JAccessRules object.
  79.      * @since  11.1
  80.      */
  81.     protected $_rules;
  82.  
  83.     /**
  84.      * Indicator that the tables have been locked.
  85.      *
  86.      * @var    boolean 
  87.      * @since  11.1
  88.      */
  89.     protected $_locked = false;
  90.  
  91.     /**
  92.      * Indicates that the primary keys autoincrement.
  93.      *
  94.      * @var    boolean 
  95.      * @since  12.3
  96.      */
  97.     protected $_autoincrement = true;
  98.  
  99.     /**
  100.      * Generic observers for this JTable (Used e.g. for tags Processing)
  101.      *
  102.      * @var    JObserverUpdater 
  103.      * @since  3.1.2
  104.      */
  105.     protected $_observers;
  106.  
  107.     /**
  108.      * Object constructor to set table and key fields.  In most cases this will
  109.      * be overridden by child classes to explicitly set the table and key fields
  110.      * for a particular database table.
  111.      *
  112.      * @param   string           $table  Name of the table to model.
  113.      * @param   mixed            $key    Name of the primary key field in the table or array of field names that compose the primary key.
  114.      * @param   JDatabaseDriver  $db     JDatabaseDriver object.
  115.      *
  116.      * @since   11.1
  117.      */
  118.     public function __construct($table$keyJDatabaseDriver $db)
  119.     {
  120.         // Set internal variables.
  121.         $this->_tbl = $table;
  122.  
  123.         // Set the key to be an array.
  124.         if (is_string($key))
  125.         {
  126.             $key array($key);
  127.         }
  128.         elseif (is_object($key))
  129.         {
  130.             $key = (array) $key;
  131.         }
  132.  
  133.         $this->_tbl_keys = $key;
  134.  
  135.         if (count($key== 1)
  136.         {
  137.             $this->_autoincrement = true;
  138.         }
  139.         else
  140.         {
  141.             $this->_autoincrement = false;
  142.         }
  143.  
  144.         // Set the singular table key for backwards compatibility.
  145.         $this->_tbl_key = $this->getKeyName();
  146.  
  147.         $this->_db = $db;
  148.  
  149.         // Initialise the table properties.
  150.         $fields $this->getFields();
  151.  
  152.         if ($fields)
  153.         {
  154.             foreach ($fields as $name => $v)
  155.             {
  156.                 // Add the field if it is not already present.
  157.                 if (!property_exists($this$name))
  158.                 {
  159.                     $this->$name null;
  160.                 }
  161.             }
  162.         }
  163.  
  164.         // If we are tracking assets, make sure an access field exists and initially set the default.
  165.         if (property_exists($this'asset_id'))
  166.         {
  167.             $this->_trackAssets = true;
  168.         }
  169.  
  170.         // If the access property exists, set the default.
  171.         if (property_exists($this'access'))
  172.         {
  173.             $this->access = (int) JFactory::getConfig()->get('access');
  174.         }
  175.  
  176.         // Implement JObservableInterface:
  177.         // Create observer updater and attaches all observers interested by $this class:
  178.         $this->_observers = new JObserverUpdater($this);
  179.         JObserverMapper::attachAllObservers($this);
  180.     }
  181.  
  182.     /**
  183.      * Implement JObservableInterface:
  184.      * Adds an observer to this instance.
  185.      * This method will be called fron the constructor of classes implementing JObserverInterface
  186.      * which is instanciated by the constructor of $this with JObserverMapper::attachAllObservers($this)
  187.      *
  188.      * @param   JObserverInterface|JTableObserver $observer  The observer object
  189.      *
  190.      * @return  void 
  191.      *
  192.      * @since   3.1.2
  193.      */
  194.     public function attachObserver(JObserverInterface $observer)
  195.     {
  196.         $this->_observers->attachObserver($observer);
  197.     }
  198.  
  199.     /**
  200.      * Gets the instance of the observer of class $observerClass
  201.      *
  202.      * @param   string  $observerClass  The observer class-name to return the object of
  203.      *
  204.      * @return  JTableObserver|null
  205.      *
  206.      * @since   3.1.2
  207.      */
  208.     public function getObserverOfClass($observerClass)
  209.     {
  210.         return $this->_observers->getObserverOfClass($observerClass);
  211.     }
  212.  
  213.     /**
  214.      * Get the columns from database table.
  215.      *
  216.      * @return  mixed  An array of the field names, or false if an error occurs.
  217.      *
  218.      * @since   11.1
  219.      * @throws  UnexpectedValueException
  220.      */
  221.     public function getFields()
  222.     {
  223.         static $cache null;
  224.  
  225.         if ($cache === null)
  226.         {
  227.             // Lookup the fields for this table only once.
  228.             $name   $this->_tbl;
  229.             $fields $this->_db->getTableColumns($namefalse);
  230.  
  231.             if (empty($fields))
  232.             {
  233.                 throw new UnexpectedValueException(sprintf('No columns found for %s table'$name));
  234.             }
  235.  
  236.             $cache $fields;
  237.         }
  238.  
  239.         return $cache;
  240.     }
  241.  
  242.     /**
  243.      * Static method to get an instance of a JTable class if it can be found in
  244.      * the table include paths.  To add include paths for searching for JTable
  245.      * classes see JTable::addIncludePath().
  246.      *
  247.      * @param   string  $type    The type (name) of the JTable class to get an instance of.
  248.      * @param   string  $prefix  An optional prefix for the table class name.
  249.      * @param   array   $config  An optional array of configuration values for the JTable object.
  250.      *
  251.      * @return  mixed    A JTable object if found or boolean false if one could not be found.
  252.      *
  253.      * @link    http://docs.joomla.org/JTable/getInstance
  254.      * @since   11.1
  255.      */
  256.     public static function getInstance($type$prefix 'JTable'$config array())
  257.     {
  258.         // Sanitize and prepare the table class name.
  259.         $type       preg_replace('/[^A-Z0-9_\.-]/i'''$type);
  260.         $tableClass $prefix ucfirst($type);
  261.  
  262.         // Only try to load the class if it doesn't already exist.
  263.         if (!class_exists($tableClass))
  264.         {
  265.             // Search for the class file in the JTable include paths.
  266.             $path JPath::find(self::addIncludePath()strtolower($type'.php');
  267.  
  268.             if ($path)
  269.             {
  270.                 // Import the class file.
  271.                 include_once $path;
  272.  
  273.                 // If we were unable to load the proper class, raise a warning and return false.
  274.                 if (!class_exists($tableClass))
  275.                 {
  276.                     JLog::add(JText::sprintf('JLIB_DATABASE_ERROR_CLASS_NOT_FOUND_IN_FILE'$tableClass)JLog::WARNING'jerror');
  277.  
  278.                     return false;
  279.                 }
  280.             }
  281.             else
  282.             {
  283.                 // If we were unable to find the class file in the JTable include paths, raise a warning and return false.
  284.                 JLog::add(JText::sprintf('JLIB_DATABASE_ERROR_NOT_SUPPORTED_FILE_NOT_FOUND'$type)JLog::WARNING'jerror');
  285.  
  286.                 return false;
  287.             }
  288.         }
  289.  
  290.         // If a database object was passed in the configuration array use it, otherwise get the global one from JFactory.
  291.         $db = isset($config['dbo']$config['dbo'JFactory::getDbo();
  292.  
  293.         // Instantiate a new table class and return it.
  294.         return new $tableClass($db);
  295.     }
  296.  
  297.     /**
  298.      * Add a filesystem path where JTable should search for table class files.
  299.      * You may either pass a string or an array of paths.
  300.      *
  301.      * @param   mixed  $path  A filesystem path or array of filesystem paths to add.
  302.      *
  303.      * @return  array  An array of filesystem paths to find JTable classes in.
  304.      *
  305.      * @link    http://docs.joomla.org/JTable/addIncludePath
  306.      * @since   11.1
  307.      */
  308.     public static function addIncludePath($path null)
  309.     {
  310.         // If the internal paths have not been initialised, do so with the base table path.
  311.         if (empty(self::$_includePaths))
  312.         {
  313.             self::$_includePaths array(__DIR__);
  314.         }
  315.  
  316.         // Convert the passed path(s) to add to an array.
  317.         settype($path'array');
  318.  
  319.         // If we have new paths to add, do so.
  320.         if (!empty($path))
  321.         {
  322.             // Check and add each individual new path.
  323.             foreach ($path as $dir)
  324.             {
  325.                 // Sanitize path.
  326.                 $dir trim($dir);
  327.  
  328.                 // Add to the front of the list so that custom paths are searched first.
  329.                 if (!in_array($dirself::$_includePaths))
  330.                 {
  331.                     array_unshift(self::$_includePaths$dir);
  332.                 }
  333.             }
  334.         }
  335.  
  336.         return self::$_includePaths;
  337.     }
  338.  
  339.     /**
  340.      * Method to compute the default name of the asset.
  341.      * The default name is in the form table_name.id
  342.      * where id is the value of the primary key of the table.
  343.      *
  344.      * @return  string 
  345.      *
  346.      * @since   11.1
  347.      */
  348.     protected function _getAssetName()
  349.     {
  350.         $keys array();
  351.  
  352.         foreach ($this->_tbl_keys as $k)
  353.         {
  354.             $keys[= (int) $this->$k;
  355.         }
  356.  
  357.         return $this->_tbl '.' implode('.'$keys);
  358.     }
  359.  
  360.     /**
  361.      * Method to return the title to use for the asset table.  In
  362.      * tracking the assets a title is kept for each asset so that there is some
  363.      * context available in a unified access manager.  Usually this would just
  364.      * return $this->title or $this->name or whatever is being used for the
  365.      * primary name of the row. If this method is not overridden, the asset name is used.
  366.      *
  367.      * @return  string  The string to use as the title in the asset table.
  368.      *
  369.      * @link    http://docs.joomla.org/JTable/getAssetTitle
  370.      * @since   11.1
  371.      */
  372.     protected function _getAssetTitle()
  373.     {
  374.         return $this->_getAssetName();
  375.     }
  376.  
  377.     /**
  378.      * Method to get the parent asset under which to register this one.
  379.      * By default, all assets are registered to the ROOT node with ID,
  380.      * which will default to 1 if none exists.
  381.      * The extended class can define a table and id to lookup.  If the
  382.      * asset does not exist it will be created.
  383.      *
  384.      * @param   JTable   $table  A JTable object for the asset parent.
  385.      * @param   integer  $id     Id to look up
  386.      *
  387.      * @return  integer 
  388.      *
  389.      * @since   11.1
  390.      */
  391.     protected function _getAssetParentId(JTable $table null$id null)
  392.     {
  393.         // For simple cases, parent to the asset root.
  394.         $assets self::getInstance('Asset''JTable'array('dbo' => $this->getDbo()));
  395.         $rootId $assets->getRootId();
  396.  
  397.         if (!empty($rootId))
  398.         {
  399.             return $rootId;
  400.         }
  401.  
  402.         return 1;
  403.     }
  404.  
  405.     /**
  406.      * Method to append the primary keys for this table to a query.
  407.      *
  408.      * @param   JDatabaseQuery  $query  A query object to append.
  409.      * @param   mixed           $pk     Optional primary key parameter.
  410.      *
  411.      * @return  void 
  412.      *
  413.      * @since   12.3
  414.      */
  415.     public function appendPrimaryKeys($query$pk null)
  416.     {
  417.         if (is_null($pk))
  418.         {
  419.             foreach ($this->_tbl_keys as $k)
  420.             {
  421.                 $query->where($this->_db->quoteName($k' = ' $this->_db->quote($this->$k));
  422.             }
  423.         }
  424.         else
  425.         {
  426.             if (is_string($pk))
  427.             {
  428.                 $pk array($this->_tbl_key => $pk);
  429.             }
  430.  
  431.             $pk = (object) $pk;
  432.  
  433.             foreach ($this->_tbl_keys AS $k)
  434.             {
  435.                 $query->where($this->_db->quoteName($k' = ' $this->_db->quote($pk->$k));
  436.             }
  437.         }
  438.     }
  439.  
  440.     /**
  441.      * Method to get the database table name for the class.
  442.      *
  443.      * @return  string  The name of the database table being modeled.
  444.      *
  445.      * @since   11.1
  446.      *
  447.      * @link    http://docs.joomla.org/JTable/getTableName
  448.      */
  449.     public function getTableName()
  450.     {
  451.         return $this->_tbl;
  452.     }
  453.  
  454.     /**
  455.      * Method to get the primary key field name for the table.
  456.      *
  457.      * @param   boolean  $multiple  True to return all primary keys (as an array) or false to return just the first one (as a string).
  458.      *
  459.      * @return  mixed  Array of primary key field names or string containing the first primary key field.
  460.      *
  461.      * @link    http://docs.joomla.org/JTable/getKeyName
  462.      * @since   11.1
  463.      */
  464.     public function getKeyName($multiple false)
  465.     {
  466.         // Count the number of keys
  467.         if (count($this->_tbl_keys))
  468.         {
  469.             if ($multiple)
  470.             {
  471.                 // If we want multiple keys, return the raw array.
  472.                 return $this->_tbl_keys;
  473.             }
  474.             else
  475.             {
  476.                 // If we want the standard method, just return the first key.
  477.                 return $this->_tbl_keys[0];
  478.             }
  479.         }
  480.  
  481.         return '';
  482.     }
  483.  
  484.     /**
  485.      * Method to get the JDatabaseDriver object.
  486.      *
  487.      * @return  JDatabaseDriver  The internal database driver object.
  488.      *
  489.      * @link    http://docs.joomla.org/JTable/getDBO
  490.      * @since   11.1
  491.      */
  492.     public function getDbo()
  493.     {
  494.         return $this->_db;
  495.     }
  496.  
  497.     /**
  498.      * Method to set the JDatabaseDriver object.
  499.      *
  500.      * @param   JDatabaseDriver  $db  A JDatabaseDriver object to be used by the table object.
  501.      *
  502.      * @return  boolean  True on success.
  503.      *
  504.      * @link    http://docs.joomla.org/JTable/setDBO
  505.      * @since   11.1
  506.      */
  507.     public function setDBO(JDatabaseDriver $db)
  508.     {
  509.         $this->_db $db;
  510.  
  511.         return true;
  512.     }
  513.  
  514.     /**
  515.      * Method to set rules for the record.
  516.      *
  517.      * @param   mixed  $input  A JAccessRules object, JSON string, or array.
  518.      *
  519.      * @return  void 
  520.      *
  521.      * @since   11.1
  522.      */
  523.     public function setRules($input)
  524.     {
  525.         if ($input instanceof JAccessRules)
  526.         {
  527.             $this->_rules $input;
  528.         }
  529.         else
  530.         {
  531.             $this->_rules new JAccessRules($input);
  532.         }
  533.     }
  534.  
  535.     /**
  536.      * Method to get the rules for the record.
  537.      *
  538.      * @return  JAccessRules object
  539.      *
  540.      * @since   11.1
  541.      */
  542.     public function getRules()
  543.     {
  544.         return $this->_rules;
  545.     }
  546.  
  547.     /**
  548.      * Method to reset class properties to the defaults set in the class
  549.      * definition. It will ignore the primary key as well as any private class
  550.      * properties (except $_errors).
  551.      *
  552.      * @return  void 
  553.      *
  554.      * @link    http://docs.joomla.org/JTable/reset
  555.      * @since   11.1
  556.      */
  557.     public function reset()
  558.     {
  559.         // Get the default values for the class from the table.
  560.         foreach ($this->getFields(as $k => $v)
  561.         {
  562.             // If the property is not the primary key or private, reset it.
  563.             if (!in_array($k$this->_tbl_keys&& (strpos($k'_'!== 0))
  564.             {
  565.                 $this->$k $v->Default;
  566.             }
  567.         }
  568.  
  569.         // Reset table errors
  570.         $this->_errors array();
  571.     }
  572.  
  573.     /**
  574.      * Method to bind an associative array or object to the JTable instance.This
  575.      * method only binds properties that are publicly accessible and optionally
  576.      * takes an array of properties to ignore when binding.
  577.      *
  578.      * @param   mixed  $src     An associative array or object to bind to the JTable instance.
  579.      * @param   mixed  $ignore  An optional array or space separated list of properties to ignore while binding.
  580.      *
  581.      * @return  boolean  True on success.
  582.      *
  583.      * @link    http://docs.joomla.org/JTable/bind
  584.      * @since   11.1
  585.      * @throws  InvalidArgumentException
  586.      */
  587.     public function bind($src$ignore array())
  588.     {
  589.         // If the source value is not an array or object return false.
  590.         if (!is_object($src&& !is_array($src))
  591.         {
  592.             throw new InvalidArgumentException(sprintf('%s::bind(*%s*)'get_class($this)gettype($src)));
  593.         }
  594.  
  595.         // If the source value is an object, get its accessible properties.
  596.         if (is_object($src))
  597.         {
  598.             $src get_object_vars($src);
  599.         }
  600.  
  601.         // If the ignore value is a string, explode it over spaces.
  602.         if (!is_array($ignore))
  603.         {
  604.             $ignore explode(' '$ignore);
  605.         }
  606.  
  607.         // Bind the source value, excluding the ignored fields.
  608.         foreach ($this->getProperties(as $k => $v)
  609.         {
  610.             // Only process fields not in the ignore array.
  611.             if (!in_array($k$ignore))
  612.             {
  613.                 if (isset($src[$k]))
  614.                 {
  615.                     $this->$k $src[$k];
  616.                 }
  617.             }
  618.         }
  619.  
  620.         return true;
  621.     }
  622.  
  623.     /**
  624.      * Method to load a row from the database by primary key and bind the fields
  625.      * to the JTable instance properties.
  626.      *
  627.      * @param   mixed    $keys   An optional primary key value to load the row by, or an array of fields to match.  If not
  628.      *                            set the instance property value is used.
  629.      * @param   boolean  $reset  True to reset the default values before loading the new row.
  630.      *
  631.      * @return  boolean  True if successful. False if row not found.
  632.      *
  633.      * @link    http://docs.joomla.org/JTable/load
  634.      * @since   11.1
  635.      * @throws  InvalidArgumentException
  636.      * @throws  RuntimeException
  637.      * @throws  UnexpectedValueException
  638.      */
  639.     public function load($keys null$reset true)
  640.     {
  641.         // Implement JObservableInterface: Pre-processing by observers
  642.         $this->_observers->update('onBeforeLoad'array($keys$reset));
  643.  
  644.         if (empty($keys))
  645.         {
  646.             $empty true;
  647.             $keys  array();
  648.  
  649.             // If empty, use the value of the current key
  650.             foreach ($this->_tbl_keys as $key)
  651.             {
  652.                 $empty      $empty && empty($this->$key);
  653.                 $keys[$key$this->$key;
  654.             }
  655.  
  656.             // If empty primary key there's is no need to load anything
  657.             if ($empty)
  658.             {
  659.                 return true;
  660.             }
  661.         }
  662.         elseif (!is_array($keys))
  663.         {
  664.             // Load by primary key.
  665.             $keyCount count($this->_tbl_keys);
  666.  
  667.             if ($keyCount)
  668.             {
  669.                 if ($keyCount 1)
  670.                 {
  671.                     throw new InvalidArgumentException('Table has multiple primary keys specified, only one primary key value provided.');
  672.                 }
  673.                 $keys array($this->getKeyName(=> $keys);
  674.             }
  675.             else
  676.             {
  677.                 throw new RuntimeException('No table keys defined.');
  678.             }
  679.         }
  680.  
  681.         if ($reset)
  682.         {
  683.             $this->reset();
  684.         }
  685.  
  686.         // Initialise the query.
  687.         $query $this->_db->getQuery(true)
  688.             ->select('*')
  689.             ->from($this->_tbl);
  690.         $fields array_keys($this->getProperties());
  691.  
  692.         foreach ($keys as $field => $value)
  693.         {
  694.             // Check that $field is in the table.
  695.             if (!in_array($field$fields))
  696.             {
  697.                 throw new UnexpectedValueException(sprintf('Missing field in database: %s &#160; %s.'get_class($this)$field));
  698.             }
  699.             // Add the search tuple to the query.
  700.             $query->where($this->_db->quoteName($field' = ' $this->_db->quote($value));
  701.         }
  702.  
  703.         $this->_db->setQuery($query);
  704.  
  705.         $row $this->_db->loadAssoc();
  706.  
  707.         // Check that we have a result.
  708.         if (empty($row))
  709.         {
  710.             $result false;
  711.         }
  712.         else
  713.         {
  714.             // Bind the object with the row and return.
  715.             $result $this->bind($row);
  716.         }
  717.  
  718.         // Implement JObservableInterface: Post-processing by observers
  719.         $this->_observers->update('onAfterLoad'array(&$result$row));
  720.  
  721.         return $result;
  722.     }
  723.  
  724.     /**
  725.      * Method to perform sanity checks on the JTable instance properties to ensure
  726.      * they are safe to store in the database.  Child classes should override this
  727.      * method to make sure the data they are storing in the database is safe and
  728.      * as expected before storage.
  729.      *
  730.      * @return  boolean  True if the instance is sane and able to be stored in the database.
  731.      *
  732.      * @link    http://docs.joomla.org/JTable/check
  733.      * @since   11.1
  734.      */
  735.     public function check()
  736.     {
  737.         return true;
  738.     }
  739.  
  740.     /**
  741.      * Method to store a row in the database from the JTable instance properties.
  742.      * If a primary key value is set the row with that primary key value will be
  743.      * updated with the instance property values.  If no primary key value is set
  744.      * a new row will be inserted into the database with the properties from the
  745.      * JTable instance.
  746.      *
  747.      * @param   boolean  $updateNulls  True to update fields even if they are null.
  748.      *
  749.      * @return  boolean  True on success.
  750.      *
  751.      * @link    http://docs.joomla.org/JTable/store
  752.      * @since   11.1
  753.      */
  754.     public function store($updateNulls false)
  755.     {
  756.         $k $this->_tbl_keys;
  757.  
  758.         // Implement JObservableInterface: Pre-processing by observers
  759.         $this->_observers->update('onBeforeStore'array($updateNulls$k));
  760.  
  761.         $currentAssetId 0;
  762.  
  763.         if (!empty($this->asset_id))
  764.         {
  765.             $currentAssetId $this->asset_id;
  766.         }
  767.  
  768.         // The asset id field is managed privately by this class.
  769.         if ($this->_trackAssets)
  770.         {
  771.             unset($this->asset_id);
  772.         }
  773.  
  774.         // If a primary key exists update the object, otherwise insert it.
  775.         if ($this->hasPrimaryKey())
  776.         {
  777.             $result $this->_db->updateObject($this->_tbl$this$this->_tbl_keys$updateNulls);
  778.         }
  779.         else
  780.         {
  781.             $result $this->_db->insertObject($this->_tbl$this$this->_tbl_keys[0]);
  782.         }
  783.  
  784.         // If the table is not set to track assets return true.
  785.         if ($this->_trackAssets)
  786.         {
  787.             if ($this->_locked)
  788.             {
  789.                 $this->_unlock();
  790.             }
  791.  
  792.             /*
  793.              * Asset Tracking
  794.              */
  795.             $parentId $this->_getAssetParentId();
  796.             $name     $this->_getAssetName();
  797.             $title    $this->_getAssetTitle();
  798.  
  799.             $asset self::getInstance('Asset''JTable'array('dbo' => $this->getDbo()));
  800.             $asset->loadByName($name);
  801.  
  802.             // Re-inject the asset id.
  803.             $this->asset_id $asset->id;
  804.  
  805.             // Check for an error.
  806.             $error $asset->getError();
  807.  
  808.             if ($error)
  809.             {
  810.                 $this->setError($error);
  811.  
  812.                 return false;
  813.             }
  814.             else
  815.             {
  816.                 // Specify how a new or moved node asset is inserted into the tree.
  817.                 if (empty($this->asset_id|| $asset->parent_id != $parentId)
  818.                 {
  819.                     $asset->setLocation($parentId'last-child');
  820.                 }
  821.  
  822.                 // Prepare the asset to be stored.
  823.                 $asset->parent_id $parentId;
  824.                 $asset->name      $name;
  825.                 $asset->title     $title;
  826.  
  827.                 if ($this->_rules instanceof JAccessRules)
  828.                 {
  829.                     $asset->rules = (string) $this->_rules;
  830.                 }
  831.  
  832.                 if (!$asset->check(|| !$asset->store($updateNulls))
  833.                 {
  834.                     $this->setError($asset->getError());
  835.  
  836.                     return false;
  837.                 }
  838.                 else
  839.                 {
  840.                     // Create an asset_id or heal one that is corrupted.
  841.                     if (empty($this->asset_id|| ($currentAssetId != $this->asset_id && !empty($this->asset_id)))
  842.                     {
  843.                         // Update the asset_id field in this table.
  844.                         $this->asset_id = (int) $asset->id;
  845.  
  846.                         $query $this->_db->getQuery(true)
  847.                             ->update($this->_db->quoteName($this->_tbl))
  848.                             ->set('asset_id = ' . (int) $this->asset_id);
  849.                         $this->appendPrimaryKeys($query);
  850.                         $this->_db->setQuery($query)->execute();
  851.                     }
  852.                 }
  853.             }
  854.         }
  855.  
  856.         // Implement JObservableInterface: Post-processing by observers
  857.         $this->_observers->update('onAfterStore'array(&$result));
  858.  
  859.         return $result;
  860.     }
  861.  
  862.     /**
  863.      * Method to provide a shortcut to binding, checking and storing a JTable
  864.      * instance to the database table.  The method will check a row in once the
  865.      * data has been stored and if an ordering filter is present will attempt to
  866.      * reorder the table rows based on the filter.  The ordering filter is an instance
  867.      * property name.  The rows that will be reordered are those whose value matches
  868.      * the JTable instance for the property specified.
  869.      *
  870.      * @param   mixed   $src             An associative array or object to bind to the JTable instance.
  871.      * @param   string  $orderingFilter  Filter for the order updating
  872.      * @param   mixed   $ignore          An optional array or space separated list of properties
  873.      *                                    to ignore while binding.
  874.      *
  875.      * @return  boolean  True on success.
  876.      *
  877.      * @link    http://docs.joomla.org/JTable/save
  878.      * @since   11.1
  879.      */
  880.     public function save($src$orderingFilter ''$ignore '')
  881.     {
  882.         // Attempt to bind the source to the instance.
  883.         if (!$this->bind($src$ignore))
  884.         {
  885.             return false;
  886.         }
  887.  
  888.         // Run any sanity checks on the instance and verify that it is ready for storage.
  889.         if (!$this->check())
  890.         {
  891.             return false;
  892.         }
  893.  
  894.         // Attempt to store the properties to the database table.
  895.         if (!$this->store())
  896.         {
  897.             return false;
  898.         }
  899.  
  900.         // Attempt to check the row in, just in case it was checked out.
  901.         if (!$this->checkin())
  902.         {
  903.             return false;
  904.         }
  905.  
  906.         // If an ordering filter is set, attempt reorder the rows in the table based on the filter and value.
  907.         if ($orderingFilter)
  908.         {
  909.             $filterValue $this->$orderingFilter;
  910.             $this->reorder($orderingFilter $this->_db->quoteName($orderingFilter' = ' $this->_db->quote($filterValue'');
  911.         }
  912.  
  913.         // Set the error to empty and return true.
  914.         $this->setError('');
  915.  
  916.         return true;
  917.     }
  918.  
  919.     /**
  920.      * Method to delete a row from the database table by primary key value.
  921.      *
  922.      * @param   mixed  $pk  An optional primary key value to delete.  If not set the instance property value is used.
  923.      *
  924.      * @return  boolean  True on success.
  925.      *
  926.      * @link    http://docs.joomla.org/JTable/delete
  927.      * @since   11.1
  928.      * @throws  UnexpectedValueException
  929.      */
  930.     public function delete($pk null)
  931.     {
  932.         if (is_null($pk))
  933.         {
  934.             $pk array();
  935.  
  936.             foreach ($this->_tbl_keys AS $key)
  937.             {
  938.                 $pk[$key$this->$key;
  939.             }
  940.         }
  941.         elseif (!is_array($pk))
  942.         {
  943.             $pk array($this->_tbl_key => $pk);
  944.         }
  945.  
  946.         foreach ($this->_tbl_keys AS $key)
  947.         {
  948.             $pk[$keyis_null($pk[$key]$this->$key $pk[$key];
  949.  
  950.             if ($pk[$key=== null)
  951.             {
  952.                 throw new UnexpectedValueException('Null primary key not allowed.');
  953.             }
  954.             $this->$key $pk[$key];
  955.         }
  956.  
  957.         // Implement JObservableInterface: Pre-processing by observers
  958.         $this->_observers->update('onBeforeDelete'array($pk));
  959.  
  960.         // If tracking assets, remove the asset first.
  961.         if ($this->_trackAssets)
  962.         {
  963.             // Get the asset name
  964.             $name  $this->_getAssetName();
  965.             $asset self::getInstance('Asset');
  966.  
  967.             if ($asset->loadByName($name))
  968.             {
  969.                 if (!$asset->delete())
  970.                 {
  971.                     $this->setError($asset->getError());
  972.  
  973.                     return false;
  974.                 }
  975.             }
  976.             else
  977.             {
  978.                 $this->setError($asset->getError());
  979.  
  980.                 return false;
  981.             }
  982.         }
  983.  
  984.         // Delete the row by primary key.
  985.         $query $this->_db->getQuery(true)
  986.             ->delete($this->_tbl);
  987.         $this->appendPrimaryKeys($query$pk);
  988.  
  989.         $this->_db->setQuery($query);
  990.  
  991.         // Check for a database error.
  992.         $this->_db->execute();
  993.  
  994.         // Implement JObservableInterface: Post-processing by observers
  995.         $this->_observers->update('onAfterDelete'array($pk));
  996.  
  997.         return true;
  998.     }
  999.  
  1000.     /**
  1001.      * Method to check a row out if the necessary properties/fields exist.  To
  1002.      * prevent race conditions while editing rows in a database, a row can be
  1003.      * checked out if the fields 'checked_out' and 'checked_out_time' are available.
  1004.      * While a row is checked out, any attempt to store the row by a user other
  1005.      * than the one who checked the row out should be held until the row is checked
  1006.      * in again.
  1007.      *
  1008.      * @param   integer  $userId  The Id of the user checking out the row.
  1009.      * @param   mixed    $pk      An optional primary key value to check out.  If not set
  1010.      *                             the instance property value is used.
  1011.      *
  1012.      * @return  boolean  True on success.
  1013.      *
  1014.      * @link    http://docs.joomla.org/JTable/checkOut
  1015.      * @since   11.1
  1016.      * @throws  UnexpectedValueException
  1017.      */
  1018.     public function checkOut($userId$pk null)
  1019.     {
  1020.         // If there is no checked_out or checked_out_time field, just return true.
  1021.         if (!property_exists($this'checked_out'|| !property_exists($this'checked_out_time'))
  1022.         {
  1023.             return true;
  1024.         }
  1025.  
  1026.         if (is_null($pk))
  1027.         {
  1028.             $pk array();
  1029.  
  1030.             foreach ($this->_tbl_keys AS $key)
  1031.             {
  1032.                 $pk[$key$this->$key;
  1033.             }
  1034.         }
  1035.         elseif (!is_array($pk))
  1036.         {
  1037.             $pk array($this->_tbl_key => $pk);
  1038.         }
  1039.  
  1040.         foreach ($this->_tbl_keys AS $key)
  1041.         {
  1042.             $pk[$keyis_null($pk[$key]$this->$key $pk[$key];
  1043.  
  1044.             if ($pk[$key=== null)
  1045.             {
  1046.                 throw new UnexpectedValueException('Null primary key not allowed.');
  1047.             }
  1048.         }
  1049.  
  1050.         // Get the current time in the database format.
  1051.         $time JFactory::getDate()->toSql();
  1052.  
  1053.         // Check the row out by primary key.
  1054.         $query $this->_db->getQuery(true)
  1055.             ->update($this->_tbl)
  1056.             ->set($this->_db->quoteName('checked_out'' = ' . (int) $userId)
  1057.             ->set($this->_db->quoteName('checked_out_time'' = ' $this->_db->quote($time));
  1058.         $this->appendPrimaryKeys($query$pk);
  1059.         $this->_db->setQuery($query);
  1060.         $this->_db->execute();
  1061.  
  1062.         // Set table values in the object.
  1063.         $this->checked_out      = (int) $userId;
  1064.         $this->checked_out_time $time;
  1065.  
  1066.         return true;
  1067.     }
  1068.  
  1069.     /**
  1070.      * Method to check a row in if the necessary properties/fields exist.  Checking
  1071.      * a row in will allow other users the ability to edit the row.
  1072.      *
  1073.      * @param   mixed  $pk  An optional primary key value to check out.  If not set the instance property value is used.
  1074.      *
  1075.      * @return  boolean  True on success.
  1076.      *
  1077.      * @link    http://docs.joomla.org/JTable/checkIn
  1078.      * @since   11.1
  1079.      * @throws  UnexpectedValueException
  1080.      */
  1081.     public function checkIn($pk null)
  1082.     {
  1083.         // If there is no checked_out or checked_out_time field, just return true.
  1084.         if (!property_exists($this'checked_out'|| !property_exists($this'checked_out_time'))
  1085.         {
  1086.             return true;
  1087.         }
  1088.  
  1089.         if (is_null($pk))
  1090.         {
  1091.             $pk array();
  1092.  
  1093.             foreach ($this->_tbl_keys AS $key)
  1094.             {
  1095.                 $pk[$this->$key$this->$key;
  1096.             }
  1097.         }
  1098.         elseif (!is_array($pk))
  1099.         {
  1100.             $pk array($this->_tbl_key => $pk);
  1101.         }
  1102.  
  1103.         foreach ($this->_tbl_keys AS $key)
  1104.         {
  1105.             $pk[$keyempty($pk[$key]$this->$key $pk[$key];
  1106.  
  1107.             if ($pk[$key=== null)
  1108.             {
  1109.                 throw new UnexpectedValueException('Null primary key not allowed.');
  1110.             }
  1111.         }
  1112.  
  1113.         // Check the row in by primary key.
  1114.         $query $this->_db->getQuery(true)
  1115.             ->update($this->_tbl)
  1116.             ->set($this->_db->quoteName('checked_out'' = 0')
  1117.             ->set($this->_db->quoteName('checked_out_time'' = ' $this->_db->quote($this->_db->getNullDate()));
  1118.         $this->appendPrimaryKeys($query$pk);
  1119.         $this->_db->setQuery($query);
  1120.  
  1121.         // Check for a database error.
  1122.         $this->_db->execute();
  1123.  
  1124.         // Set table values in the object.
  1125.         $this->checked_out      0;
  1126.         $this->checked_out_time '';
  1127.  
  1128.         return true;
  1129.     }
  1130.  
  1131.     /**
  1132.      * Validate that the primary key has been set.
  1133.      *
  1134.      * @return  boolean  True if the primary key(s) have been set.
  1135.      *
  1136.      * @since   12.3
  1137.      */
  1138.     public function hasPrimaryKey()
  1139.     {
  1140.         if ($this->_autoincrement)
  1141.         {
  1142.             $empty true;
  1143.  
  1144.             foreach ($this->_tbl_keys as $key)
  1145.             {
  1146.                 $empty $empty && empty($this->$key);
  1147.             }
  1148.         }
  1149.         else
  1150.         {
  1151.             $query $this->_db->getQuery(true)
  1152.                 ->select('COUNT(*)')
  1153.                 ->from($this->_tbl);
  1154.             $this->appendPrimaryKeys($query);
  1155.  
  1156.             $this->_db->setQuery($query);
  1157.             $count $this->_db->loadResult();
  1158.  
  1159.             if ($count == 1)
  1160.             {
  1161.                 $empty false;
  1162.             }
  1163.             else
  1164.             {
  1165.                 $empty true;
  1166.             }
  1167.         }
  1168.  
  1169.         return !$empty;
  1170.     }
  1171.  
  1172.     /**
  1173.      * Method to increment the hits for a row if the necessary property/field exists.
  1174.      *
  1175.      * @param   mixed  $pk  An optional primary key value to increment. If not set the instance property value is used.
  1176.      *
  1177.      * @return  boolean  True on success.
  1178.      *
  1179.      * @link    http://docs.joomla.org/JTable/hit
  1180.      * @since   11.1
  1181.      * @throws  UnexpectedValueException
  1182.      */
  1183.     public function hit($pk null)
  1184.     {
  1185.         // If there is no hits field, just return true.
  1186.         if (!property_exists($this'hits'))
  1187.         {
  1188.             return true;
  1189.         }
  1190.  
  1191.         if (is_null($pk))
  1192.         {
  1193.             $pk array();
  1194.  
  1195.             foreach ($this->_tbl_keys AS $key)
  1196.             {
  1197.                 $pk[$key$this->$key;
  1198.             }
  1199.         }
  1200.         elseif (!is_array($pk))
  1201.         {
  1202.             $pk array($this->_tbl_key => $pk);
  1203.         }
  1204.  
  1205.         foreach ($this->_tbl_keys AS $key)
  1206.         {
  1207.             $pk[$keyis_null($pk[$key]$this->$key $pk[$key];
  1208.  
  1209.             if ($pk[$key=== null)
  1210.             {
  1211.                 throw new UnexpectedValueException('Null primary key not allowed.');
  1212.             }
  1213.         }
  1214.  
  1215.         // Check the row in by primary key.
  1216.         $query $this->_db->getQuery(true)
  1217.             ->update($this->_tbl)
  1218.             ->set($this->_db->quoteName('hits'' = (' $this->_db->quoteName('hits'' + 1)');
  1219.         $this->appendPrimaryKeys($query$pk);
  1220.         $this->_db->setQuery($query);
  1221.         $this->_db->execute();
  1222.  
  1223.         // Set table values in the object.
  1224.         $this->hits++;
  1225.  
  1226.         return true;
  1227.     }
  1228.  
  1229.     /**
  1230.      * Method to determine if a row is checked out and therefore uneditable by
  1231.      * a user. If the row is checked out by the same user, then it is considered
  1232.      * not checked out -- as the user can still edit it.
  1233.      *
  1234.      * @param   integer  $with     The userid to preform the match with, if an item is checked
  1235.      *                              out by this user the function will return false.
  1236.      * @param   integer  $against  The userid to perform the match against when the function
  1237.      *                              is used as a static function.
  1238.      *
  1239.      * @return  boolean  True if checked out.
  1240.      *
  1241.      * @link    http://docs.joomla.org/JTable/isCheckedOut
  1242.      * @since   11.1
  1243.      */
  1244.     public function isCheckedOut($with 0$against null)
  1245.     {
  1246.         // Handle the non-static case.
  1247.         if (isset($this&& ($this instanceof JTable&& is_null($against))
  1248.         {
  1249.             $against $this->get('checked_out');
  1250.         }
  1251.  
  1252.         // The item is not checked out or is checked out by the same user.
  1253.         if (!$against || ($against == $with))
  1254.         {
  1255.             return false;
  1256.         }
  1257.  
  1258.         $db JFactory::getDbo();
  1259.         $db->setQuery('SELECT COUNT(userid) FROM ' $db->quoteName('#__session'' WHERE ' $db->quoteName('userid'' = ' . (int) $against);
  1260.         $checkedOut = (boolean) $db->loadResult();
  1261.  
  1262.         // If a session exists for the user then it is checked out.
  1263.         return $checkedOut;
  1264.     }
  1265.  
  1266.     /**
  1267.      * Method to get the next ordering value for a group of rows defined by an SQL WHERE clause.
  1268.      * This is useful for placing a new item last in a group of items in the table.
  1269.      *
  1270.      * @param   string  $where  WHERE clause to use for selecting the MAX(ordering) for the table.
  1271.      *
  1272.      * @return  mixed  Boolean false an failure or the next ordering value as an integer.
  1273.      *
  1274.      * @link    http://docs.joomla.org/JTable/getNextOrder
  1275.      * @since   11.1
  1276.      * @throws  UnexpectedValueException
  1277.      */
  1278.     public function getNextOrder($where '')
  1279.     {
  1280.         // If there is no ordering field set an error and return false.
  1281.         if (!property_exists($this'ordering'))
  1282.         {
  1283.             throw new UnexpectedValueException(sprintf('%s does not support ordering.'get_class($this)));
  1284.         }
  1285.  
  1286.         // Get the largest ordering value for a given where clause.
  1287.         $query $this->_db->getQuery(true)
  1288.             ->select('MAX(ordering)')
  1289.             ->from($this->_tbl);
  1290.  
  1291.         if ($where)
  1292.         {
  1293.             $query->where($where);
  1294.         }
  1295.  
  1296.         $this->_db->setQuery($query);
  1297.         $max = (int) $this->_db->loadResult();
  1298.  
  1299.         // Return the largest ordering value + 1.
  1300.         return ($max 1);
  1301.     }
  1302.  
  1303.     /**
  1304.      * Get the primary key values for this table using passed in values as a default.
  1305.      *
  1306.      * @param   array  $keys  Optional primary key values to use.
  1307.      *
  1308.      * @return  array  An array of primary key names and values.
  1309.      *
  1310.      * @since   12.3
  1311.      */
  1312.     public function getPrimaryKey(array $keys array())
  1313.     {
  1314.         foreach ($this->_tbl_keys as $key)
  1315.         {
  1316.             if (!isset($keys[$key]))
  1317.             {
  1318.                 if (!empty($this->$key))
  1319.                 {
  1320.                     $keys[$key$this->$key;
  1321.                 }
  1322.             }
  1323.         }
  1324.  
  1325.         return $keys;
  1326.     }
  1327.  
  1328.     /**
  1329.      * Method to compact the ordering values of rows in a group of rows
  1330.      * defined by an SQL WHERE clause.
  1331.      *
  1332.      * @param   string  $where  WHERE clause to use for limiting the selection of rows to compact the ordering values.
  1333.      *
  1334.      * @return  mixed  Boolean  True on success.
  1335.      *
  1336.      * @link    http://docs.joomla.org/JTable/reorder
  1337.      * @since   11.1
  1338.      * @throws  UnexpectedValueException
  1339.      */
  1340.     public function reorder($where '')
  1341.     {
  1342.         // If there is no ordering field set an error and return false.
  1343.         if (!property_exists($this'ordering'))
  1344.         {
  1345.             throw new UnexpectedValueException(sprintf('%s does not support ordering.'get_class($this)));
  1346.         }
  1347.  
  1348.         $k $this->_tbl_key;
  1349.  
  1350.         // Get the primary keys and ordering values for the selection.
  1351.         $query $this->_db->getQuery(true)
  1352.             ->select(implode(','$this->_tbl_keys', ordering')
  1353.             ->from($this->_tbl)
  1354.             ->where('ordering >= 0')
  1355.             ->order('ordering');
  1356.  
  1357.         // Setup the extra where and ordering clause data.
  1358.         if ($where)
  1359.         {
  1360.             $query->where($where);
  1361.         }
  1362.  
  1363.         $this->_db->setQuery($query);
  1364.         $rows $this->_db->loadObjectList();
  1365.  
  1366.         // Compact the ordering values.
  1367.         foreach ($rows as $i => $row)
  1368.         {
  1369.             // Make sure the ordering is a positive integer.
  1370.             if ($row->ordering >= 0)
  1371.             {
  1372.                 // Only update rows that are necessary.
  1373.                 if ($row->ordering != $i 1)
  1374.                 {
  1375.                     // Update the row ordering field.
  1376.                     $query->clear()
  1377.                         ->update($this->_tbl)
  1378.                         ->set('ordering = ' ($i 1));
  1379.                     $this->appendPrimaryKeys($query$row);
  1380.                     $this->_db->setQuery($query);
  1381.                     $this->_db->execute();
  1382.                 }
  1383.             }
  1384.         }
  1385.  
  1386.         return true;
  1387.     }
  1388.  
  1389.     /**
  1390.      * Method to move a row in the ordering sequence of a group of rows defined by an SQL WHERE clause.
  1391.      * Negative numbers move the row up in the sequence and positive numbers move it down.
  1392.      *
  1393.      * @param   integer  $delta  The direction and magnitude to move the row in the ordering sequence.
  1394.      * @param   string   $where  WHERE clause to use for limiting the selection of rows to compact the
  1395.      *                            ordering values.
  1396.      *
  1397.      * @return  mixed    Boolean  True on success.
  1398.      *
  1399.      * @link    http://docs.joomla.org/JTable/move
  1400.      * @since   11.1
  1401.      * @throws  UnexpectedValueException
  1402.      */
  1403.     public function move($delta$where '')
  1404.     {
  1405.         // If there is no ordering field set an error and return false.
  1406.         if (!property_exists($this'ordering'))
  1407.         {
  1408.             throw new UnexpectedValueException(sprintf('%s does not support ordering.'get_class($this)));
  1409.         }
  1410.  
  1411.         // If the change is none, do nothing.
  1412.         if (empty($delta))
  1413.         {
  1414.             return true;
  1415.         }
  1416.  
  1417.         $k     $this->_tbl_key;
  1418.         $row   null;
  1419.         $query $this->_db->getQuery(true);
  1420.  
  1421.         // Select the primary key and ordering values from the table.
  1422.         $query->select(implode(','$this->_tbl_keys', ordering')
  1423.             ->from($this->_tbl);
  1424.  
  1425.         // If the movement delta is negative move the row up.
  1426.         if ($delta 0)
  1427.         {
  1428.             $query->where('ordering < ' . (int) $this->ordering)
  1429.                 ->order('ordering DESC');
  1430.         }
  1431.         // If the movement delta is positive move the row down.
  1432.         elseif ($delta 0)
  1433.         {
  1434.             $query->where('ordering > ' . (int) $this->ordering)
  1435.                 ->order('ordering ASC');
  1436.         }
  1437.  
  1438.         // Add the custom WHERE clause if set.
  1439.         if ($where)
  1440.         {
  1441.             $query->where($where);
  1442.         }
  1443.  
  1444.         // Select the first row with the criteria.
  1445.         $this->_db->setQuery($query01);
  1446.         $row $this->_db->loadObject();
  1447.  
  1448.         // If a row is found, move the item.
  1449.         if (!empty($row))
  1450.         {
  1451.             // Update the ordering field for this instance to the row's ordering value.
  1452.             $query->clear()
  1453.                 ->update($this->_tbl)
  1454.                 ->set('ordering = ' . (int) $row->ordering);
  1455.             $this->appendPrimaryKeys($query);
  1456.             $this->_db->setQuery($query);
  1457.             $this->_db->execute();
  1458.  
  1459.             // Update the ordering field for the row to this instance's ordering value.
  1460.             $query->clear()
  1461.                 ->update($this->_tbl)
  1462.                 ->set('ordering = ' . (int) $this->ordering);
  1463.             $this->appendPrimaryKeys($query$row);
  1464.             $this->_db->setQuery($query);
  1465.             $this->_db->execute();
  1466.  
  1467.             // Update the instance value.
  1468.             $this->ordering = $row->ordering;
  1469.         }
  1470.         else
  1471.         {
  1472.             // Update the ordering field for this instance.
  1473.             $query->clear()
  1474.                 ->update($this->_tbl)
  1475.                 ->set('ordering = ' . (int) $this->ordering);
  1476.             $this->appendPrimaryKeys($query);
  1477.             $this->_db->setQuery($query);
  1478.             $this->_db->execute();
  1479.         }
  1480.  
  1481.         return true;
  1482.     }
  1483.  
  1484.     /**
  1485.      * Method to set the publishing state for a row or list of rows in the database
  1486.      * table.  The method respects checked out rows by other users and will attempt
  1487.      * to checkin rows that it can after adjustments are made.
  1488.      *
  1489.      * @param   mixed    $pks     An optional array of primary key values to update.
  1490.      *                             If not set the instance property value is used.
  1491.      * @param   integer  $state   The publishing state. eg. [0 = unpublished, 1 = published]
  1492.      * @param   integer  $userId  The user id of the user performing the operation.
  1493.      *
  1494.      * @return  boolean  True on success; false if $pks is empty.
  1495.      *
  1496.      * @link    http://docs.joomla.org/JTable/publish
  1497.      * @since   11.1
  1498.      */
  1499.     public function publish($pks null$state 1$userId 0)
  1500.     {
  1501.         $k $this->_tbl_keys;
  1502.  
  1503.         if (!is_null($pks))
  1504.         {
  1505.             foreach ($pks AS $key => $pk)
  1506.             {
  1507.                 if (!is_array($pk))
  1508.                 {
  1509.                     $pks[$keyarray($this->_tbl_key => $pk);
  1510.                 }
  1511.             }
  1512.         }
  1513.  
  1514.         $userId = (int) $userId;
  1515.         $state  = (int) $state;
  1516.  
  1517.         // If there are no primary keys set check to see if the instance key is set.
  1518.         if (empty($pks))
  1519.         {
  1520.             $pk array();
  1521.  
  1522.             foreach ($this->_tbl_keys AS $key)
  1523.             {
  1524.                 if ($this->$key)
  1525.                 {
  1526.                     $pk[$this->$key$this->$key;
  1527.                 }
  1528.                 // We don't have a full primary key - return false
  1529.                 else
  1530.                 {
  1531.                     return false;
  1532.                 }
  1533.             }
  1534.  
  1535.             $pks array($pk);
  1536.         }
  1537.  
  1538.         foreach ($pks AS $pk)
  1539.         {
  1540.             // Update the publishing state for rows with the given primary keys.
  1541.             $query $this->_db->getQuery(true)
  1542.                 ->update($this->_tbl)
  1543.                 ->set('published = ' . (int) $state);
  1544.  
  1545.             // Determine if there is checkin support for the table.
  1546.             if (property_exists($this'checked_out'|| property_exists($this'checked_out_time'))
  1547.             {
  1548.                 $query->where('(checked_out = 0 OR checked_out = ' . (int) $userId ')');
  1549.                 $checkin true;
  1550.             }
  1551.             else
  1552.             {
  1553.                 $checkin false;
  1554.             }
  1555.  
  1556.             // Build the WHERE clause for the primary keys.
  1557.             $this->appendPrimaryKeys($query$pk);
  1558.  
  1559.             $this->_db->setQuery($query);
  1560.             $this->_db->execute();
  1561.  
  1562.             // If checkin is supported and all rows were adjusted, check them in.
  1563.             if ($checkin && (count($pks== $this->_db->getAffectedRows()))
  1564.             {
  1565.                 $this->checkin($pk);
  1566.             }
  1567.  
  1568.             $ours true;
  1569.  
  1570.             foreach ($this->_tbl_keys AS $key)
  1571.             {
  1572.                 if ($this->$key != $pk[$key])
  1573.                 {
  1574.                     $ours false;
  1575.                 }
  1576.             }
  1577.  
  1578.             if ($ours)
  1579.             {
  1580.                 $this->published $state;
  1581.             }
  1582.         }
  1583.  
  1584.         $this->setError('');
  1585.  
  1586.         return true;
  1587.     }
  1588.  
  1589.     /**
  1590.      * Method to lock the database table for writing.
  1591.      *
  1592.      * @return  boolean  True on success.
  1593.      *
  1594.      * @since   11.1
  1595.      * @throws  RuntimeException
  1596.      */
  1597.     protected function _lock()
  1598.     {
  1599.         $this->_db->lockTable($this->_tbl);
  1600.         $this->_locked true;
  1601.  
  1602.         return true;
  1603.     }
  1604.  
  1605.     /**
  1606.      * Method to unlock the database table for writing.
  1607.      *
  1608.      * @return  boolean  True on success.
  1609.      *
  1610.      * @since   11.1
  1611.      */
  1612.     protected function _unlock()
  1613.     {
  1614.         $this->_db->unlockTables();
  1615.         $this->_locked false;
  1616.  
  1617.         return true;
  1618.     }
  1619. }

Documentation generated on Tue, 19 Nov 2013 15:14:51 +0100 by phpDocumentor 1.4.3